Unreal GAS (18) - Attribute Menu Widget, C++ Native GameplayTags

wnsduf0000·2025년 12월 1일

Unreal_GAS

목록 보기
19/34
  • Attribute Menu Widget
    • Plan
      • Attribute Menu 위젯에서 각 Attribute들에 접근하여 현재 능력치를 표기할 수 있도록 하려 함.
        • 모든 Attribute마다 델리게이트를 활용하여 변경 사항을 전파하는 방법
          • 각 Attribute마다 직접 델리게이트 등을 작성해야 하여 코드가 복잡해짐.
            확장하기가 번거로워지고 유지보수 측면에서 좋지 않은 코드가 됨.
        • 모든 Attribute에 대응할 수 있는 델리게이트를 활용하여 여러 정보를 넘겨받는 방법
          • FOnAttributeChanged와 같은 이름으로 Attribute 변경에 호출되는 범용 델리게이트를 작성하여, GameplayTag, Attribute 이름, 수치, 부가 설명 등을 담은 FAuraAttributeInfo와 같은 이름의 구조체를 생성하여 한꺼번에 전달할 수 있음.
        1. UAttributeMenuWidgetController
          • Attribute 변경 시에 델리게이트를 통해 반응하여 어떤 Attribute가 변경됐는지 등에 대한 정보를 전파할 수 있도록 해야 함. (GameplayTag, Attribute 이름, 수치, 부가 설명 등)
        2. 변경된 Attribute에 해당하는 GameplayTag를 찾아냄.
        3. DataAsset(UAttributeInfo)을 통해 GameplayTag를 넘겨받아 FAuraAttributeInfo를 생성하여 반환하도록 함.
        4. FAuraAttributeInfo를 통해 위젯이 정보를 업데이트 하도록 함.
    • Native Gameplay Tags
      • AssetManager 클래스 상속을 통해 커스텀 AssetManager 클래스를 사용하여 C++ 코드를 통해 Native GameplayTag 설정하기
        • Singleton으로서 작동하는 구조체 FAuraGameplayTag를 생성

          • FAuraGameplayTag를 생성하는 이유는 게임 중 어디에서나 접근 가능한 GameplayTag를 만들기 위함임.
          • 새로운 GameplayTag를 추가하려면 FAuraGameplayTags에서 설정하면 됨.
            (추후 추가할 UDataAsset을 상속하는 UAttributeInfo에도 에디터에서 추가해야 함)
        • FAuraGameplayTag는 기존 DataTable이나 프로젝트 세팅에서 설정했던 GameplayTag들을 선언하고 UGameplayTagsManager의 AddNativeGameplayTag()로 초기화해주는 역할을 담당함.

          #pragma once
          
          #include "CoreMinimal.h"
          #include "GameplayTagContainer.h"
          
          
          struct FAuraGameplayTags
          {
          
          public:
          	static const FAuraGameplayTags& Get() { return GameplayTags; }
          
          	static void InitializeNativeGameplayTags();
          
          	// 각종 Attribute들을 선언해줌.
          	FGameplayTag Attributes_Primary_Strength;
          	FGameplayTag Attributes_Primary_Intelligence;
          	FGameplayTag Attributes_Primary_Resilience;
          	FGameplayTag Attributes_Primary_Vigor;
          
          	FGameplayTag Attributes_Secondary_Armor;
          	FGameplayTag Attributes_Secondary_ArmorPenetration;
          	FGameplayTag Attributes_Secondary_BlockChance;
          	FGameplayTag Attributes_Secondary_CriticalHitChance;
          	FGameplayTag Attributes_Secondary_CriticalHitDamage;
          	FGameplayTag Attributes_Secondary_CriticalHitResistance;
          	FGameplayTag Attributes_Secondary_HealthRegeneration;
          	FGameplayTag Attributes_Secondary_ManaRegeneration;
          	FGameplayTag Attributes_Secondary_MaxHealth;
          	FGameplayTag Attributes_Secondary_MaxMana;
          
          	FGameplayTag Attributes_Vital_Health;
          	FGameplayTag Attributes_Vital_Mana;
          
          private:
          	static FAuraGameplayTags GameplayTags;
          
          };
          #include "AuraGameplayTags.h"
          #include "GameplayTagsManager.h"
          
          FAuraGameplayTags FAuraGameplayTags::GameplayTags;
          
          // Attribute들을 초기화하는 함수.
          // 해당 함수를 AssetManager의 StartInitialLoading()에서 호출할 것임.
          void FAuraGameplayTags::InitializeNativeGameplayTags()
          {
          	/**
          	* Primary Attributes Start
          	*/
          	GameplayTags.Attributes_Primary_Strength = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Primary.Strength"), 
          			FString("Increases Physical Damage and Carry Weight"));
          	GameplayTags.Attributes_Primary_Intelligence = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Primary.Intelligence"), 
          			FString("Increases Magical Damage and Max Mana"));
          	GameplayTags.Attributes_Primary_Resilience = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Primary.Resilience"), 
          			FString("Increases Armor and Health Regeneration"));
          	GameplayTags.Attributes_Primary_Vigor = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Primary.Vigor"), 
          			FString("Increases Health and Stamina"));
          	/**
          	* Primary Attributes End
          	*/
          
          	/**
          	* Secondary Attributes Start
          	*/
          	GameplayTags.Attributes_Secondary_Armor = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.Armor"), 
          			FString("Reduce Damage Taken, Increase Block Chance. Affected by Resilience"));
          	GameplayTags.Attributes_Secondary_ArmorPenetration = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.ArmorPenetration"), 
          			FString("Ignore a portion of target's Armor. Affected by Armor Penetration"));
          	GameplayTags.Attributes_Secondary_BlockChance = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.BlockChance"), 
          			FString("Chance to cut incoming damage in half. Affected by Armor"));
          	GameplayTags.Attributes_Secondary_CriticalHitChance = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.CriticalHitChance"), 
          			FString("Chance to double damage plus critical hit bonus. Affected by Armor Penetration"));
          	GameplayTags.Attributes_Secondary_CriticalHitDamage = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.CriticalHitDamage"), 
          			FString("Bonus Damage added when a critical hit occurs. Affected by Armor Penetration"));
          	GameplayTags.Attributes_Secondary_CriticalHitResistance = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.CriticalHitResistance"), 
          			FString("Reduces Critical Hit Chance of incoming attack. Affected by Armor"));
          	GameplayTags.Attributes_Secondary_HealthRegeneration = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.HealthRegeneration"), 
          			FString("Health Regeneration per second. Affected by Vigor"));
          	GameplayTags.Attributes_Secondary_ManaRegeneration = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.ManaRegeneration"), 
          			FString("Mana Regeneration per second. Affected by Intelligence"));
          	GameplayTags.Attributes_Secondary_MaxHealth = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.MaxHealth"), 
          			FString("Maximum amount of Health Obtainable. Affected by Vigor"));
          	GameplayTags.Attributes_Secondary_MaxMana = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Secondary.MaxMana"), 
          			FString("Maximum amount of Mana Obtainable. Affected by Intelligence"));
          	/**
          	* Secondary Attributes End
          	*/
          
          	/**
          	* Vital Attributes Start
          	*/
          	GameplayTags.Attributes_Vital_Health = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Vital.Health"), 
          			FString("Current Health Value"));
          	GameplayTags.Attributes_Vital_Mana = UGameplayTagsManager::Get()
          		.AddNativeGameplayTag(FName("Attributes.Vital.Mana"), 
          			FString("Current Mana Value"));
          	/**
          	* Vital Attributes End
          	*/
          }
          
        • AssetManager를 상속하는 UAuraAssetManager 클래스를 생성하여, StartInitialLoading을 오버라이드하여 에셋 초기화 시 FAuraGameplayTag에 선언한 GameplayTag들을 같이 초기화 할 수 있도록 함.

          • 해당 타이밍에 초기화 해야 본격적으로 게임이 작동하기 이전에 안전하게 GameplayTag들을 초기화 하는 것이 가능하여 이런 방식을 사용함.

            #include "CoreMinimal.h"
            #include "Engine/AssetManager.h"
            #include "AuraAssetManager.generated.h"
            
            UCLASS()
            class AURA_API UAuraAssetManager : public UAssetManager
            {
            	GENERATED_BODY()
            	
            public:
            	static UAuraAssetManager& Get();
            
            protected:
            	virtual void StartInitialLoading() override;
            };
            #include "AuraAssetManager.h"
            #include "AuraGameplayTags.h"
            
            UAuraAssetManager& UAuraAssetManager::Get()
            {
            	check(GEngine);
            
            	UAuraAssetManager* AuraAssetManager = Cast<UAuraAssetManager>(GEngine->AssetManager);
            	return *AuraAssetManager;
            }
            
            void UAuraAssetManager::StartInitialLoading()
            {
            	Super::StartInitialLoading();
            
            	FAuraGameplayTags::InitializeNativeGameplayTags();
            }
            
        • 프로젝트 폴더의 Config/DefaultEngine.ini의 [/Script/Engine.Engine] 항목에
          AssetManagerClassName=/Script/Aura.AuraAssetManager 를 추가해야 함.
          Script/(프로젝트명).(클래스이름) 의 방식으로 작성하면 됨.

profile
저는 게임 개발자로 일하고 싶어요

0개의 댓글