2026-06-01(월) FTransform곱셈, WaitGameplayEvent, GameplayEffect와 Spec, FGameplayEffectModCallbackData, Data.EvaluatedData.attribute

조범근·2026년 6월 1일

TIL

목록 보기
67/81

C++ Week 14

Study

개인 연습 프로젝트, 알고리즘 2문제



Today I Learned


UnrealC++

1. FTransform

FTransform은 위치, 회전, 스케일을 가진 자료형이다.

내부적으로 대충 이 세 가지를 가진다

Translation = 위치
Rotation = 회전
Scale3D = 스케일

FTransform Result = A * B;

Transform의 곱셈은 A를 먼저 적용하고, 그 다음 B를 적용한다. 로컬위치를 월드 위치로 바꿀 때 자주 사용한다.

FTransform WorldTransform = LocalTransform * OwnerActor->GetActorTransform();

즉, LocalTransform을 먼저 적용하고, 그 결과를 OwnerActor의 월드 Transform 기준으로 변환한다.

예를 들어 보스 앞쪽에 근접 공격 판정을 만들고 싶다면:

FTransform LocalHitBoxTransform(
    FRotator::ZeroRotator,
    FVector(150.f, 0.f, 50.f)
);

FTransform WorldHitBoxTransform =
    LocalHitBoxTransform * OwnerCharacter->GetActorTransform();

여기서 주의해야할 점은 Transform 곱셈은 순서가 중요하다. B를 기준으로 A를 이동한다.




2. WaitGameplayEvent

const FGameplayTag hitEventTag =
    FGameplayTag::RequestGameplayTag(TEXT("Event.Boss.Melee.Hit"));

UAbilityTask_WaitGameplayEvent* waitHitEventTask =
    UAbilityTask_WaitGameplayEvent::WaitGameplayEvent(
        this,
        hitEventTag,
        nullptr,
        true,
        true
    );

waitHitEventTask->EventReceived.AddDynamic(
    this,
    &ThisClass::OnMeleeHitEventReceived
);

waitHitEventTask->ReadyForActivation();

이 코드는 Ability 안에서 특정 GameplayEvent를 기다리는 코드다. 가져온 태그는 Project Settings의 Gameplay Tags에 등록되어 있어야 한다.

WaitGameplayEvent(this, hitEventTag, nullptr, true, true);

this = 이 Ability에서 실행되는 Task
hitEventTag = 기다릴 이벤트 태그
nullptr = 별도 Target ASC가 아니라 이 Ability의 Owner ASC에서 이벤트를 기다림
true = 한 번만 받고 끝냄
true = 정확히 같은 태그만 받음

태그에 델리케이트를 바인딩한다고 생각하면 쉽다




3. GameplayEffect와 Spec

GE_Damage
GE_Heal
GE_Stun
GE_Buff_AttackPower

GameplayEffect는 능력치들을 모아둔 의 설계도다.

이 안에는 어떤 Attribute를 바꿀지, 얼마나 바꿀지, Instant인지 Duration인지 Infinite인지, 어떤 Tag를 줄지 이런 정보가 들어간다.

하지만 GameplayEffect 자체는 그냥 정의일 뿐이고 실제로 "이번 공격에서 데미지 35를 준다" 같은 런타임 정보는 Spec에 들어간다.

FGameplayEffectSpecHandle SpecHandle =
    ASC->MakeOutgoingSpec(DamageEffectClass, Level, EffectContext);

GameplayEffect는 데이터 원본, 효과들을 모아둔 설계도이고
GameplayEffectSpecGameplayEffect를 누가, 누구에게, 몇 레벨로, 어떤 값으로 적용할지를 담은 런타임 데이터이다.




4. FGameplayEffectModCallbackData

void UMyAttributeSet::PostGameplayEffectExecute(
    const FGameplayEffectModCallbackData& Data
)
{
if (Data.EvaluatedData.Attribute == GetDamageAttribute())
{
    const float LocalDamage = GetDamage();
    SetDamage(0.f);

    if (LocalDamage > 0.f)
    {
        SetHealth(FMath::Clamp(
            GetHealth() - LocalDamage,
            0.f,
            GetMaxHealth()
        ));
    }
}
}

FGameplayEffectModCallbackData는 AttributeSet의 PostGameplayEffectExcute에서 자주 볼 수 있다. PostGameplayEffectExcuteGameplayEffect를 적용한 뒤 HP <= 0일때의 처리 같은 후처리를 담당한다.

Data.EffectSpec

-> 이번 수정을 일으킨 GameplayEffectSpec.
여기서 Instigator, Causer, SourceObject, SetByCaller 값, Tag 정보 등을 확인할 수 있다.

Data.EvaluatedData

-> 실제로 계산된 Modifier 정보.
어떤 Attribute가 바뀌었는지, 얼마만큼 바뀌었는지 등이 들어 있다.

Data.Target

-> 이 Effect를 적용받은 Target ASC다.




5. Data.EvaluatedData.attribute

Data.EvaluatedData.Attribute방금 수정된 Attribute가 무엇인지 알려준다.

예를 들어 GE가 Health를 수정했다면
Data.EvaluatedData.Attribute == GetHealthAttribute()
이 값이 true다

GE가 Damage를 수정했따면
Data.EvaluatedData.Attribute == GetDamageAttribute()
이 값도 true다

"Health냐, Damage냐, MaxHealth냐" 같은 값을 구분하기 위한 값이다. 그래서 AttributeSet에서는 보통 이렇게 분기한다.

if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
    // Health가 직접 변경된 경우
}

if (Data.EvaluatedData.Attribute == GetDamageAttribute())
{
    // Damage Meta Attribute가 변경된 경우
}

0개의 댓글