1. UGameplayEffectExecutionCalculation
데미지 효과를 커스텀으로 계산하기 위하여 UGameplayEffectExecutionCalculation 커스텀 클래스를 구현하려고 한다.
해당 클래스를 만들고 아래 함수를 오버라이드 한다.
virtual void Execute_Implementation(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const override;
해당 함수는 GameplayEffect의 실행로직을 커스텀화 할때 사용하는 함수라고 한다.
매개변수 설명
- const FGameplayEffectCustomExecutionParameters& ExecutionParams
- 역할: 실행에 필요한 입력 데이터를 제공합니다.
- 내용:
- ExecutionParams는 효과를 계산할 때 필요한 정보와 컨텍스트(맥락)를 포함합니다.
- 포함된 주요 데이터:
- Source(효과를 발생시킨 대상)
- Target(효과를 받는 대상)
- 게임플레이 태그, 속성(Attributes), 기타 데이터.
- 이 데이터를 통해 효과 계산의 기반 데이터를 가져올 수 있습니다.
- FGameplayEffectCustomExecutionOutput& OutExecutionOutput
- 역할: 실행 결과를 출력 데이터로 반환합니다.
- 내용:
- 이 매개변수는 효과 계산의 결과(속성 변화, 실행 결과 등)를 저장합니다.
- 개발자는 이 구조체를 사용해 계산된 결과를 설정하거나 속성을 업데이트합니다.
const UAbilitySystemComponent* SourceASC = ExecutionParams.GetSourceAbilitySystemComponent();
const UAbilitySystemComponent* TargetASC = ExecutionParams.GetTargetAbilitySystemComponent();
이를 통해서 아바타 액터도 구할 수 있다.
const AActor* SourceAvatar = SourceASC ? SourceASC->GetAvatarActor() : nullptr;
const AActor* TargetAvatar = TargetASC ? TargetASC->GetAvatarActor() : nullptr;
const FGameplayEffectSpec& Spec = ExecutionParams.GetOwningSpec();
이제 속성들을 캡쳐해서 이것에 영향을 미쳐야 한다.
2. 속성 캡쳐하기
속성을 저장할 구조체를 만들 것이다.
struct AuraDamageStatics
{
DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
AuraDamageStatics()
{
}
};
DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
해당 매크로의 정의는 아래와 같다.
#define DECLARE_ATTRIBUTE_CAPTUREDEF(P) \
FProperty* P##Property; \
FGameplayEffectAttributeCaptureDefinition P##Def; \
해당 매크로를 사용하면 P의 이름을 가진 속성이 캡쳐가 된다. 정확히는 캡쳐할 속성이 선언이 된다. 선언만 된 것이기 때문에 매크로로 캡쳐된 속성은 반드시 생성자에서 초기화해야한다.
이때 사용하는 매크로가 아래의 매크로이다.
#define DEFINE_ATTRIBUTE_CAPTUREDEF(S, P, T, B) \
DEFINE_ATTRIBUTE_CAPTUREDEF
- DECLARE_ATTRIBUTE_CAPTUREDEF로 선언한 속성을 정의하고 초기화합니다.
- 예: Source/Target 객체에서 속성을 캡처할지 여부 등을 설정.
#define DEFINE_ATTRIBUTE_CAPTUREDEF(S, P, T, B) \
{ \
P##Property = FindFieldChecked<FProperty>(S::StaticClass(), GET_MEMBER_NAME_CHECKED(S, P)); \
P##Def = FGameplayEffectAttributeCaptureDefinition(P##Property, EGameplayEffectAttributeCaptureSource::T, B); \
}
- S : 속성이 정의된 클래스.
- P : 캡처할 속성 이름.
- T : Source 또는 Target(속성을 가져올 객체 지정).
- B : 캡처 시점에서 값을 스냅샷처럼 고정할지 여부.
아래와 같이 사용될 수 있다.
struct AuraDamageStatics
{
DECLARE_ATTRIBUTE_CAPTUREDEF(Armor);
AuraDamageStatics()
{
DEFINE_ATTRIBUTE_CAPTUREDEF(UAuraAttributeSet, Armor, Target, false);
}
};
그리고 이 스태틱 구조체를 반환할 함수를 정의하자.
static const AuraDamageStatics& DamageStatics()
{
static AuraDamageStatics DStatics;
return DStatics;
}
데미지 스태틱 구조체는 런타임 중 하나만 존재하게 될 것이다.
속성을 캡쳐했으면 캡쳐 정의를 저장하는 배열에 저장되어야 할 것이다.
UExecCalc_Damage::UExecCalc_Damage()
{
RelevantAttributesToCapture.Add(DamageStatics().ArmorDef);
}
이렇게 필요한 속성들을 캡쳐할 수 있다.
이제 이 캡쳐된 아머를 사용할 수 있어야 할 것이다.
const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();
FAggregatorEvaluateParameters EvaluationParameters;
EvaluationParameters.SourceTags = SourceTags;
EvaluationParameters.TargetTags = TargetTags;
float Armor = 0.f;
ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvaluationParameters, Armor);
이렇게 하여 캡쳐된 속성을 불러온다.
이제 이러한 속성들을 가져올 수는 있었는데 실제 우리가 원하는 작업(데미지를 입히는 작업)은 어떻게 해야할까?
매개변수를 보면 아웃파라메터가 있는 것을 볼 수 있다.
FGameplayModifierEvaluatedData
위의 구조체를 만들어서 어트리뷰트의 어떤 작업을 할지 정의하고 출력 파라메터의 모디파이어로 설정하면 된다.
const FGameplayModifierEvaluatedData EvaluedData(DamageStatics().ArmorProperty, EGameplayModOp::Additive, Armor);
OutExecutionOutput.AddOutputModifier(EvaluedData);
현재 작업은 크게 의미는 없다. 그저 아머를 바꾸는 작업을 할 뿐이다.
데미지 수치를 바꾸려면 데미지 값을 가져와 설정하면 된다. 이는 비교적 쉽다.
// SetByCallerMagnitude 부터 데미지 불러오기
float Damage = Spec.GetSetByCallerMagnitude(FAuraGameplayTags::Get().Damage);
const FGameplayModifierEvaluatedData EvaluedData(UAuraAttributeSet::GetIncomingDamageAttribute(), EGameplayModOp::Additive, Damage);
OutExecutionOutput.AddOutputModifier(EvaluedData);
게임플레이 이펙트에 들어가 우리가 만든 클래스를 할당해주면 된다.
이후에는 추가적으로 방어력을 적용한다던지 해서 데미지 수치를 조절할 수도 있을 것이다.
'게임프로그래밍 > 실습2' 카테고리의 다른 글
[실습2] 53. 네트워크 직렬화 (0) | 2024.12.07 |
---|---|
[실습2] 52. 커스텀 게임플레이 이펙트 컨텍스트 만들기 (0) | 2024.12.06 |
[실습2] 50. 에너미가 죽을때 디졸브 적용하기 (0) | 2024.12.06 |
[실습2] 49. Set by Coller로 데미지 설정하기 (0) | 2024.12.05 |
[실습2] 48. 메타 어트리뷰트 (0) | 2024.12.05 |