๐ ์ ๋ฐ๋ฏธ GAS ๊ฐ์ ์ค ๊ธฐ๋กํด๋๊ณ ์ถ์ ๋ด์ฉ์ ์ ์ด๋ ํฌ์คํธ
Section 3 : GAS์ AttributeSet ์ถ๊ฐํ๊ธฐ
ASC(AbilitySystemComponent)์ ์ฌ๋ฌ AttributeSet ์ฌ์ฉ ๊ฐ๋ฅ


Attribute ๊ฐ์ ์กฐ์ ํ๋ ๋ฐฉ์์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ง๋ง ์์ ์์๋ ๊ฒ์ํ๋ ์ด ์ดํํธ๋ฅผ ์ฌ์ฉํ๋ค.
์ด๋ฅผ ํตํด ์ธ๋ฆฌ์ผ ์์ง์์ ์ง์ํ๋ ๋ฆฌํ๋ฆฌ์ผ์ด์
๋ฐฉ์์ธ ๋ก์ปฌ ์์ธก ๋ฐฉ์์ ์ฌ์ฉํ ์ ์๊ธฐ๋๋ฌธ
๋ฐ์์ฑ๊ณผ ์ ํ์ฑ ์ฌ์ด์ ๊ท ํ์ด ์ ์กํ ์ต์ ์ ๋๋ค. ํด๋ผ์ด์ธํธ๊ฐ ๋ช ๋ น์ ๋ด๋ฆฌ๋ฉด ๋ก์ปฌ ํด๋ผ์ด์ธํธ์์ ์ด๋น๋ฆฌํฐ๊ฐ ์ฆ์ ์คํ๋์ง๋ง, ์ด๋น๋ฆฌํฐ์ ์ค์ ์ํฅ์ด ์ด๋ ๋์ง์ ๋ํ ์ต์ข ๊ฒฐ์ ์ ์๋ฒ๊ฐ ๋ด๋ฆฌ๊ณ ํด๋ผ์ด์ธํธ๋ฅผ ์ค๋ฒ๋ผ์ด๋ํ ์ ์์ต๋๋ค. ์ค์ ๋ก ํด๋ผ์ด์ธํธ๋ ์๋ฒ์ ์ด๋น๋ฆฌํฐ ์คํ ๊ถํ์ ์์ฒญํ์ง๋ง, ํด๋ผ์ด์ธํธ ๊ด์ ์ ๊ฒฐ๊ณผ๋ฅผ ์๋ฒ๊ฐ ๋์ํ ๊ฒ์ผ๋ก ์์ํ๊ณ ๋ก์ปฌ์์ ์งํํฉ๋๋ค. ํด๋ผ์ด์ธํธ๋ ๋ก์ปฌ์์ ์ด๋น๋ฆฌํฐ์ ๋นํค์ด๋น์ด๋ฅผ ์์ธกํ๋ฏ๋ก, ํด๋ผ์ด์ธํธ์ ์์ธก์ด ์๋ฒ์ ๋ชจ์๋์ง ์๋๋ค๋ฉด ์ง์ฐ ์์ด ์์ ํ ๋งค๋๋ฝ๊ฒ ๋๊ปด์ง ๊ฒ์ ๋๋ค.
์ถ์ฒ : ์ธ๋ฆฌ์ผ ๊ณต์ ๋ฌธ์

Attribute๋ฅผ ํํํ๋ ๊ตฌ์กฐ์ฒด๋ก BaseValue์ CurrentValue๋ก ๊ตฌ์ฑ๋์ด์๋ค.
BaseValue ๋ MaxValue๊ฐ ์๋๋ฏ๋ก HealthAttribute๋ฅผ ๋ง๋ ๋ค๊ณ ํ ๋ Base๋ฅผ MaxHealth์ฒ๋ผ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋๊ณ MaxHealthAttribute๋ฅผ ๋ฐ๋ก ๋ง๋ค์ด์ ์ฌ์ฉValue๋ floatํํฌ๊ฒ ์ธ๊ฐ์ง ๊ณตํต ์ฝ๋๋ฅผ ์ถ๊ฐํด์ผํ๋ค.
1. ReplicatedUsing ํด๋์ค ์ง์ ์์ RepNotify ์ถ๊ฐํ๊ธฐ
2. GetLifetimeReplicatedProps์ ๋ณ์ ๋ฑ๋กํ๊ธฐ
3. GAMEPLAYATTRIBUTE_REPNOTIFY๋ก ASC์ ์ฐ๋ํ๊ธฐ
ReplicatedUsing ํด๋์ค ์ง์ ์์ RepNotify ์ถ๊ฐํ๊ธฐUPROPERTY(BlueprintReadOnly,ReplicatedUsing=OnRep_Health,Category="Vital Attributes")
FGameplayAttributeData Health;
ReplicatedUsing ํด๋์ค ์ง์ ์๋ฅผ ์ถ๊ฐํ๊ณ RepNotify ํจ์๋ช
์ ๋ฌ์์ค๋ค.UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth) const;
GetLifetimeReplicatedProps์ ๋ณ์ ๋ฑ๋กํ๊ธฐGetLifetimeReplicatedProps ํจ์๋ฅผ ์ค๋ฒ๋ผ์ด๋ ํ ๋ค
DOREPLIFETIME_CONDITION_NOTIFY ๋งคํฌ๋ก๋ฅผ ํตํด Attribute๋ฅผ ๋ฑ๋กํ๋ค.
void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<class FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet,Health,COND_None,REPNOTIFY_Always);
}
DOREPLIFETIME_CONDITION_NOTIFY(ํด๋์ค, ๋ฉค๋ฒ, ์กฐ๊ฑด, ๋
ธํฐํ์ด ์ค์ )
COND_None : ๋ฆฌํ๋ฆฌ์ผ์ด์
๋๋ ๋ฐฉ์์ ์ค์ ํ๋ ๊ฒ (None์ ํญ์ ๋ฆฌํ๋ฆฌ์ผ์ด์
๋๋๋ก ํจ)REPNOTIFY_Always๋ ํญ์ ๋ฆฌํ๋ฆฌ์ผ์ด์
๋๋๋ก ์ค์ ํ ๊ฒ.REPNOTIFY_OnChanged๋ก ๋ก์ปฌ ๊ฐ๊ณผ ๋ค๋ฅผ ๋๋ง ๋ฆฌํ๋ฆฌ์ผ์ด์
)GAMEPLAYATTRIBUTE_REPNOTIFY๋ก ASC์ ์ฐ๋ํ๊ธฐ
void UAuraAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet,Health,OldHealth);
}
RepNotify ํจ์์์ ๋ฆฌํ๋ฆฌ์ผ์ด์
๋ ๋ ASC์๋ ์ ๋ฌ๋๋๋ก ์ฌ์ฉํ๋ ํฌํผ ๋งคํฌ๋ก์ด๋ค.
"This is a helper macro that can be used in RepNotify functions to handle attributes that will be predictively modified by clients."
Attribute๋ง๋ค ๊ธฐ๋ณธ์ ์ผ๋ก ์ฌ์ฉํ ์ผ์ด ๋ง์ Getter, Setter, Init ๋ฑ์ ํจ์๋ฅผ ์ผ์ผ์ด ๋ง๋ค์ง ์๋๋ก ์ ๊ทผ์ ์์ฑ ๋งคํฌ๋ก๋ฅผ ์ง์ํ๋ค.
attributeset.h์ ์ฐพ์๋ณด๋ฉด ATTRIBUTE_ACCESSORS๊ฐ ์ ์๋ ๋ถ๋ถ์ด ์๋ค.
ํด๋น ๋งคํฌ๋ก๋ฅผ ์ปค์คํ
ํด๋์ค ํค๋์ ์ถ๊ฐํ๋ฉด ๋๋ค.
์ถ๊ฐํ ๋ผ์ธ
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
์ฌ์ฉ ์์
UPROPERTY(BlueprintReadOnly,ReplicatedUsing=OnRep_Health,Category="Vital Attributes")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(UAuraAttributeSet,Health)
ATTRIBUTE_ACCESSORS(ํด๋์ค,์์ฑ์ด๋ฆ) ๋ฅผ ๋ฑ๋กํ๋ฉด ์ดํ
InitMaxHealth(100);
InitHealth(GetMaxHealth());
์ด๋ฐ์์ผ๋ก Get์์ฑ์ด๋ฆAttribute, Get์์ฑ์ด๋ฆ, Set์์ฑ์ด๋ฆ, Init์์ฑ์ด๋ฆ 4๊ฐ์ ํจ์๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
ํจ์ ์ํ
#define GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
static FGameplayAttribute Get##PropertyName##Attribute() \
{ \
static FProperty* Prop = FindFieldChecked<FProperty>(ClassName::StaticClass(), GET_MEMBER_NAME_CHECKED(ClassName, PropertyName)); \
return Prop; \
}
#define GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
FORCEINLINE float Get##PropertyName() const \
{ \
return PropertyName.GetCurrentValue(); \
}
#define GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
FORCEINLINE void Set##PropertyName(float NewVal) \
{ \
UAbilitySystemComponent* AbilityComp = GetOwningAbilitySystemComponent(); \
if (ensure(AbilityComp)) \
{ \
AbilityComp->SetNumericAttributeBase(Get##PropertyName##Attribute(), NewVal); \
}; \
}
#define GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) \
FORCEINLINE void Init##PropertyName(float NewVal) \
{ \
PropertyName.SetBaseValue(NewVal); \
PropertyName.SetCurrentValue(NewVal); \
}
Get์์ฑ์ด๋ฆAttribute : FGameplayAttribute ๊ตฌ์กฐ์ฒด๋ฅผ ๋ฆฌํด
Get์์ฑ์ด๋ฆ : CurrentValue๋ฅผ ๋ฆฌํด
Set์์ฑ์ด๋ฆ : BaseValue๋ฅผ ์ค์
Init์์ฑ์ด๋ฆ : BaseValue์ CurrentValue๋ฅผ ๋์์ ์ค์

์ฝ์ ๋ช
๋ น์ด showdebug abilitysystem ์ ์
๋ ฅํด ์์ง์์ ๋๋ฒ๊น
์ด ๊ฐ๋ฅํ๋ค.
(์คํฌ๋ฆฐ์ท ์ข์ธก ์ค์์ ์์ฑ๊ณผ ๊ฐ์ด ํ์๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.)
if (IAbilitySystemInterface* ASCInterface = Cast<IAbilitySystemInterface>(OtherActor))
{
const UAuraAttributeSet* AuraAttributeSet =
Cast<UAuraAttributeSet>(ASCInterface->
GetAbilitySystemComponent()->
GetAttributeSet(UAuraAttributeSet::StaticClass()));
}
OtherActor๊ฐ ASC ์ธํฐํ์ด์ค๋ฅผ ์์ ๋ฐ์๋ค๋ฉด ์บ์คํ
์ฑ๊ณตASC ์ธํฐํ์ด์ค ๊ตฌํ ํจ์์ธ GetAbilitySystemComponent()๋ฅผ ํตํด ์กํฐ์ ASC์ ์ ๊ทผGetAttributeSet()์ ํตํด ASC์ ๋ฑ๋ก๋ AttributeSet์ ์ ๊ทผํ๋ค.ASC๋ ์ด๊ธฐํ๋ ๋ ์๋์ผ๋ก OwnerActor์ ์กด์ฌํ๋ AttributeSet์ ์ฐพ์์ ์ปดํฌ๋ํธ์ ๋ฑ๋กํ๋ฏ๋ก ๋ฐ๋ก ํ ๋นํ์ง ์์๋๋ผ๋ ๋ถ๋ฌ์ฌ ์ ์๋ค.GetAttributeSet()์ ์ธ์๋ TSubclassOf<UAttributeSet>์ด๋ฏ๋ก StaticClass()๋ฅผ ํตํด ๋๊ฒจ์ค๋ค.https://github.com/jongmin7759/Unreal_GAS/commit/799da6ebfcdfd0fc84d565ca6c900b71b9c132b7