1. 이펙트 액터 리팩터링
지난 번에 이펙트 액터 클래스 자체는 만들었지만 따로 특별한 설정은 하지 않았다. 이제 게임플레이 이펙트를 통해 플레이어의 어트리뷰트 속성에 영향을 주게 만들어보자.
class PRACTICE2_API AAuraEffectActor : public AActor
{
GENERATED_BODY()
public:
AAuraEffectActor();
protected:
virtual void BeginPlay() override;
UFUNCTION()
virtual void OnOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& HitResult);
UFUNCTION()
virtual void EndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
private:
UPROPERTY(VisibleAnywhere)
TObjectPtr<USphereComponent> Sphere;
UPROPERTY(VisibleAnywhere)
TObjectPtr<UStaticMeshComponent> Mesh;
};
현재 이펙트 액터의 구성은 위와 같다. 사실 굳이 오버랩 이벤트가 C++에서 구현될 필요가 없다고 한다. 성능상 이점이 있는 것도 아니고 이 오버랩 이벤트를 다른 C++클래스에서 호출하는 것도 아니기 때문에 정말 특별한 이유나 극한의 최적화를 요구하는 것이 아니면 블루프린트에서 구현해도 된다고 한다.
그렇기에 메시랑 스피어 컴포넌트는 물론 오버랩, 엔드 오버랩 이벤트 전부 블루프린트에서 구현할 것이고 C++ 클래스에서는 전부 삭제해 주자.
루트 컴포넌트만 새로 구성할 것이다.
AAuraEffectActor::AAuraEffectActor()
{
PrimaryActorTick.bCanEverTick = false;
SetRootComponent(CreateDefaultSubobject<USceneComponent>("SceneRoot"));
}
물론 이렇게 한다고 모든 기능을 블루프린트에서 구현하려는 것이 아니다. 게임플레이 이펙트는 C++로 구현하고 이를 블루프린트와 연결할 것이다.
2. 게임플레이 이펙트 효과 주기
class PRACTICE2_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 Effects")
TSubclassOf<UGameplayEffect> InstanceGameplayEffectClass;
};
게임플레이 이펙트를 담을 변수와 이를 적용할 함수를 만들자.
void AAuraEffectActor::ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(Target);;
if (ASCInterface)
{
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target);
TargetASC->ApplyGameplayEffectSpecToSelf()
}
}
함수를 만들고 있다.
TargetASC->ApplyGameplayEffectSpecToSelf()
이곳에 들어갈 매개변수를 설정해야 한다.
이펙트 컨텍스트 핸들을 만들자. 핸들은 이펙트 컨텍스트를 래핑한 구조체로 이펙트 컨텍스트를 좀 더 다루기 쉽게 해주는 핸들이다.
이펙트 컨텍스트는 효과가 발생한 맥락, 즉 누가 시전했는지 효과가 어디서 발동된 위치가 어딘지 등이 저장되는 구조체이다.
FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
아래와 같이 소스 오브젝트를 선택한다던지 다양한 작업을 할 수 있다.
EffectContextHandle.AddSourceObject(this);
다음으로 만들것은 이펙트 스펙 핸들이다. 이펙트 스펙 핸들은 게임플레이 이펙트와 이펙트 컨텍스트를 바탕으로 만들어 진다.
FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);
이펙트 스펙 핸들은 이펙트 스펙을 다루는 핸들로 이펙트 스펙에서는 이펙트의 실제 효과, 가령 데미지, 지속 시간 등을 가지고 있는 구조체이다.
이제 이를 함수의 매개변수로 넣어주면 된다.
TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
함수를 자세히 살펴보면 이 안에 들어가는 것은 참조이지 포인터가 아니다. 그렇기 때문에 역참조하여 실제 데이터를 가져와야 한다.
전체 코드를 보면 다음과 같다.
void AAuraEffectActor::ApplyEffectToTarget(AActor* Target, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(Target);;
if (ASCInterface)
{
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Target);
FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
EffectContextHandle.AddSourceObject(this);
FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);
TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
}
}
이제 코드를 보면 GameplayEffectClass 가 필요한 것을 알 수 있다. 에디터로 가서 이것을 만들어보자.
'게임프로그래밍 > 실습2' 카테고리의 다른 글
[실습2] 23. C++에서 인피니트 게임플레이 이펙트 제거하기 (0) | 2024.11.30 |
---|---|
[실습2] 22. 인스턴트 게임플레이 이펙트 (0) | 2024.11.29 |
[실습2] 20. 어트리뷰트 변경사항 적용하기 (0) | 2024.11.29 |
[실습2] 19. 초기값 위젯에 브로드캐스팅하기기 (0) | 2024.11.29 |
[실습2] 18. 위젯 컨트롤러로 설정하기 (0) | 2024.11.29 |