게임플레이 이펙트(Gameplay Effect, GE)
- GAS는 게임에 영향을 주는 객체를 별도로 분리하여 관리한다.
- 게임에 영향을 준다는 것은 게임 데이터를 변경한다는 것을 의미한다.
- 대부분 게임플레이 이펙트과 어트리뷰트는 함께 동작하도록 구성되어있다.
- GAS시스템에서 가장 많은 기능을 제공하는 클래스이다.
- GameplayEffect를 상속하여 생성하면 된다.
게임플레이 이펙트의 타입
- Instant : 어트리뷰트에 즉각적으로 적용되는 게임플레이 이펙트. 한 프레임에 실행된다.
- Duration : 지정한 시간 동안 동작하는 게임플레이 이펙트.
- Infinite : 명시적으로 종료하지 않으면 계속 동작하는 게임플레이 이펙트.
게임플레이 이펙트 모디파이어(Modifier)
- GE에서 어트리뷰트의 변경 방법을 지정한 설정을 모디파이어라고 함.
Modifier 사용 방법
- 적용할 어트리뷰트의 지정
- 적용 방식의 설정 : 더하기, 곱하기, 나누기, 덮어쓰기
- C++로 설정하기에는 문법이 복잡하여 Blueprint로 제작하는 것을 권장.
Modifier 계산 방법
- ScalableFloat : 실수값 대입 (Data Table과 연동 가능)
- AttributeBased : 특정 어트리뷰트에 기반
- CustomCalculationClass : 계산을 담당하는 전용 클래스 활용
- SetByCaller : 데이터 태그를 활용한 데이터 전달, 데이터 값을 받는 형태이다.
- 모디파이어 없이 자체 계산 로직을 만드는 것도 가능하다. (GameplayEffecetExecutionCalculation)
C++로 데미지 Effect 설정
#include "GE/ABGE_AttackDamage.h"
#include "Attribute/ABCharacterAttributeSet.h"
UABGE_AttackDamage::UABGE_AttackDamage()
{
//DurationTypw을 Instant로 지정
DurationPolicy = EGameplayEffectDurationType::Instant;
//이 Effect는 체력을 깎는 Effect이다. 이것을 어떻게 갂을지 작성하는 곳이다.
FGameplayModifierInfo HealthModifier;
//HealthModifier의 Attribute에 ABCharacterAttributeSet의 Health 속성을 가리키는 FGameplayAttribute를 넣는 동작이다.
//해당 Health는 protected로 되어있어서 AttributeSet에서 friend class 설정 또는 public으로 해야한다.
HealthModifier.Attribute = FGameplayAttribute(FindFieldChecked<FProperty>(UABCharacterAttributeSet::StaticClass(), GET_MEMBER_NAME_CHECKED(UABCharacterAttributeSet, Health)));
//ModifierOp은 더하기, 곱하기, 나누기 등 다양한 설정을 할 수 있다.
HealthModifier.ModifierOp = EGameplayModOp::Additive;
//실제로 적용할 값을 지정한다.
FScalableFloat DamageAmount(-30.f);
FGameplayEffectModifierMagnitude ModMagnitude(DamageAmount);
HealthModifier.ModifierMagnitude = ModMagnitude;
//여기까지 설명하자면
//기존의 Healt정보에 Additive(더하기)를 활용하여 ModMagnitude 의 값(-30)을 더하겠다는 명령이다.
//Modifier들을 관리하는 Modifiers 변수에 추가한다.
Modifiers.Add(HealthModifier);
}
C++로 Attack Damage를 주는 Effect를 설정하는 방법이다.
FGmaplayModifierInfo에 어떤 Attribute를 설정할 것인지, 어떤 방식으로 값을 수정할 것인지, 어떤 값을 수정할 것인지 등 설정을 해야한다.
특히 Modifier의 Attribute를 넣는 코드를 보면 많이 긴 것을 확인할 수 있고
Health가 protected로 되어있어서 friend class 추가 또는 public으로 전환해야하는 번거로움이 있다.
UPROPERTY(EditAnywhere, Category = "GAS")
TSubclassOf<UGameplayEffect> AttackDamageEffect;
-----------------------------------------------------------------------------
void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
//FGameplayAbilityTargetDataHandle는 내부적으로 TArray<TSharedPtr<FGameplayAbilityTargetData>> 컨테이너를 들고 있다.
//TagetDataHasHitResult는 TargetDataHandle에서 0번째 요소를 뽑아 해당 요소에 HitResult가 존재하는지 확인하는 함수이다.
if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0))
{
//TargetDataHandle의 0번째 요소에서 HitResult를 Get하여 저장.
FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0);
//어떤 Target이 맞았는지 출력
GAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *HitResult.GetActor()->GetName());
//해당 Effect에 대한 SpecHandle을 넣어준다. Make~함수는 GA에서 제공하는 함수이다.
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackDamageEffect);
if (EffectSpecHandle.IsValid())
{
//인자 - 어빌리티의 SpecHandle, 어빌리티에 관련된 현재 액터 정보, 어빌리티의 발동된 정보, 발동시킬 Effect 정보, TargetHandle 정보.
ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
}
}
...
}
GA는 간단해졌다.
UGameplayEffect를 받아서 cpp에서 GameplayEffectSpecHandle을 만들고
TargetDataHandle에 적용시키면 된다.
지금까지 보면 Effect로 간단하게 체력에서 -30을 하는 코드가 많이 번거롭고 복잡하다는 것을 확인할 수 있다.
Blueprint로 데미지 Effect 설정
Scalable Float
Blueprint를 GameplayEffect를 상속받아 제작하고 다음과 같이 설정하면 된다.
아래와 같이 설정만 하면 위의 GE는 cpp은 사용하지 않고 간단하게 가능하다.

Attribute Based
어트리뷰트 값을 사용해서 별도의 코딩없이 값을 넘겨주는 것도 가능하다.

Magnitude Calculation Type을 Attribute Base로 교체했다.
일단 Backing Attribute에서
Attribute to Capture는 어떤 값을 가져올 것인지? Attribute Source는 누구의 것을 들고올 것인지이다.
위를 예시로는 Source의 ABCharacterAttributeSet.AttackRate값을 들고온다는 의미이다.
그리고 위에 Coefficient는 값을 곱하는 것이다. -1.0을 적용해서 음수로 만들어주고
Pre Muliply Additive Vale는 곱하기 전에 더할 값, Post는 곱한 이후에 더할 값을 넣어주면 된다.
Custom Calculation Class
별도의 계산 클래스를 지정하는 방식이다.
Calculation Class가 가지고 있는 Blueprint를 제작해주면 된다.

해당 GameplayModMagnitudeCalculation을 상속받고
Blueprint를 열고

Calculate Base Magnitude를 override해서 구현하면 된다.
제작한 이후에

GE의 Blueprint에 Calculation Class에 제작한 Class를 적용하면 해당 클래스를 사용해서 데미지를 감소시킨다.
SetByCaller
Magnitude CalculationType에서 SetByCaller를 사용하는 방법이다.
태그를 활용하여 데이터를 받는 형식이다.
#define ABTAG_DATA_DAMAGE FGameplayTag::RequestGameplayTag(FName("Data.Damage"))
다음과 같이 Data.Damage를 Tag에 추가해주고 define해준다.
void UABGA_AttackHitCheck::OnTraceResultCallback(const FGameplayAbilityTargetDataHandle& TargetDataHandle)
{
if (UAbilitySystemBlueprintLibrary::TargetDataHasHitResult(TargetDataHandle, 0))
{
//TargetDataHandle의 0번째 요소에서 HitResult를 Get하여 저장.
FHitResult HitResult = UAbilitySystemBlueprintLibrary::GetHitResultFromTargetData(TargetDataHandle, 0);
//어떤 Target이 맞았는지 출력
GAS_LOG(LogABGAS, Log, TEXT("Target %s Detected"), *HitResult.GetActor()->GetName());
UAbilitySystemComponent* SourceASC = GetAbilitySystemComponentFromActorInfo_Checked();
const UABCharacterAttributeSet* SourceAttribute = SourceASC->GetSet<UABCharacterAttributeSet>();
//해당 Effect에 대한 SpecHandle을 넣어준다. Make~함수는 GA에서 제공하는 함수이다.
FGameplayEffectSpecHandle EffectSpecHandle = MakeOutgoingGameplayEffectSpec(AttackDamageEffect);
if (EffectSpecHandle.IsValid())
{
//EffectSpecHandle에 Data.Damage Tag를 키로하고 -SourceAttribute->GetAttackRate()값을 넣는다.
EffectSpecHandle.Data->SetSetByCallerMagnitude(ABTAG_DATA_DAMAGE, -SourceAttribute->GetAttackRate());
//인자 - 어빌리티의 SpecHandle, 어빌리티에 관련된 현재 액터 정보, 어빌리티의 발동된 정보, 발동시킬 Effect 정보, TargetHandle 정보.
ApplyGameplayEffectSpecToTarget(CurrentSpecHandle, CurrentActorInfo, CurrentActivationInfo, EffectSpecHandle, TargetDataHandle);
}
}
...
}
이 방법은 Tag를 활용하여 데미지를 입히게 된다.
Tag는 Data.Damge 태그를 사용하며 해당 Tag에 의해 입혀지는 데미지는 -30 즉, -SourceAttribute.AttackRate값이 들어간다.
Blueprint는 다음과 같이 지정해주면 된다.

'Unreal 게임 개발 > Unreal 강의 개인 정리' 카테고리의 다른 글
| 레벨과 커브 테이블 & 연속 공격 공격력 변화 - GAS (2) | 2025.08.25 |
|---|---|
| 메타 어트리뷰트 - GAS (1) | 2025.08.24 |
| 캐릭터 어트리뷰트 & 데미지 입히기(Attribute 사용) - GAS (0) | 2025.08.23 |
| AbilityTask와 TargetActor를 활용한 물리 판정 - GAS (0) | 2025.08.22 |
| Notify로 GA실행 & GameplayAbilityTargetActor - GAS (0) | 2025.08.22 |