FGameplayAttributeData
타입의 애트리뷰트를 만들고 Replicated 변수로 등록한다.
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
UCLASS()
class AURA_API UAuraAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UAuraAttributeSet();
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = Vital)
FGameplayAttributeData Health;
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth) const;
};
GetLifetimeReplicatedProps
에서 DOREPLIFETIME_CONDITION
매크로를 이용해 복제 변수 등록을 해 주는 것과 더불어, 애트리뷰트의 경우 Rep Notify 함수에서 하나의 작업을 더 해줘야 하는데 GAMEPLAYATTRIBUTE_REPNOTIFY
매크로를 사용해준다. 마찬가지로 이 애트리뷰트의 값을 다른 플레이어들에게 복제하겠다는 뜻
void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Health, COND_None, REPNOTIFY_Always);
}
void UAuraAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Health, OldHealth);
}
GAMEPLAYATTRIBUTE_REPNOTIFY
의 definition을 타고 올라가면 AttributeSet.h
에서 매크로가 선언된 곳을 찾아갈 수 있는데, 여기서 이런 주석 메시지를 볼 수 있다.
/**
* This defines a set of helper functions for accessing and initializing attributes, to avoid having to manually write these functions.
* It would creates the following functions, for attribute Health
*
* static FGameplayAttribute UMyHealthSet::GetHealthAttribute();
* FORCEINLINE float UMyHealthSet::GetHealth() const;
* FORCEINLINE void UMyHealthSet::SetHealth(float NewVal);
* FORCEINLINE void UMyHealthSet::InitHealth(float NewVal);
*
* To use this in your game you can define something like this, and then add game-specific functions as necessary:
*
* #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
* GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
* GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
*
* ATTRIBUTE_ACCESSORS(UMyHealthSet, Health)
*/
대충 해석하자면 애트리뷰트에 접근하고 값을 초기화하는 데 사용되는 유용한 함수들을 제공한다는 뜻이며, static
, FORCEINLINE
함수들을 자동으로 생성한 효과를 낼 수 있다는 것이다.
아래 #define
으로부터 5개 라인을 복사해서 내 attribute set 헤더 파일로 가져간다.
그리고 애트리뷰트를 선언한 부분에서 아래에 ATTRIBUTE_ACCESSORS(UMyHealthSet, Health)
을 추가함으로써 간단하게 유틸 함수들을 만들 수 있다.
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = Vital)
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Health);
이제 이렇게 하면 별도의 이니셜라이저나 게터, 세터 함수를 만들지 않더라도 다음과 같은 문법으로 함수들을 사용할 수 있다.
'PropertyName' 에 애트리뷰트 명이 들간 형태로 Get, Set, Init을 사용할 수 있다. 또는 뒤에 Attribute()
를 붙여서 데이터 자체를 가져올 수도 있다.
자동완성되어 사용할 수 있는 모습.
디버깅 모드로 에디터를 실행한 후 게임에 들어가 백틱을 눌러 콘솔 입력 모드로 들어간다.
그리고 showdebug abilitysystem
이라고 치면 위 사진과 같이 여러 캐릭터들의 GAS 상태, 좌표, 태그 등을 확인할 수 있다. 아래에 AbilityTag
에서 내가 설정한 값이 반영돼있는 것을 확인할 수 있다.