Attribute는 캐릭터의 능력치 하나하나를 말합니다. 예를 들어:
Health (체력)
MaxHealth (최대 체력)
Mana (마나)
Strength (힘)
Defense (방어력)
이러한 값들은 보통 float 타입이며, GameplayEffect를 통해 여러 작업을 할 수 있습니다.
AttributeSet은 여러 개의 Attribute들을 묶어서 관리하는 클래스입니다.
Owner Actor의 생성자에서 해당 AttributeSet을 생성하면 자동으로 ASC(AbilitySystemComponent)에 등록됩니다.
AbilitySystemComponent는 하나 또는 여러 개의 AttributeSet을 가질 수 있습니다. 각 방식의 장단점을 이해하고, 게임의 구조에 맞게 설계하는 것이 중요합니다.
✅ 단일 모놀리식 AttributeSet 방식
예: 체력, 마나, 스태미나, 방어력 등 모든 스탯을 UMyCommonAttributeSet에 정의하고 모든 캐릭터에 적용
✅ 그룹화된 다중 AttributeSet 방식
AttributeSet의 생성은 현재 C++에서만 수행됩니다. 블루프린트에서는 ASC와 AttributeSet의 초기화 흐름을 완전히 제어할 수 없습니다. (5.5 version 기준)
우선 AttributeSet 클래스를 부모로 삼는 GAS_AttributeSet을 생성하겠습니다.
// GAS_AttributeSet.h
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h" // AttributeSet을 사용하기 위한 헤더 파일
#include "GAS_AttributeSet.generated.h"
// Attribute를 정의하기 위한 매크로들
// UAttributeSet에 정의되어 있는 매크로로 Getter, setter, initter 등을 자동으로 생성합니다.
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GASTEMPLATE_API UGAS_AttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
/*
* 속성(Attribute)에 어떤 수정이 일어나기 직전에 호출됩니다. 이 함수는 PreAttributeModify/PostAttributeModify보다 더 하위 레벨에서 동작합니다.
* 여기서는 추가적인 컨텍스트가 제공되지 않으며, 실행된 효과, 지속 효과, 효과 제거, 면역 적용, 스택 규칙 변경 등 어떤 것이든 이 함수를 트리거할 수 있습니다.
* 이 함수의 목적은 "Health = Clamp(Health, 0, MaxHealth)"와 같이 값을 강제로 제한하는 것이며, "데미지가 적용되면 추가로 무언가를 트리거한다"와 같은 동작을 구현하는 곳이 아닙니다.
*
* NewValue는 변경 가능한 참조(mutable reference)이므로, 새로 적용되는 값을 이 함수 내에서 제한(clamp)할 수 있습니다.
*/
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
/* 속성(Attribute)에 어떤 수정이 발생한 직후에 호출됩니다. */
virtual void PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue) override;
// 속성(Attribute) 정의
UPROPERTY(BlueprintReadOnly, Category = "Attribute")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UGAS_AttributeSet, Health) // Health 속성에 대한 Getter, Setter, Initter를 자동으로 생성합니다.
};
// GAS_AttributeSet.cpp
#include "GAS/Attributes/GAS_AttributeSet.h"
void UGAS_AttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
// 여기서 속성(Attribute)의 값을 제한하거나 조정할 수 있습니다.
}
void UGAS_AttributeSet::PostAttributeChange(const FGameplayAttribute& Attribute, float OldValue, float NewValue)
{
// 속성(Attribute)의 값이 변경된 후에 추가적인 작업을 수행할 수 있습니다.
}
AttributeSet에서 Attribute를 생성하려면 3가지의 기본적인 작업이 필요합니다
#include "AbilitySystemComponent.h" 헤더 추가#define ATTRIBUTE_ACCESSORS 매크로 추가Attribute 변수 생성이렇게 생성된 Attribute는 이제 GAS Framework내에서 자유롭게 사용하여 다양한 값들을 사용할 수 있게 됩니다.
또한 생성된 Attribute는 Unreal Engine에서 제공하는 멀티플레이에서의 프로퍼티 복제 시스템과 매우 유사한 방식으로 사용 가능합니다.
이에 대해서는 추가적인 작업이 필요하지만, 이번에는 다루지 않겠습니다.
이제 액터에 생성한 AttributeSet을 적용시켜보겠습니다.
현재(5.5 version 혹은 그 이하 버전)는 ASC가 부착된 액터에 AttributeSet을 사용하기 위해서는 C++에서만 생성이 가능합니다.
// YourCharacter.h
...
class AGASTemplateCharacter : public ACharacter, public IAbilitySystemInterface
{
GENERATED_BODY()
...
/** AttributeSet */
UPROPERTY()
TObjectPtr<class UGAS_AttributeSet> AttributeSet;
적용시킨 AttributeSet을 초기화하는 방식에는 여러 가지가 있습니다.
그 중에서도 여기에서는 DataTable 혹은 CurveTables을 이용하는 방식에 대해 설명하겠습니다.
브라우저에서 우클릭을 한 뒤,
기타 - 데이터테이블 - 행구조(AttributeMetaData) 선택
을 한 후 DT_InitAttributeSet을 생성합니다.

이후 DataTable의 값의 이름을 "AttributeSet Name"."Attribute Name"과 같은 형식으로 만들고 초기화할 값과 최소 최대값을 지정해줍니다.
이렇게 생성된 데이터 테이블은 블루프린트에서 액터의 Ability System Component - Attribute Test 항목에 넣어 사용할 수 있게 됩니다.

이후 게임을 시작해보면 디버깅 창에 다음과 같이 Attribute가 적용된 것을 볼 수 있습니다.

이제 이렇게 생성된 Attribute는 Gameplay Ability와 Gameplay Effect 등을 통해 자유롭게 변경이 가능합니다.
다음 포스팅에서는 생성된 Attribute를 가지고 Gameplay Effect를 다루어 보겠습니다.