AuraEffectActor를 변경하여, 세부 사항은 블루프린트를 이용하여 구현할 수 있도록 하는 기본 클래스의 역할을 하도록 만드려고 함.
기존의 AttributeSet에 직접 접근하여 const_cast를 통해 변경한 것과 다르게,
GameplayEffect를 이용하여 Attribute를 변경하도록 만들 것임.
class UGameplayEffect;
UCLASS()
class AURA_API AAuraEffectActor : public AActor
{
GENERATED_BODY()
public:
AAuraEffectActor();
protected:
virtual void BeginPlay() override;
UFUNCTION(BlueprintCallable)
void ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass);
UPROPERTY(EditAnywhere, Category = "Applied Effect")
TSubclassOf<UGameplayEffect> InstantGameplayEffectClass;
};
InstantGameplayEffectClass에 GameplayEffect를 생성하여 등록하고,
ApplyEffectToTarget()을 통해 Target에게 GameplayEffect를 적용할 것임.
// AAuraEffectActor.cpp
void AAuraEffectActor::ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target);
if (TargetASC == nullptr) return;
check(GameplayEffectClass);
FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
EffectContextHandle.AddSourceObject(this);
const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);
TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
}
GameplayEffect를 적용하기 함수는 이미 AbilitySystemComponent에 거의 준비되어 있음.
여러 가지 방법이 있지만, 우선은 ApplyGameplayEffectSpecToSelf()를 이용하여 GameplayEffect를 Target에게 적용시켜 볼 것임.
1. UAbilitySystemBlueprintLibrary에서 제공하는 GetAbilitySystemComponent() 함수를 이용하면,
해당 인터페이스 캐스팅 및 만약 인터페이스를 상속하지 않을 경우 FindComponentByClass()를 통한 컴포넌트 탐색까지 실시하여
AbilitySystemComponent를 반환하도록 시도해주는 기능을 편리하게 사용할 수 있음.
"AbilitySystemBlueprintLibrary.h” 를 include 해주어야 사용할 수 있음.
- UKismetSystemLibrary, UKismetMathLibrary, UGameplayStatics의 함수를 쓰기 위해
Kismet 폴더 내에서 필요한 헤더를 include 하는 것처럼 미리 외워두면 좋음
- 다만, AbilitySystemComponent 소유 액터들이 모두 반드시 IAbilitySystemInterface를 상속하도록 할 것이 확실한 경우는
반드시 UAbilitySystemBlueprintLibrary의 함수를 이용할 필요는 없음. 프로젝트 설계 방향에 따라 결정하면 됨.
2. ApplyGameplayEffectSpecToSelf()는 매개변수로 const FGameplayEffectSpec&와 FPredictionKey를 받음.
(FPredictionKey는 일단 기본값을 그대로 사용함)
3. FGameplayEffectSpec은 AbilitySystemComponent의 MakeOutGoingSpec()을 통해 반환되는 FGameplayEffectSpecHandle을 통해 얻을 수 있음.
- FGameplayEffectSpecHandle은 FGameplayEffectSpec을 생성하고 사용할 수 있게 해주는 구조체이기 때문에,
FGameplayEffectSpec을 멤버변수로 지니고 있음.
4. MakeOutGoingSpec()의 매개변수로는 TSubclassOf<UGameplayEffect>, float level, FGameplayEffectContextHandle이 필요함.
- UGameplayEffect 클래스는 사용할 GameplayEffect 클래스를 그대로 넣어주면 됨.
- level의 경우 GameplayEffect들이 다양해짐에 따라 서로 다른 값을 사용하지만, 일단은 임시로 1을 사용하도록 함.
- 다만, FGameplayEffectContextHandle의 경우는 생성해서 넘겨받아야 함.
5. FGameplayEffectContextHandle 또한 AbilitySystemComponent의 MakeEffectContext()를 통해 생성할 수 있음
- FGameplayEffectContextHandle은 FGameplayEffectSpecHandle과 비슷한 맥락으로, FGameplayEffectContext를 다루는 구조체이며,
FGameplayEffectContext는 이 GameplayEffect의 말 그대로의 ‘맥락’에 대한 정보를 담기 위한 구조체라고 보면 됨.
- 예를 들어, 이 GameplayEffect가 누구에 의해 생성되었으며, 누가 영향을 받는 지 등.
FEffectContextHandle에 AddSourceObject()로 this를 넘겨주면 됨.
(AuraEffectActor 자신이 영향을 주는 액터이기 때문)