Unreal GAS (13) - AttributeSet - Attribute 변경에 반응하기 (PreAttributeChange, PostGameplayEffectExecute)

wnsduf0000·2025년 12월 1일

Unreal_GAS

목록 보기
14/34
  • PreAttributeChange

    • Attribute가 변경되기 전에 호출되는 함수.
      Attribute의 값이 변경되는 범위를 Clamp 처리 해주는 대에 사용할 수 있다.
    • AttributeSet에서 PreAttributeChange()를 오버라이드 하여 사용하여야 한다.
      // AuraAttributeSet.h
      virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
      
      // AuraAttributeSet.cpp
      void UAuraAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
      {
      	Super::PreAttributeBaseChange(Attribute, NewValue);
      
      	if (Attribute == GetHealthAttribute())
      	{
      		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
      	}
      	if (Attribute == GetManaAttribute())
      	{
      		NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
      	}
      }
      
    • 값 자체를 변경시키는 것이 아니라, Clamp 처리 등으로 변경시킨 값을 다시 전달하는 것 뿐이다.
      따라서, PreAttributeChange() 이후에 어떠한 과정에 의해서 Attribute 값이 다시 변경되는 것은 막지 못한다.
    • 단, 에픽게임즈에서도 이 함수를 Clamp 처리 외의 용도로 사용하는 것은 권장하지 않는다고 한다.
  • PostGameplayEffectExecute

    • GameplayEffect가 적용된 이후에 호출되는 함수.
    • PreAttributeChange()와 마찬가지로, AttributeSet 클래스에서 제공하는 함수를 오버라이드하여 사용한다.
      // AuraAttributeSet.h
      virtual void PostGameplayEffectExecute(const struct FGameplayEffectModCallbackData& Data) override;
      
      // AuraAttributeSet.cpp
      void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
      {
      	Super::PostGameplayEffectExecute(Data);
      	
      	FEffectProperties EffectProperties;
      	SetEffectProperties(Data, EffectProperties);
      }
      
      void UAuraAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& OutEffectProperties) const
      {
      	OutEffectProperties.EffectContextHandle = Data.EffectSpec.GetContext();
      	OutEffectProperties.SourceASC = OutEffectProperties.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();
      	if (IsValid(OutEffectProperties.SourceASC) && OutEffectProperties.SourceASC->AbilityActorInfo.IsValid() && OutEffectProperties.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
      	{
      		OutEffectProperties.SourceAvatarActor = OutEffectProperties.SourceASC->AbilityActorInfo->AvatarActor.Get();
      		OutEffectProperties.SourceController = OutEffectProperties.SourceASC->AbilityActorInfo->PlayerController.Get();
      		if (OutEffectProperties.SourceController == nullptr && OutEffectProperties.SourceAvatarActor != nullptr)
      		{
      			if (const APawn* Pawn = Cast<APawn>(OutEffectProperties.SourceAvatarActor))
      			{
      				OutEffectProperties.SourceController = Pawn->GetController();
      			}
      		}
      
      		if (OutEffectProperties.SourceController)
      		{
      			OutEffectProperties.SourceCharacter = Cast<ACharacter>(OutEffectProperties.SourceController->GetPawn());
      		}
      	}
      
      	if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
      	{
      		OutEffectProperties.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
      		OutEffectProperties.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();
      		OutEffectProperties.TargetCharacter = Cast<ACharacter>(OutEffectProperties.TargetAvatarActor);
      		OutEffectProperties.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(OutEffectProperties.TargetAvatarActor);
      	}
      }
      
      // FEffectProperties (AuraAttributeSet.h에 선언됨)
      USTRUCT()
      struct FEffectProperties
      {
      	GENERATED_BODY()
      
      	FEffectProperties() {}
      
      	// Effect Context Handle
      	FGameplayEffectContextHandle EffectContextHandle;
      
      	// Source Info
      	UPROPERTY()
      	UAbilitySystemComponent* SourceASC = nullptr;
      	UPROPERTY()
      	AActor* SourceAvatarActor = nullptr;
      	UPROPERTY()
      	AController* SourceController = nullptr;
      	UPROPERTY()
      	ACharacter* SourceCharacter = nullptr;
      
      	// Target Info
      	UPROPERTY()
      	UAbilitySystemComponent* TargetASC = nullptr;
      	UPROPERTY()
      	AActor* TargetAvatarActor = nullptr;
      	UPROPERTY()
      	AController* TargetController = nullptr;
      	UPROPERTY()
      	ACharacter* TargetCharacter = nullptr;
      };
      • FGameplayEffectModCallbackData 구조체를 out 형태로 내보내는 함수이다.
      • FGameplayEffectModCallbackData 구조체는 EffectSpec, EvaluatedData, Target의 3가지 멤버 변수를 지니는 구조체이며, 이들 멤버 변수를 통해 해당 GameplayEffect에 대한 거의 모든 정보에 접근할 수 있다.
        • EffectSpec (FGameplayEffectSpec)
          • GameplayEffect를 담은 FGameplayEffectSpec
          • GetContext()를 통해 FGameplayEffectContextHandle를 얻어올 수 있기 때문에,
            이를 통해 GameplayEffect의 SourceActor에 대한 정보도 접근할 수 있다.
        • EvaluatedData (FGameplayModifierEvaluatedData)
          • Target에게 적용될 Data
        • Target (UAbilitySystemComponent)
          • GameplayEffect가 적용될 Target
  • Curve Table

    • GameplayEffect의 Modifier를 Scalable Float로 설정할 경우, Curve Table을 설정할 수 있음.
    • Curve Table을 생성 후, MakeOutgoingSpec()에서 레벨 매개변수를 설정해줌으로서,
      레벨에 따라 차등되는 수치를 적용할 수 있음.
      ```cpp
      // ActorLevel이 레벨을 나타내는 매개변수임.
      const FGameplayEffectSpecHandle EffectSpecHandle 
      = TargetASC->MakeOutgoingSpec(GameplayEffectClass, ActorLevel, EffectContextHandle);
      ```
    • 레벨에 해당하는 커브 테이블의 수치와 Scalable Float를 곱한 수치가 적용됨.
profile
저는 게임 개발자로 일하고 싶어요

0개의 댓글