[UE5] Custom Execution Calculation Class

kkado·2024년 9월 18일
0

UE5

목록 보기
62/63
post-thumbnail

Gameplay Attribute의 값을 변화시킬 수 있는 Gameplay Effect에는 여러 가지 Modifier Magnitude를 설정할 수 있다.
기존에 만들어진 Curve Table을 이용할 수 있는 Scalable float 옵션, 다른 어트리뷰트에 연산을 더한 값을 사용할 수 있는 Attribute Based 옵션, 호출하는 쪽에서 값을 정할 수 있는 Set by caller 옵션 등이 있다. 그리고 이번 글에서 다룰 Custom Calculation Class를 사용하면 프로그래머가 여러 어트리뷰트를 사용해서 임의로 계산식을 만들 수 있는 강력한 기능을 사용할 수 있다.

GameplayEffectExecutionCalculation

굉장히 긴 이름의 이 클래스를 상속하는 하위 클래스를 만듦으로써 계산식을 커스텀할 수 있다.
이 클래스의 맨 아래를 보면 다음과 같은 매크로식을 발견할 수 있다.

#define DECLARE_ATTRIBUTE_CAPTUREDEF(P) \
	FProperty* P##Property; \
	FGameplayEffectAttributeCaptureDefinition P##Def; \

#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); \
}

P 라는 파라미터를 받아서 P##Property, P##Def 이런 식으로 변수명에 사용하고 있는 것을 볼 수 있는데, # 기호 두 개를 이어 붙인 ## 형태를 사용하면 마치 문자열을 이어 붙이듯이 파라미터를 이름에 사용할 수 있다.

AttributeSet에서 GAMEPLAYATTRIBUTE_VALUE_GETTER 매크로에서 사용해 본 적이 있다.

#define GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
	FORCEINLINE float Get##PropertyName() const \
	{ \
		return PropertyName.GetCurrentValue(); \
	}

예를 들어 PropertyNameHealth 를 입력해서 선언하면 Get##PropertyName() 에 의해 GetHealth() 라는 getter 함수를 쉽게 생성할 수 있다.

이렇게 생성된 프로퍼티를 관리/접근할 수 있도록 static 변수를 만들어 주고, 계산에 사용될 어트리뷰트를 저장하는 TArray<FGameplayEffectAttributeCaptureDefinition>RelevantAttributesToCapture에 Definition을 추가한다.

static const AuraDamageStatics& DamageStatics()
{
	static AuraDamageStatics DStatics;
	return DStatics;
}

Execute

Gameplay Attribute가 실행되면 UGameplayEffectExecutionCalculation::Execute() 함수가 실행된다.
이 함수는 두 개의 파라미터를 가지며 하나는 FGameplayEffectCustomExecutionParameters 파라미터이고, 하나는 FGameplayEffectCustomExecutionOutput 이다. 함수의 선언부로 이동해 주석을 확인해 보면 ExecutionParams는 Custom execution calculation에 필요한 여러 파라미터들을 담고 있는 구조체임을 알 수 있다. 그리고 OutExecutionOutput은 실행의 결과를 담은 구조체임을 알 수 있다.

	/**
	 * Called whenever the owning gameplay effect is executed. Allowed to do essentially whatever is desired, including generating new
	 * modifiers to instantly execute as well.
	 * 
	 * @note: Native subclasses should override the auto-generated Execute_Implementation function and NOT this one.
	 * 
	 * @param ExecutionParams		Parameters for the custom execution calculation
	 * @param OutExecutionOutput	[OUT] Output data populated by the execution detailing further behavior or results of the execution
	 */
	UFUNCTION(BlueprintNativeEvent, Category="Calculation")
	void Execute(const FGameplayEffectCustomExecutionParameters& ExecutionParams, FGameplayEffectCustomExecutionOutput& OutExecutionOutput) const;

Execution Parameter 구조체에는 여러 멤버 변수들이 들어 있고,

output 구조체에는 결과를 나타내는 여러 멤버들이 들어 있다.

	FAggregatorEvaluateParameters EvalParam;
	EvalParam.SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
	EvalParam.TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

	float Armor = 0.f;
	ExecutionParams.AttemptCalculateCapturedAttributeMagnitude(DamageStatics().ArmorDef, EvalParam, Armor);
	Armor = FMath::Max<float>(0.f, Armor);

	FGameplayModifierEvaluatedData EvaluatedData(DamageStatics().ArmorProperty, EGameplayModOp::Additive, Armor);
	OutExecutionOutput.AddOutputModifier(EvaluatedData);

AttemptCalculateCapturedAttributeMagnitude()를 통해 Armor Definition의 값을 로컬 변수로 가져오고, 이를 토대로 EvaluatedData를 만들어 Output에 추가할 수 있다.


위 사진과 같이 Execution에 해당 클래스를 Calculation Class 자리에 추가해 주면, 이 GE가 실행될 때 해당 클래스에서 오버라이드한 Execute() 함수가 실행된다.

profile
베이비 게임 개발자

0개의 댓글