-
[Unreal Engine] GamePlay Ability System #2 Attribute Sets2024년 05월 12일
- 유니얼
-
작성자
-
2024.05.12.:29
728x90Unreal Engine의 Gameplay Ability System(GAS)은 개발자가 게임 내에서 캐릭터의 능력, 상태 변경, 상호작용 등을 효율적으로 관리할 수 있게 하는 강력한 프레임워크입니다. 이 시스템의 핵심 요소 중 하나는 "속성(Attribute)"입니다. 이번 포스트에서는 GAS에서 속성이 어떻게 정의되고 사용되는지에 대해 자세히 살펴보겠습니다.
참고 링크:
언리얼 엔진의 게임플레이 어빌리티 시스템을 위한 게임플레이 어트리뷰트 및 어트리뷰트 세트
게임플레이 어트리뷰트 및 어트리뷰트 세트 사용하기
dev.epicgames.com
속성(Attribute)의 정의
속성은 FGameplayAttributeData 구조체를 사용하여 정의되며, 이는 게임 내에서 캐릭터의 다양한 수치 정보를 나타냅니다. 이러한 수치들은 캐릭터의 남은 생명력, 비히클의 최고 속도, 아이템 사용 가능 횟수 등을 포함할 수 있으며, 각각의 속성은 AttributeSet 내에 저장되어 관리됩니다.
속성은 기본적으로 ‘현재(current) 값’과 ‘기본(base) 값’ 두 가지를 가집니다. 기본 값은 보다 장기적으로 고정되어 있으며, 현재 값은 게임플레이 이펙트에 따라 일시적으로 변경될 수 있습니다. 예를 들어, 점프 높이 속성이 기본적으로 100.0이지만, 특정 게임플레이 이펙트로 인해 70%만큼 저하되었다면 현재 값은 70.0이 됩니다.
어트리뷰트 세트(Attribute Set)의 정의 및 구성
어트리뷰트 세트는 하나 이상의 게임플레이 어트리뷰트(Gameplay Attributes)로 구성됩니다. 게임플레이 어트리뷰트는 FGameplayAttributeData UProperties로 표현되며, 이들은 캐릭터의 생명력, 이동 속도, 마나 등과 같은 게임플레이 관련 수치를 저장하고 관리하는 역할을 합니다.
속성의 생성 및 관리
속성을 생성하고 관리하기 위해서는 먼저 AttributeSet을 정의해야 합니다. AttributeSet은 하나 이상의 게임플레이 속성을 포함하며, 어빌리티 시스템 컴포넌트에 등록되어 게임플레이 속성과 시스템의 다른 부분 간의 상호작용을 관리합니다.
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "AttributeSet.h" #include "AbilitySystemComponent.h" #include "CharacterAttributeSetBase.generated.h" UCLASS() class SAMPLEPROJECT_API UCharacterAttributeSetBase : public UAttributeSet { GENERATED_BODY() public: UPROPERTY(BlueprintReadOnly, Category = "Level") FGameplayAttributeData Level; UPROPERTY(BlueprintReadOnly, Category = "Health") FGameplayAttributeData Health; UPROPERTY(BlueprintReadOnly, Category = "Health") FGameplayAttributeData MaxHealth; UPROPERTY(BlueprintReadOnly, Category= "Mana") FGameplayAttributeData Mana; UPROPERTY(BlueprintReadOnly, Category= "Mana") FGameplayAttributeData MaxMana; UPROPERTY(BlueprintReadOnly, Category="Damage") FGameplayAttributeData Damage; };
게임플레이 어트리뷰트 상호작용 매크로
어트리뷰트와 효율적으로 상호작용하기 위해 Unreal Engine은 다음과 같은 매크로를 제공합니다. 이 매크로들은 어트리뷰트 세트의 헤더 파일에 추가하여 사용할 수 있으며, 각 어트리뷰트에 대한 getter와 setter 함수를 자동으로 생성해 줍니다.
매크로(파라미터) 생성된 함수의 시그니처 행동/사용 GAMEPLAYATTRIBUTE_PROPERTY_GETTER(UMyAttributeSet,AttributeName) static FGameplayAttribute GetHealth() 스태틱 함수이며, 엔진의 리플렉션 시스템으로부터 FGameplayAttribute 구조체를 반환합니다. GAMEPLAYATTRIBUTE_VALUE_GETTER(AttributeName) float GetAttribute() const 게임플레이 어트리뷰트의 현재 값을 반환합니다. GAMEPLAYATTRIBUTE_VALUE_SETTER(AttributeName) void SetAttribute(float NewVal) 게임플레이 어트리뷰트의 값을 NewVal 로 설정합니다. GAMEPLAYATTRIBUTE_VALUE_INITTER(AttributeName) void InitAttribute(float NewVal) 게임플레이 어트리뷰트의 값을 NewVal 로 초기화합니다. // Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "AttributeSet.h" #include "AbilitySystemComponent.h" #include "CharacterAttributeSetBase.generated.h" // ATTRIBUTE_ACCESSORS 매크로: 주어진 속성에 대한 접근자 함수들을 자동으로 생성합니다. // ClassName은 클래스 이름, PropertyName은 속성 이름을 인자로 받습니다. // 이 매크로는 속성의 getter, setter 및 초기화 함수를 정의합니다. #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) /** * */ UCLASS() class SAMPLEPROJECT_API UCharacterAttributeSetBase : public UAttributeSet { GENERATED_BODY() public: UPROPERTY(BlueprintReadOnly, Category = "Level") FGameplayAttributeData Level; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Level) UPROPERTY(BlueprintReadOnly, Category = "Health") FGameplayAttributeData Health; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Health) UPROPERTY(BlueprintReadOnly, Category = "Health") FGameplayAttributeData MaxHealth; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxHealth) UPROPERTY(BlueprintReadOnly, Category= "Mana") FGameplayAttributeData Mana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Mana) UPROPERTY(BlueprintReadOnly, Category= "Mana") FGameplayAttributeData MaxMana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxMana) UPROPERTY(BlueprintReadOnly, Category="Damage") FGameplayAttributeData Damage; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Damage); }
어트리뷰트 세트의 리플리케이션 설정
어트리뷰트 세트 내에서 개별 게임플레이 어트리뷰트의 리플리케이션을 설정하는 것은 멀티플레이어 게임에서 각 플레이어의 게임 상태를 동기화하는 데 필수적입니다. 예를 들어, 캐릭터의 'Health' 어트리뷰트를 리플리케이트하려면 다음 단계를 따라야 합니다:
1. 어트리뷰트 프로퍼티 정의
UPROPERTY 매크로를 사용하여 어트리뷰트를 정의하고, ReplicatedUsing 지정자를 추가하여 리플리케이션 시 호출될 콜백 함수를 지정합니다.
UCLASS() class SAMPLEPROJECT_API UCharacterAttributeSetBase : public UAttributeSet { GENERATED_BODY() public: // Level 속성: 캐릭터의 현재 건강 수치를 나타내며, 변경 시 OnRep_Health 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Level", ReplicatedUsing = OnRep_Level) FGameplayAttributeData Level; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Level) // Health 속성: 캐릭터의 현재 건강 수치를 나타내며, 변경 시 OnRep_Health 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health) FGameplayAttributeData Health; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Health) // MaxHealth 속성: 캐릭터의 최대 건강 수치를 나타내며, 변경 시 OnRep_MaxHealth 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_MaxHealth) FGameplayAttributeData MaxHealth; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxHealth) // Mana 속성: 캐릭터의 현재 마나 수치를 나타내며, 변경 시 OnRep_Mana 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category= "Mana", ReplicatedUsing= OnRep_Mana) FGameplayAttributeData Mana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Mana) // MaxMana 속성: 캐릭터의 최대 마나 수치를 나타내며, 변경 시 OnRep_MaxMana 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category= "Mana", ReplicatedUsing= OnRep_MaxMana) FGameplayAttributeData MaxMana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxMana) // Damage 속성: 캐릭터가 입히는 피해량을 나타냅니다. 이 값은 능력 시스템을 통해 변경될 수 있습니다. UPROPERTY(BlueprintReadOnly, Category="Damage") FGameplayAttributeData Damage; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Damage); }
2. 리플리케이션 콜백 함수 선언
네트워크를 통해 새로운 'Attribute' 값이 도착할 때 호출될 콜백 함수를 선언합니다
// Health 속성 변경 시 호출되는 함수, 변경 전 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Level(const FGameplayAttributeData& OldLevel); // Health 속성 변경 시 호출되는 함수, 변경 전 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Health(const FGameplayAttributeData& OldHealth); // MaxHealth 속성 변경 시 호출되는 함수, 변경 전 최대 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth); // Mana 속성 변경 시 호출되는 함수, 변경 전 마나 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Mana(const FGameplayAttributeData& OldMana); // MaxMana 속성 변경 시 호출되는 함수, 변경 전 최대 마나 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana); // 네트워크 복제를 위한 속성들을 설정하는 함수. virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; };
3. 콜백 함수 구현
어트리뷰트 세트의 소스 파일에서 콜백 함수를 정의하고, GAMEPLAYATTRIBUTE_REPNOTIFY 매크로를 사용하여 기본적인 리플리케이션 행동을 구현합니다.
#include "Character/Abilities/AttributeSets/CharacterAttributeSetBase.h" #include "Net/UnrealNetwork.h" void UCharacterAttributeSetBase::OnRep_Level(const FGameplayAttributeData& OldLevel) { // Health 속성의 변경을 처리하고, 필요한 UI 업데이트나 게임 로직을 트리거할 수 있습니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Level, OldLevel); } // Health 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth) { // Health 속성의 변경을 처리하고, 필요한 UI 업데이트나 게임 로직을 트리거할 수 있습니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Health, OldHealth); } // MaxHealth 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) { // MaxHealth 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, MaxHealth, OldMaxHealth); } // Mana 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_Mana(const FGameplayAttributeData& OldMana) { // Mana 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Mana, OldMana); } // MaxMana 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) { // MaxMana 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, MaxMana, OldMaxMana); }
4. 리플리케이션 프로퍼티 등록
GetLifetimeReplicatedProps 함수를 오버라이드하여 어트리뷰트의 리플리케이션을 설정합니다. 이 함수는 어떤 프로퍼티가 네트워크를 통해 복제될지 결정합니다.
// 네트워크 동기화를 위해 속성 복제를 설정하는 함수입니다. void UCharacterAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { // 부모 클래스의 동일 함수를 호출하여 기본 속성 복제 설정을 상속받습니다. Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 각 속성의 네트워크 복제를 설정합니다. 이 속성들은 항상 네트워크에 복제되며, 값이 변경되면 통지가 발생합니다. DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Level, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Health, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Mana, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, MaxMana, COND_None, REPNOTIFY_Always); }
전체코드
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "AttributeSet.h" #include "AbilitySystemComponent.h" #include "CharacterAttributeSetBase.generated.h" // ATTRIBUTE_ACCESSORS 매크로: 주어진 속성에 대한 접근자 함수들을 자동으로 생성합니다. // ClassName은 클래스 이름, PropertyName은 속성 이름을 인자로 받습니다. // 이 매크로는 속성의 getter, setter 및 초기화 함수를 정의합니다. #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \ GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) /** * */ UCLASS() class SAMPLEPROJECT_API UCharacterAttributeSetBase : public UAttributeSet { GENERATED_BODY() public: // Level 속성: 캐릭터의 현재 건강 수치를 나타내며, 변경 시 OnRep_Health 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Level", ReplicatedUsing = OnRep_Level) FGameplayAttributeData Level; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Level) // Health 속성: 캐릭터의 현재 건강 수치를 나타내며, 변경 시 OnRep_Health 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health) FGameplayAttributeData Health; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Health) // MaxHealth 속성: 캐릭터의 최대 건강 수치를 나타내며, 변경 시 OnRep_MaxHealth 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_MaxHealth) FGameplayAttributeData MaxHealth; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxHealth) // Mana 속성: 캐릭터의 현재 마나 수치를 나타내며, 변경 시 OnRep_Mana 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category= "Mana", ReplicatedUsing= OnRep_Mana) FGameplayAttributeData Mana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Mana) // MaxMana 속성: 캐릭터의 최대 마나 수치를 나타내며, 변경 시 OnRep_MaxMana 함수를 호출합니다. UPROPERTY(BlueprintReadOnly, Category= "Mana", ReplicatedUsing= OnRep_MaxMana) FGameplayAttributeData MaxMana; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, MaxMana) // Damage 속성: 캐릭터가 입히는 피해량을 나타냅니다. 이 값은 능력 시스템을 통해 변경될 수 있습니다. UPROPERTY(BlueprintReadOnly, Category="Damage") FGameplayAttributeData Damage; ATTRIBUTE_ACCESSORS(UCharacterAttributeSetBase, Damage); // Health 속성 변경 시 호출되는 함수, 변경 전 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Level(const FGameplayAttributeData& OldLevel); // Health 속성 변경 시 호출되는 함수, 변경 전 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Health(const FGameplayAttributeData& OldHealth); // MaxHealth 속성 변경 시 호출되는 함수, 변경 전 최대 건강 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth); // Mana 속성 변경 시 호출되는 함수, 변경 전 마나 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_Mana(const FGameplayAttributeData& OldMana); // MaxMana 속성 변경 시 호출되는 함수, 변경 전 최대 마나 수치를 인자로 받습니다. UFUNCTION() virtual void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana); // 네트워크 복제를 위한 속성들을 설정하는 함수. virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override; };
// Fill out your copyright notice in the Description page of Project Settings. #include "Character/Abilities/AttributeSets/CharacterAttributeSetBase.h" #include "Net/UnrealNetwork.h" void UCharacterAttributeSetBase::OnRep_Level(const FGameplayAttributeData& OldLevel) { // Health 속성의 변경을 처리하고, 필요한 UI 업데이트나 게임 로직을 트리거할 수 있습니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Level, OldLevel); } // Health 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth) { // Health 속성의 변경을 처리하고, 필요한 UI 업데이트나 게임 로직을 트리거할 수 있습니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Health, OldHealth); } // MaxHealth 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) { // MaxHealth 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, MaxHealth, OldMaxHealth); } // Mana 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_Mana(const FGameplayAttributeData& OldMana) { // Mana 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, Mana, OldMana); } // MaxMana 속성이 네트워크를 통해 변경되었을 때 호출되는 함수입니다. void UCharacterAttributeSetBase::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) { // MaxMana 속성의 변경을 처리합니다. GAMEPLAYATTRIBUTE_REPNOTIFY(UCharacterAttributeSetBase, MaxMana, OldMaxMana); } // 네트워크 동기화를 위해 속성 복제를 설정하는 함수입니다. void UCharacterAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const { // 부모 클래스의 동일 함수를 호출하여 기본 속성 복제 설정을 상속받습니다. Super::GetLifetimeReplicatedProps(OutLifetimeProps); // 각 속성의 네트워크 복제를 설정합니다. 이 속성들은 항상 네트워크에 복제되며, 값이 변경되면 통지가 발생합니다. DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Level, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Health, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, MaxHealth, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, Mana, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(UCharacterAttributeSetBase, MaxMana, COND_None, REPNOTIFY_Always); }
결론
Unreal Engine의 Gameplay Ability System에서 속성을 효과적으로 관리하는 것은 게임의 다이내믹을 조절하고 플레이어에게 몰입감 있는 경험을 제공하는 데 필수적입니다. 속성 시스템을 통해 개발자는 캐릭터의 다양한 상태와 능력을 정밀하게 조절하며, 게임의 다양한 상황에 맞게 적응시킬 수 있습니다.
반응형다음글이전글이전 글이 없습니다.댓글