언리얼/게임 프로젝트

GameplayAbilitySystem을 이용한 RPG 프로젝트 - (23) GE의 델리게이트를 통해 현재 적용되는 GE의 Tag를 출력하기

monstro 2024. 12. 30. 01:38
728x90
반응형

이번에는 이전에 배운 Gameplay Effect의 Tag를 한번 화면에 띄워 보도록 하겠습니다.

따라서 Gameplay Effect가 적용될 때 사용할 수 있는 델리게이트를 사용하여 이를 구현해보겠습니다.

 

1) AbilitySystemComponent의 델리게이트

GAS의 주체인 ASC는 많은 기능을 지원합니다.

그 중에서도 OnGameplayEffectAppliedDelegateToSelf 델리게이트는 

GameplayEffect가 자기자신에게 적용되는 경우 호출됩니다.

따라서 해당 델리게이트를 사용해보도록 하겠습니다.

 

2) 코드 일부를 수정

또한, 코드 구조를 일부 수정하도록 하겠습니다.

현재 구조에서 AuraCharacterBase가 부모 클래스이고,

AuraPlayer와 AuraEnemy가 부모 클래스에서 상속된 자식 클래스입니다.

 

따라서 델리게이트를 연결하는 동작을 수행하기 위해 일부 코드 구조를 변경하겠습니다.

 

3) AuraAbilitySystemComponent

#pragma once

#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "AuraAbilitySystemComponent.generated.h"

/**
 * 
 */
UCLASS()
class AURA_API UAuraAbilitySystemComponent : public UAbilitySystemComponent
{
	GENERATED_BODY()
	
public:
	void AbilityActorInfoSet();
	
protected:
	void EffectApplied(
		UAbilitySystemComponent* AbilitySystemComponent, 
		const FGameplayEffectSpec& EffectSpec, 
		FActiveGameplayEffectHandle ActiveEffectHandle
	);
};

 

#include "AbilitySystem/AuraAbilitySystemComponent.h"

void UAuraAbilitySystemComponent::AbilityActorInfoSet()
{
	OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &UAuraAbilitySystemComponent::EffectApplied);
}

void UAuraAbilitySystemComponent::EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveEffectHandle)
{
	FGameplayTagContainer TagContainer;
	EffectSpec.GetAllAssetTags(TagContainer);
	for (const FGameplayTag& Tag : TagContainer)
	{
		const FString TagMsg = FString::Printf(TEXT("GE Tag : %s"), *Tag.ToString());
		GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Blue, TagMsg);
	}
}

 

AuraAbilitySystemComponent에 2개의 함수가 추가된 것을 볼 수 있습니다.

각각 AbilityActorInfoSetEffectApplied 입니다.


AbilityActorInfoSet 함수

델리게이트 OnGameplayEffectAppliedDelegateToSelf함수 EffectApplied를 연결합니다.

따라서 GE가 발동되면 EffectApplied도 같이 발동하게 됩니다.

 

EffectApplied 함수Tag를 저장하는 FGameplayTagContainer를 로컬 변수로 생성합니다.

생성한 컨테이너EffectSpecHandle의 함수 GetAllAssetTags를 사용하여

GE의 Granted Tag가 아닌 GameplayEffectAssetTag를 가져오게 됩니다.
이때 가져오는 Tag가 여러개여도 문제없이 동작합니다.

최종적으로는 채워진 Tag 컨테이너를 순회하면서 화면에 Tag를 출력합니다.

 

4) AuraCharacterBase

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AbilitySystemInterface.h"
#include "AuraCharacterBase.generated.h"

class USkeletalMeshComponent;
class UAbilitySystemComponent;
class UAttributeSet;

UCLASS(Abstract)
class AURA_API AAuraCharacterBase : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	.
	.
	.

protected:
	.
	.
	.

	virtual void InitAbilityActorInfo();
};

 

.
.
.
void AAuraCharacterBase::InitAbilityActorInfo()
{

}

 

자식 클래스들에서 오버라이드될 함수 InitAbilityActorInfo를 선언 / 정의하였습니다.

 

5) AuraPlayer

#pragma once

#include "CoreMinimal.h"
#include "Character/AuraCharacterBase.h"
#include "AuraPlayer.generated.h"

class USpringArmComponent;
class UCameraComponent;

/**
 * 
 */
UCLASS()
class AURA_API AAuraPlayer : public AAuraCharacterBase
{
	GENERATED_BODY()
	
public:
	.
	.
	.

private:
	/*
	* AuraCharacterBase Section
	*/
	virtual void InitAbilityActorInfo() override;
};

 

.
.
.

void AAuraPlayer::PossessedBy(AController* InController)
{
	Super::PossessedBy(InController);

	InitAbilityActorInfo();
}

.
.
.

void AAuraPlayer::InitAbilityActorInfo()
{
	// 서버단계에서 ASC의 OwnerActor와 AvatarActor를 초기화 + BaseCharacter에서 상속된 멤버들을 PlayerState 값으로 초기화
	AAuraPlayerState* AuraPlayerState = CastChecked<AAuraPlayerState>(GetPlayerState());
	AuraPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(AuraPlayerState, this);
	Cast<UAuraAbilitySystemComponent>(AuraPlayerState->GetAbilitySystemComponent())->AbilityActorInfoSet();
	AbilitySystemComponent = AuraPlayerState->GetAbilitySystemComponent();
	AttributeSet = AuraPlayerState->GetAttributeSet();

	AAuraPlayerController* AuraPlayerController = Cast<AAuraPlayerController>(GetController());
	if (AuraPlayerController)
	{
		AAuraHUD* AuraHUD = Cast<AAuraHUD>(AuraPlayerController->GetHUD());
		if (AuraHUD)
		{
			AuraHUD->InitOverlay(AuraPlayerController, AuraPlayerState, AbilitySystemComponent, AttributeSet);
		}
	}
}

 

기존의 SetAbilityActorInfo 메서드의 이름을 InitAbilityActorInfo로 변경하여 위와 같이 수정하였습니다.

또한, ASC를 가져와 AuraAbilitySystemComponent로 캐스트한 후

AbilityActorInfoSet 메서드를 호출하여, GE가 발동되면 Tag를 출력하도록 설정하였습니다.

 

6) AuraEnemy

#pragma once

#include "CoreMinimal.h"
#include "Character/AuraCharacterBase.h"
#include "Interface/EnemyInterface.h"
#include "AuraEnemy.generated.h"

/**
 * 
 */
UCLASS()
class AURA_API AAuraEnemy : public AAuraCharacterBase, public IEnemyInterface
{
	GENERATED_BODY()

public:
	.
	.
	.
	
protected:
	.
	.
	.

	/*
	* AuraCharacterBase Section
	*/
	virtual void InitAbilityActorInfo() override;
};

 

void AAuraEnemy::BeginPlay()
{
	Super::BeginPlay();
	InitAbilityActorInfo();
}

.
.
.

void AAuraEnemy::InitAbilityActorInfo()
{
	AbilitySystemComponent->InitAbilityActorInfo(this, this);
	Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent)->AbilityActorInfoSet();
}

 

AuraEnemy의 경우, BeginPlay의 로직InitAbilityActorInfo에서 수행하도록 수정하였습니다.

마찬가지로, GE가 발동되면 GE의 Tag를 화면에 출력하도록 설정하였습니다.

 

이후 언리얼 에디터에서 GE 블루프린트에 Tag를 설정해보겠습니다.

 

위와 같은 형태로 총 4개를 구성하였습니다.

이제 실행결과를 확인해보겠습니다.

 

 

다음에는 화면에만 출력하던 Tag를 UI 시스템과 결합하도록 하겠습니다.

728x90
반응형