0. 개요

스펠 장착 버튼을 생성하고 스펠 메뉴에 추가한다.

위젯 컨트롤러 코드를 리펙토링한다.

 

 

1. 스펠 장착 버튼

(1) WBP_WideButton 배치

 

 

2. 위젯 컨트롤러 리펙토링

AuraWidgetController를 상속받는 위젯 컨트롤러를 생성한다.

 

(1) OverlayWidgetController의 델리게이트를 부모인 AuraWidgetController로 이전

오버레이 위젯 컨트롤러가 사용하던 AbilityInfo 델리게이트를 부모로 이전해서 다른 위젯 컨트롤러도 이용할 수 있게 할 것이다.

이는 스펠 메뉴에서도 어빌리티 정보 구조체를 활용할 것이기 때문이다.

DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityInfoSignature, const FAuraAbilityInfo&, Info);
class AURA_API UAuraWidgetController : public UObject
{
	GENERATED_BODY()

public:
//~~~~~~~~~~~~~~~~~~
	UPROPERTY(BlueprintAssignable, Category = "GAS|Messages")
	FAbilityInfoSignature AbilityInfoDelegate;

 

 

(2) AuraWidgetController에 멤버 변수 추가

이제 이 클래스를 상속받는 모든 클래스가 더이상 GAS의 변수를 가져와 캐스팅하여 사용하는 것이 아니라, 멤버 변수로 직접 접근할 수 있도록 변경할 것이다.


- 종속성 문제

GAS의 구성 요소를 커스텀화한 'Aura' 버전들은 이미 프로젝트 내에서 전반적으로 사용되고 있고 일종의 시스템화가 되으며, 종속성이 일방적이기 때문에 문제가 없다.


protected:
	// 종속성 설정
	// 플레이어 스테이트 , 플레이어 컨트롤러, 속성 세트, 어빌리티 시스템 컴포넌트
	UPROPERTY(BlueprintReadOnly, Category="WidgetController")
	TObjectPtr<APlayerController> PlayerController;

	UPROPERTY(BlueprintReadOnly, Category="WidgetController")
	TObjectPtr<APlayerState> PlayerState;

	UPROPERTY(BlueprintReadOnly, Category="WidgetController")
	TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

	UPROPERTY(BlueprintReadOnly, Category="WidgetController")
	TObjectPtr<UAttributeSet> AttributeSet;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetController")
	TObjectPtr<AAuraPlayerController> AuraPlayerController;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetController")
	TObjectPtr<AAuraPlayerState> AuraPlayerState;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetController")
	TObjectPtr<UAuraAbilitySystemComponent> AuraAbilitySystemComponent;

	UPROPERTY(BlueprintReadOnly, Category = "WidgetController")
	TObjectPtr<UAuraAttributeSet> AuraAttributeSet;
    
	// Get Aura PlayerController
	AAuraPlayerController* GetAuraPC();

	// Get Aura PlayerState
	AAuraPlayerState* GetAuraPS();

	// Get Aura AbilitySystemComponent
	UAuraAbilitySystemComponent* GetAuraASC();

	// Get Aura AttributeSet
	UAuraAttributeSet* GetAuraAS();
};

Aura 버전의 GAS 구성요소들과 Getter 함수를 선언한다.

#include "Player/AuraPlayerController.h"
#include "Player/AuraPlayerState.h"
#include "AbilitySystem/AuraAbilitySystemComponent.h"
#include "AbilitySystem/AuraAttributeSet.h"
AAuraPlayerController* UAuraWidgetController::GetAuraPC()
{
    if (AuraPlayerController == nullptr)
    {
        AuraPlayerController = Cast<AAuraPlayerController>(PlayerController);
    }
    return AuraPlayerController;
}

AAuraPlayerState* UAuraWidgetController::GetAuraPS()
{
    if (AuraPlayerState == nullptr)
    {
        AuraPlayerState = Cast<AAuraPlayerState>(PlayerState);
    }
    return AuraPlayerState;
}

UAuraAbilitySystemComponent* UAuraWidgetController::GetAuraASC()
{
    if (AuraAbilitySystemComponent == nullptr)
    {
        AuraAbilitySystemComponent = Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent);
    }
    return AuraAbilitySystemComponent;
}

UAuraAttributeSet* UAuraWidgetController::GetAuraAS()
{
    if (AuraAttributeSet == nullptr)
    {
        AuraAttributeSet = Cast<UAuraAttributeSet>(AttributeSet);
    }
    return AuraAttributeSet;
}

없으면 생성하고 있으면 반환하는 Getter 함수이다.

이제부터는 GAS의 기본 구성 요소를 Aura 버전으로 캐스팅하지 않고 직접 Get하여 사용할 수 있다.

AuraWidgetController의 자식 클래스의 코드를 모두 수정하여 캐스팅 부분을 Getter로 대체한다.

 

 

(3) OverlayWidgetController 클래스의 OnInitializeStartupAbilities 함수 이전

OnInitializeStartupAbilities 함수는 모든 어빌리티를 순회하여 해당 어빌리티의 정보를 가져와 블루프린트로 전달하는 역할을 하고 있다.

이 함수의 이름을 바꾸고 상위 클래스인 AuraWidgetController로 옮겨 SpellMenuWidgetController에서도 해당 함수를 활용할 것이다.

void UAuraWidgetController::BroadcastAbilityInfo()
{
    // 어빌리티가 주어지지 않았다면 리턴
    if (!GetAuraASC()->bStartupAbilitiesGiven)
        return;

    // 어빌리티를 순회하지 않고 델리게이트를 사용
    // 콜백 함수 바인딩
    FForEachAbility BroadcastDelegate;
    BroadcastDelegate.BindLambda([this](const FGameplayAbilitySpec& AbilitySpec)
        {
            // TODO : 태그를 이용해서 어빌리티 정보 가져오기
            FAuraAbilityInfo Info = AbilityInfo->FindAbilityInfoForTag(GetAuraASC()->GetAbilityTagFromSpec(AbilitySpec));
            Info.InputTag = GetAuraASC()->GetInputTagFromSpec(AbilitySpec);

            // 블루프린트 델리게이트
            AbilityInfoDelegate.Broadcast(Info);
        });

    // 델리게이트 실행
    GetAuraASC()->ForEachAbility(BroadcastDelegate);
}

그리고 OverlayWidgetController에서도 상속된 함수를 이용할 것이다.

    if (GetAuraASC())
    {
        if (GetAuraASC()->bStartupAbilitiesGiven)
        {
            // 콜백 함수 바인드 필요 없이 바로 호출
            BroadcastAbilityInfo();
        }
        else
        {
            // 어빌리티 부여 이전이면 델리게이트에 함수 바인딩
            GetAuraASC()->AbilitiesGivenDelegate.AddUObject(this, &UOverlayWidgetController::OnInitializeStartupAbilities);
        }

기존의 OnInitializeStartupAbilities 함수 호출을 상속받은 BroadcastAbilityInfo 호출로 변경한다.

 

(3-1) AuraAbilitySystemComponent

한편 위의 코드 블럭에서 AbilitiesGiven 델리게이트를 AuraASC에서 가져와 바인딩하는 것을 볼 수 있다.

DECLARE_MULTICAST_DELEGATE_OneParam(FAbilitiesGiven, UAuraAbilitySystemComponent*);

이제는 각 WidgetController에서 직접 Aura버전의 구성요소를 가져와 쓸 수 있으므로 델리게이트도 변경한다.

DECLARE_MULTICAST_DELEGATE(FAbilitiesGiven);

코드 이전이 완료되었으면 오버레이 위젯 컨트롤러 클래스에서 해당 코드를 제거한다.

 


이제 스펠 메뉴 위젯 컨트롤러에서 어빌리티 정보에 접근할 수 있게 되었다.

(커스텀 GAS 구성요소에 Getter를 사용하여 직접 접근할 수도 있게 되었다)