직접 간단한 포션을 GameEffect를 사용하여 만들어보자.
대충의 계획을 세워보면 아래와 같다.
EffectActor
를 만들어 범용적으로 사용할 기본 클래스를 만들어 준다.EffectActor
를 블루프린트로 파생하여 포션 클래스를 만든다.UGameplayEffect
클래스를 만들어서 적용 시켜준다.차근차근 해보자
우선 Actor를 만들어볼건데 UGameplayEffect
가 우리가 생각하는 GameplayEffect를 만들어 놓은 클래스이다.
UGameplayEffect
의 정의를 피킹해보자
무수한 코드..
훑어보다보면 익숙한 친구들이 보인다.
Attributes에 영향을 줄 수 있는 Modifiers와 Executions들이 잘 있는 것을 볼 수 있다.
블루프린트로 만들어서 사용할 것이기 때문에 코드를 쓸 일은 지금 없지만..
그래서 이 GameplayEffect를 어떻게 적용시키냐?
그것은 UAbilitySystemComponent
의 ApplyGameplayEffect 친구들을 사용하면 된다.
무수한 함수들이 있는데 지금 사용할 것은 이 중 ApplyGameplayEffectSpecToSelf
이다.
포션은 그냥 체력 Attibutes에 단순한 Add를 플레이어 본인에게 해주는 것이기 때문에.
만약 플레이어가 적에게 대미지를 입히거나 한다면 ApplyGameplayEffectSpecToTarget
이 될 것이다.
근데 함수 인자에 FGameplayEffectSpecHandle
이라는 못보던 구조체가 있다.
뭐지?
GameplaySpec은 GameplayEffect의 인스턴스 개념이다.
GameplayEffect를 게임에 실제로 적용시키기 위해 사용되며 GameplayEffect에 설정된 기본 속성, 파라미터 값 등을 포함하고 있다.
GameplaySpecHandle는 이를 감싸고 있는 타입이다.
FString과 문자열의 관계랑 비슷한거 같기도 하고?
그래서 이를 어떻게 만들어서 넣어주느냐!
ASC에는 MakeOutgoingSpec
이라는 함수가 있다.
근데 문제는 여기 인자에도 이상한게 있다.
FGameplayEffectContextHandle
.. 이건 뭐지
GameplayEffect의 문맥.
말그대로다.
이게 어떤 상황에서 일어났는지를 담고 있는 구조체이다.
안에 무엇이 있는고 하니
대충 효과를 받는 쪽과 입히는 쪽, 리플리케이트 되지 않는 어빌리티 등
확실히 Effect에 대한 문맥을 나타내주고 있는 것 같다.
얘도 ASC에 MakeEffectContext
라는 함수가 있어서 이걸로 만들면 된다.
만들어주고 특별한 내용은 없으니 SourceObject만 포션 클래스로 지정해주고 넘겨주자.
FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
EffectContextHandle.AddSourceObject(this);
그럼 이제 Spec도 만들 수 있다.
const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);
EffectActor라는 기본 클래스를 만들어서 사용하면 재사용성이 커지니 아주 좋다고 할 수 있다.
그렇다면 GameplayEffect를 적용하는 것도 재사용 가능하게 만들어야하니 BlueprintCallable 함수로 만들어 주자.
void AAuraEffectActor::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
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());
}
포션에 닿으면 먹게끔 포션에 Sphere Collision을 달아주고 Begin Overlap에서 위 함수를 호출해준다.
Effect Class는 어디서 났냐고? 블루프린트로 만들었당
만들어주면 블루프린트 디테일 패널에서 GameplayEffect를 수정할 수 있다.
아까 C++ 코드 베이스에서 본 그 두녀석이 얘네가 아닐까 싶다.
Attribute를 Health로 설정하고 Add로 25를 더해준다.
똑같은 방법으로 마나 포션도 만들 수 있다.
성공!