๐ ์ ๋ฐ๋ฏธ GAS ๊ฐ์ ์ค ๊ธฐ๋กํด๋๊ณ ์ถ์ ๋ด์ฉ์ ์ ์ด๋ ํฌ์คํธ
Section 6 : GameplayTags
- ํ๋ก์ ํธ ์ธํ ์์ ์ง์ ์ถ๊ฐ

- ๋ฐ์ดํฐ ํ ์ด๋ธ ํ์ฉํ๊ธฐ
RowType : GameplayTagTableRow ๋ก DT ๋ง๋ค๊ณ
ํ๋ก์ ํธ ์ธํ
์ ํ
์ด๋ธ ๋ฆฌ์คํธ์ ์ถ๊ฐํ๊ธฐ

- .ini ํ์ผ์์ ์ง์ ์ถ๊ฐ


Components์์ ์ถ๊ฐ ๊ฐ๋ฅ
Tags This Effect Has (Asset Tags)
์ดํํธ ์์ฒด๋ฅผ ์ค๋ช ํ๋ ํ๊ทธ ๊ฐ๋
Grant Tags To Target Actor
์ดํํธ ํ๊ฒ์๊ฒ ํ๊ทธ๋ฅผ ๋ฌ์์ค๋ค.
์ดํํธ ํจ๊ณผ๊ฐ ๋๋๋ฉด ํด๋น ํ๊ทธ๋ ํ๊ฒ์๊ฒ์ ์ฌ๋ผ์ง๋ค.
์คํ ๊ฐ๋
ํ๊ทธ๋ ์ดํํธ์ฒ๋ผ ์คํ์ด ๊ฐ๋ฅํ๋ค.
ํ์ง๋ง ์ดํํธ์ ์คํ ์ํ์ ๋ฐ๋ผ ํ๊ทธ์ ์คํ๋ ๋ฌ๋ผ์ง๋ค.
์ดํํธ๊ฐ ์คํ ๊ฐ๋ฅํ ๊ฒฝ์ฐ
: ํ๊ทธ๋ 1ํ๋ง ์คํ๋๋ค.
ex - ์คํ ๊ฐ๋ฅํ ํ๋ณต ์ดํํธ๋ฅผ 4๋ฒ ๋ฐ์๋๋ผ๋ ํ๊ทธ ์คํ์ 1ํ,
์คํ ๊ฐ๋ฅํ 1๊ฐ์ ์ดํํธ ํ๊ทธ๋ฅผ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ๋ณธ๋ค.
์ดํํธ๊ฐ ์คํ๋์ง ์๋ ๊ฒฝ์ฐ
: ํ๊ทธ๊ฐ ๊ณ์ ์คํ๋๋ค.
ex - StackingType None ์ดํํธ๋ฅผ 4๋ฒ ๋ฐ์์ผ๋ฉด ํ๊ทธ ์คํ๋ 4ํ ์์ธ๋ค.
์ดํํธ๊ฐ ์ ์ฉ๋ ๋ ๋ถ๋ฌ์ค๋ OnGameplayEffectAppliedDelegateToSelf ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ํตํด EffectSpec์ ์ ๊ทผํ๊ณ GetAll~Tags()๋ฅผ ํตํด ํด๋น ์ดํํธ์ ๊ฒฐํฉ๋ ํ๊ทธ ์ ๋ณด๋ฅผ ๋ฐ์์ฌ ์ ์๋ค.
์์ ์ ๊ฒฝ์ฐ MVC๋ฅผ ๊ตฌ์กฐ๋ฅผ ์ ์งํ๊ธฐ์ํด ASC์์ ํจ์ ๋ฐ์ธ๋ฉ ๋ฐ ๋ธ๋ก๋์บ์คํ ์ฒ๋ฆฌ
void UAuraAbilitySystemComponent::AbilityActorInfoSet()
{
// ๋ธ๋ฆฌ๊ฒ์ดํธ ๋ฐ์ธ๋ฉ
OnGameplayEffectAppliedDelegateToSelf.AddUObject(this,&UAuraAbilitySystemComponent::EffectApplied);
}
void UAuraAbilitySystemComponent::EffectApplied(UAbilitySystemComponent* AbilitySystemComponent,
const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveEffectHandle)
{
FGameplayTagContainer TagContainer;
EffectSpec.GetAllAssetTags(TagContainer);
// ์ปจํธ๋กค๋ฌ์์ ๋ฐ์ธ๋ฉํ ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ๋ธ๋ก๋์บ์คํธ
EffectAssetTags.Broadcast(TagContainer);
}
FGameplayTagContainer
EffectAssetTags ๋ธ๋ฆฌ๊ฒ์ดํธ
// BP์์ ๋ฐ์ธ๋ฉํ์ง ์๊ณ WidgetController์ ๋ฐ์ธ๋ฉํ ๊ฒ์ด๋ฏ๋ก Dynamic X
DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTags, const FGameplayTagContainer& /*AssetTags*/);
WidgetController์์ ๋๋ค ํจ์ ๋ฐ์ธ๋ฉ
// Effect Delegate ๋ฐ์ธ๋ฉ
Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent)->EffectAssetTags.AddLambda( // ๋๋ค ํจ์ [capture](param){body}
[this](const FGameplayTagContainer& AssetTags)
{
for (FGameplayTag Tag : AssetTags)
{
// ํ๊ทธ๊ฐ ๋ฉ์์ง์ธ ๊ฒฝ์ฐ์๋ง ๋ฉ์์ง ๋ธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ์ฌ์ฉํ๋๋ก ํํฐ๋ง
FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag("Message");
if (Tag.MatchesTag(MessageTag))
{
// [] ์์ this ๋ฉค๋ฒ ๋ฃ์ด์ฃผ์ง ์์ผ๋ฉด ๋๋ค ํจ์ ๋ด์์๋ ์ ๋ณด๊ฐ ์์ด์ ๋ฉค๋ฒ ํจ์ ํธ์ถ์ ๋ชปํจ.
// []๋ฅผ ํตํด ์ธ๋ถ ๋ณ์๋ฅผ ์บก์ณํด์ ์ฌ์ฉํ๋ค.
const FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable,Tag);
MessageWidgetRowDelegate.Broadcast(*Row);
}
}
}
);
FUIWidgetRow๋ฅผ RowType์ผ๋ก ์ฌ์ฉํ๋ DataTable์ ๋ง๋ค๊ณ ์์ง์์ ๊ฐ์ ๋ฃ์ด์ค๋ค.
// DataTable์ ์ฌ์ฉํ ๊ตฌ์กฐ์ฒด (TableRowBase ์์)
USTRUCT(BlueprintType)
struct FUIWidgetRow : public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayTag MessageTag = FGameplayTag();
UPROPERTY(EditAnywhere, BlueprintReadOnly)
FText MessageText = FText();
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TSubclassOf<UAuraUserWidget> MessageWidget;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UTexture2D* Image = nullptr;
};
์ปจํธ๋กค๋ฌ ํค๋์ ๋ฉค๋ฒ์ ๋ฉ์๋ ์ถ๊ฐ
{
...
// ์ปจํธ๋กค๋ฌ๋ฅผ ํตํด DT์ ์๋ ์ ๋ณด ์ ๊ทผํ ์ ์๋๋ก ๋ณ์ ์ถ๊ฐ
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Widget Data")
TObjectPtr<UDataTable> MessageWidgetDataTable;
...
// ํ๊ทธ๋ก ์์์ ํ
์ด๋ธ ๋ก์ฐ ๋ฐํํ๋๋ก ํ
ํ๋ฆฟ ํจ์ ๋ง๋ค๊ธฐ
template<typename T>
T* GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag);
}
template <typename T>
T* UOverlayWidgetController::GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag)
{
// ํ ์ด๋ฆ์ ํ๊ทธ ์ด๋ฆ๊ณผ ์ผ์นํ๊ฒ ๋ง๋ค์๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ์ฐพ์ ์ ์์
return DataTable->FindRow<T>(Tag.GetTagName(),TEXT("")/*๋ฏธ์ฌ์ฉ*/);
}
MessageWidgetDataTable์ ์์ง์์ ์ถ๊ฐ

๋๋ค ํจ์๊ฐ ํธ์ถ๋๋ฉด
const FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable,Tag);
MessageWidgetRowDelegate.Broadcast(*Row);
๋ฐ์ธ๋ฉํ๋ OverlayWidget(View)์์ ๋ฉ์์ง ์์ ฏ ์์ฑ ๋ฐ ํ์

PreAttributeChange()
CurrentValue์๋ง ์ํฅ์ ์ค๋ค.
BaseValue๊น์ง ๋ฐ๊พธ๋ ค๋ฉด PostGameplayEffectExecute()์์ ํ์คํ Set์ผ๋ก ํด๋จํํ๊ธฐ
PreAttributeChange์์๋ง ํด๋จํํ ๊ฒฝ์ฐ ์๊ธธ ์ ์๋ ์ค๋ฅ
(๊ฒ์ผ๋ก ๋ณด๊ธฐ์ MaxHealth์ธ 100์ ๋์ง ์์์ง๋ง BaseValue๋ ์ด๋ฏธ ์ด๊ณผ๋์ด์์ด ๋ค๋ฅธ ์ฐ์ฐ์ ํ ๋ ์ค๋ฅ๊ฐ ์๊น)

PostGameplayEffectExecute()
PreAttributeChange()์์๋ ๋ชจ๋ํ์ด์ด ์ ์ฉ ์ ์ ํธ์ถ๋๋ ๊ฐ๋ง ๋ณ๊ฒฝ๋๋ฏ๋ก
BaseValue ํด๋จํ์ด ์ ๋๋ก ๋์ด์์ง ์๊ธฐ๋๋ฌธ์ ๊ฒ์ํ๋ ์ด ์ดํํธ ์ ์ฉ ์ดํ ๋ค์ ๊ฐ์ ํด๋จํํด์ค ํ์๊ฐ ์๋ค.
๋์ค์ BaseValue ์ฐ์ฐํ ๋ ๊ฒ์ผ๋ก ๋ณด๊ธฐ์๋ง ์ต๋๊ฐ ์ ์ง ์ค์ด๊ณ
์ค์ Value๊ฐ ๊ทธ ์ด์์ด๋ผ๋ฉด ์ค์ Value๋ถํฐ ๊ฐ์ ๊น๊ธฐ๋๋ฌธ์ ์ดํํธ ์ ์ฉ์ด ์ ๋๋ก ๋์ง ์๊ณ ์๋ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์๋ค.
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(),0.f,GetMaxHealth()));
}
if (Data.EvaluatedData.Attribute == GetManaAttribute())
{
SetMana(FMath::Clamp(GetMana(),0.f,GetMaxMana()));
}

ํ๋ก๊ทธ๋ ์ค๋ฐ๊ฐ ์์ฐ์ค๋ฝ๊ฒ ์ค์ด๋๋ ๊ฒ์ฒ๋ผ ๋ณด์ด๊ธฐ ์ํด ์ถ๊ฐ ๊ฒ์ด์ง๋ฅผ ๋ง๋๋ ํจ๊ณผ.
๋ฐํฌ๋ช ํ ํ๋ก๊ทธ๋ ์ค๋ฐ๋ฅผ ํ๋ ๋ ๋ง๋ค๊ณ ์๋ ๊ฒ์ด์ง๊ฐ ๋ณํํ ๋ ๋๋ ์ด๋ฅผ ์ฃผ๊ณ ์ถ๊ฐ ๊ฒ์ด์ง๊ฐ ๋ณํํ๋๋ก ์ค์ .
Tick๊ณผ Interpolation, TargetPercent ํ์ฉ

GhostGlobeSet์์๋ Delay ์ดํ GhostPercentTarget์ด Set๋๋๋ก ํ๊ณ ์์
GhostGlobe ์ด๊ธฐํ๋ฅผ ์ํด GhostInitialized ๋ณ์๋ก ๋ถ๊ธฐ ๋๋๊ธฐ
(์ด๊ธฐํ๋ฅผ ๋ฐ๋ก ์ ํด์ฃผ๋ฉด GhostGlobe๊ฐ ProgressBar์ ๋ค๋ฅธ ์ํ๋ก ์์ํ๊ณ ๋ณด๊ฐํ๋ ๋ชจ์ต์ด ๋ณด์ฌ์ง๊ฒ๋จ)

https://github.com/jongmin7759/Unreal_GAS/commit/fde64d9d202e1d45ba24b8c6085e4e4ff7846719
https://github.com/jongmin7759/Unreal_GAS/commit/3d539fa0da30163b2c3e22e5ba2760811dd325b9