1. Modifier Magnitude Calculaitions
에디터에서 기본적으로 제공해주는 기능을 통해서 다양한 속성들을 원하는 계수들로 설정할 수 있지만 더 복잡한 식을 원할 수 있다. 그때 사용하는 것이 MMC 클래스이다.
MMC 클래스를 생성하도록 하자.
이제 이 클래스를 채우도록 하자.
class PRACTICE2_API UMMC_MaxHealth : public UGameplayModMagnitudeCalculation
{
GENERATED_BODY()
public:
UMMC_MaxHealth();
virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;
};
게임플레이 이펙트 스펙에 접근이 가능한 함수 하나를 오버라이드 한다.
이 클래스는 어트리뷰트를 캡쳐하는 것 또한 가능하다.
private:
FGameplayEffectAttributeCaptureDefinition VigorDef;
이제 위의 변수를 실제로 할당해주어야 할 것이다. 그리고 이 작업은 생성자에서 할 수 있다.
#include "AbilitySystem/AuraAttributeSet.h"
UMMC_MaxHealth::UMMC_MaxHealth()
{
VigorDef.AttributeToCapture = UAuraAttributeSet::GetVigorAttribute();
}
엑세서를 만들었기 때문에 이렇게 접근이 가능하다.
이제 이 값을 타겟에서 캡쳐할지 소스에서 캡쳐할지를 정해야한다. 사실 이 경우에는 둘이 동일하긴 하지만 그래도 설정을 해놓자.
UMMC_MaxHealth::UMMC_MaxHealth()
{
VigorDef.AttributeToCapture = UAuraAttributeSet::GetVigorAttribute();
VigorDef.AttributeSource = EGameplayEffectAttributeCaptureSource::Target;
VigorDef.bSnapshot = false;
RelevantAttributesToCapture.Add(VigorDef);
}
float UMMC_MaxHealth::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
{
const FGameplayTagContainer* SoueceTags = Spec.CapturedSourceTags.GetAggregatedTags();
const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();
FAggregatorEvaluateParameters EvaluateParameters;
EvaluateParameters.SourceTags = SoueceTags;
EvaluateParameters.TargetTags = TargetTags;
}
태그를 가져와 FAggregatorEvaluateParameters 구조체에 저장해준다. 해당 구조체의 역할은 아래와 같다고 한다.
FAggregatorEvaluateParameters는 Unreal Engine의 **Gameplay Ability System (GAS)**에서 속성(Attribute)을 계산하거나 평가할 때 사용되는 구조체입니다. 속성 값을 평가하는 데 필요한 태그 정보와 상황별 설정을 담고 있으며, 계산 과정을 제어하는 역할을 합니다.
이제 아래와 같이 작성하자.
float Vigor = 0.f;
GetCapturedAttributeMagnitude(VigorDef, Spec, EvaluateParameters, Vigor);
Vigor = FMath::Max<float>(Vigor, 0.f);
GetCapturedAttributeMagnitude() 함수는 해당 정의의 어트리뷰트 속성의 magnitude를 3번째 매개변수에 할당해주는 함수이다.
첫번째 어트리뷰트 정의는 캡쳐가 되어있어야 하며 우리가 제일 처음에 한 작업이 캡쳐를 하는 작업이었다.
ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
const int32 PlayerLevel = CombatInterface->GetPlayerLevel();
return 80.f + 2.5f * Vigor + 10.f * PlayerLevel;
그리고 이어서 작성한다. 캐릭터의 레벨을 가져왔고 기타 수학 계산을 통해 리턴하는 값이 바로 최대 체력의 값이 될 것이다. 이 클래스를 나중에 게임플레이 이펙트에 할당해주기만 하면 된다.
2. 커스텀 계산 어트리뷰트 이펙트에 할당하기
컴파일하고 에디터로 들어가자.
Magnitude Calculation Type 를 커스텀 클래스로 바꿔준다.
클래스를 선택해주면 된다. 항목들을 보면 알겠지만 커스텀 계산 후에도 추가로 또 계산을 진행할 수도 있다.
이제 게임을 키면..에러가 발생한다.
ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
문제가 발생한 구문이다. 소스 오브젝트를 생성하지 않아 이 문제가 생겼다. 게임플레이 이펙트를 적용할때 소스 오브젝트도 알려주어야 한다.
베이스 캐릭터 클래스로 가자.
ApplyEffectToSelf
해당 함수에서 게임플레이 이펙트들을 적용하고 있다. 여기서 소스 객체를 할당해주자.
void AAuraCharacterBase::ApplyEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level) const
{
check(IsValid(GetAbilitySystemComponent()));
check(GameplayEffectClass);
FGameplayEffectContextHandle ContextHandle = GetAbilitySystemComponent()->MakeEffectContext();
ContextHandle.AddSourceObject(this); // 추가
const FGameplayEffectSpecHandle SpecHandle = GetAbilitySystemComponent()->MakeOutgoingSpec(GameplayEffectClass, Level, ContextHandle);
GetAbilitySystemComponent()->ApplyGameplayEffectSpecToTarget(*SpecHandle.Data.Get(), GetAbilitySystemComponent());
}
컨텍스트 핸들에서 소스 오브젝트를 설정할 수 있다. 다시 컴파일하고 확인하자.
이제 정상적으로 작동한다. 이렇게 해서 더욱 정교하게 어트리뷰트를 구현할 수 있게 되었다.
'게임프로그래밍 > 실습2' 카테고리의 다른 글
[실습2] 34. 어트리뷰트 정보를 담은 데이터 에셋 만들기 (0) | 2024.12.02 |
---|---|
[실습2] 33. C++로 게임플레이 태그 만들기 (싱글톤 디자인 적용) (0) | 2024.12.02 |
[실습2] 31. Combat 인터페이스를 통해 플레이어 레벨 얻기 (0) | 2024.12.01 |
[실습2] 30. 게임플레이 이펙트로 어트리뷰트 초기화 하기 (0) | 2024.12.01 |
[실습 2] 29. 클램핑 버그 고치기 (0) | 2024.11.30 |