Unreal GAS (29) - Character Class

wnsduf0000·2025년 12월 1일

Unreal_GAS

목록 보기
30/34
  • Character Class

    • 게임 내 등장하는 여러 캐릭터들은 전사, 궁수, 마법사 같은 직업(Class)으로 분류될 예정임.
      - 해당 캐릭터들에 대한 정의를 어떻게 하고, 능력치/스킬 등은 어떻게 다르게 할 지에 대한 정의를 내려야 함.

    • 캐릭터의 클래스를 ECharacterClass라는 이름의 Enum을 생성하여 그 곳에 정의하고,
      클래스마다 다른 기본 능력치를 CurveTable을 이용하여 지정함.

    • 만들어둔 각 클래스의 정보를 UCharacterClassInfo라는 이름의 DataAsset을 정의하여 그 곳에 통합하는 식으로 구성함.

      #pragma once
      
      #include "CoreMinimal.h"
      #include "Engine/DataAsset.h"
      #include "CharacterClassInfo.generated.h"
      
      class UGameplayEffect;
      
      UENUM(BlueprintType)
      enum class ECharacterClass : uint8
      {
      	Elementalist,
      	Warrior,
      	Ranger
      };
      
      USTRUCT(BlueprintType)
      struct FCharacterClassDefaultInfo
      {
      	GENERATED_BODY()
      
      	UPROPERTY(EditDefaultsOnly, Category = "Class Defaults")
      	TSubclassOf<UGameplayEffect> PrimaryAttributes;
      };
      
      
      UCLASS()
      class AURA_API UCharacterClassInfo : public UDataAsset
      {
      	GENERATED_BODY()
      	
      public:
      	UPROPERTY(EditDefaultsOnly, Category = "Character Class Defaults")
      	TMap<ECharacterClass, FCharacterClassDefaultInfo> CharacterClassInformation;
      
      	UPROPERTY(EditDefaultsOnly, Category = "Common Class Defaults")
      	TSubclassOf<UGameplayEffect> SecondaryAttributes;
      
      	UPROPERTY(EditDefaultsOnly, Category = "Common Class Defaults")
      	TSubclassOf<UGameplayEffect> VitalAttributes;
      
      	FCharacterClassDefaultInfo GetClassDefaultInfo(ECharacterClass CharacterClass);
      };
      
      // UCharacterClassInfo.cpp
      #include "AbilitySystem/Data/CharacterClassInfo.h"
      
      FCharacterClassDefaultInfo UCharacterClassInfo::GetClassDefaultInfo(ECharacterClass CharacterClass)
      {
          return CharacterClassInformation.FindChecked(CharacterClass);
      }
    • Attribute의 초기화는 GameplayEffect를 사용하는 방식으로 했으므로, 각 캐릭터 클래스에 따른 Attribute 초기화도 마찬가지로 진행함.

    • 생성한 UCharacterClassInfo DataAsset에 별도의 GameplayEffect를 설정하고,
      해당 GameplayEffect들이 CurveTable을 이용하여 레벨마다 적절한 값을 갖도록 함.
      - CurveTable은 CSV나 JSON 포맷을 이용하여 Import/Export 하는 것이 가능함.

    • UCharacterClassInfo는 각 캐릭터들이 지니는 것도 가능은 하겠지만, 정보를 초기화 하는데 한 번만 사용할 뿐더러, 다른 직업에 대한 정보도 모두 지니고 있기 때문에 메모리 차원에서 비효율적임.

      • 이러한 내용은 게임의 규칙과 직접적으로 연관되어 있으므로, GameplayMode에 배치하는 것이 좋은 방법임.

        #pragma once
        
        #include "CoreMinimal.h"
        #include "GameFramework/GameModeBase.h"
        #include "AuraGameModeBase.generated.h"
        
        class UCharacterClassInfo;
        
        UCLASS()
        class AURA_API AAuraGameModeBase : public AGameModeBase
        {
        	GENERATED_BODY()
        
        public:
        	UPROPERTY(EditDefaultsOnly, Category = "Character Class Info")
        	TObjectPtr<UCharacterClassInfo> CharacterClassInfo;
        
        };
      • 그리고 GameMode에 존재하는 UCharacterClassInfo에 쉽게 접근할 수 있도록, 블루프린트 함수 라이브러리에 함수를 작성하여 사용할 수 있음.

        #pragma once
        
        #include "CoreMinimal.h"
        #include "Kismet/BlueprintFunctionLibrary.h"
        #include "UI/WidgetController/OverlayWidgetController.h"
        #include "Data/CharacterClassInfo.h"
        #include "AuraAbilitySystemLibrary.generated.h"
        
        class UAbilitySystemComponent;
        
        UCLASS()
        class AURA_API UAuraAbilitySystemLibrary : public UBlueprintFunctionLibrary
        {
        	GENERATED_BODY()
        	
        public:
        	UFUNCTION(BlueprintPure, Category = "AuraAbilitySystemLibrary|WidgetController")
        	static UOverlayWidgetController* GetOverlayWidgetController(const UObject* WorldContextObject);
        
        	UFUNCTION(BlueprintPure, Category = "AuraAbilitySystemLibrary|WidgetController")
        	static UAttributeMenuWidgetController* GetAttributeMenuWidgetController(const UObject* WorldContextObject);
        
        	UFUNCTION(BlueprintCallable, Category = "AuraAbilitySystemLibrary|CharacterClassInfo")
        	static void InitializeDefaultAttributes(const UObject* WorldContextObject, ECharacterClass CharacterClass, float Level, UAbilitySystemComponent* AbilitySystemComponent);
        };
        
        // AuraAbilitySystemLibrary.cpp
        void UAuraAbilitySystemLibrary::InitializeDefaultAttributes(const UObject* WorldContextObject, ECharacterClass CharacterClass, float Level, UAbilitySystemComponent* AbilitySystemComponent)
        {
        	AAuraGameModeBase* AuraGameMode = Cast<AAuraGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject));
        	
        	if (AuraGameMode == nullptr) return;
        
        	AActor* AvatarActor = AbilitySystemComponent->GetAvatarActor();
        
        	UCharacterClassInfo* CharacterClassInfo = AuraGameMode->CharacterClassInfo;
        	FCharacterClassDefaultInfo ClassDefaultInfo = CharacterClassInfo->GetClassDefaultInfo(CharacterClass);
        	
        	FGameplayEffectContextHandle PrimaryAttributeContextHandle = AbilitySystemComponent->MakeEffectContext();
        	PrimaryAttributeContextHandle.AddSourceObject(AvatarActor);
        	FGameplayEffectSpecHandle PrimaryAttributeSpecHandle = AbilitySystemComponent->MakeOutgoingSpec(ClassDefaultInfo.PrimaryAttributes, Level, AbilitySystemComponent->MakeEffectContext());
        	AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*PrimaryAttributeSpecHandle.Data.Get());
        
        	FGameplayEffectContextHandle SecondaryAttributeContextHandle = AbilitySystemComponent->MakeEffectContext();
        	SecondaryAttributeContextHandle.AddSourceObject(AvatarActor);
        	FGameplayEffectSpecHandle SecondaryAttributeSpecHandle = AbilitySystemComponent->MakeOutgoingSpec(CharacterClassInfo->SecondaryAttributes, Level, AbilitySystemComponent->MakeEffectContext());
        	AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*SecondaryAttributeSpecHandle.Data.Get());
        
        	FGameplayEffectContextHandle VitalAttributeContextHandle = AbilitySystemComponent->MakeEffectContext();
        	VitalAttributeContextHandle.AddSourceObject(AvatarActor);
        	FGameplayEffectSpecHandle VitalAttributeSpecHandle = AbilitySystemComponent->MakeOutgoingSpec(CharacterClassInfo->VitalAttributes, Level, AbilitySystemComponent->MakeEffectContext());
        	AbilitySystemComponent->ApplyGameplayEffectSpecToSelf(*VitalAttributeSpecHandle.Data.Get());
        }
profile
저는 게임 개발자로 일하고 싶어요

0개의 댓글