Udemy Unreal - Gameplay Ability System - Top Down RPG (Section 6)

๊น€์ข…๋ฏผยท2025๋…„ 4์›” 16์ผ

Udemy Unreal - GAS

๋ชฉ๋ก ๋ณด๊ธฐ
6/7

๐Ÿ“– ์œ ๋ฐ๋ฏธ GAS ๊ฐ•์˜ ์ค‘ ๊ธฐ๋กํ•ด๋‘๊ณ  ์‹ถ์€ ๋‚ด์šฉ์„ ์ ์–ด๋‘” ํฌ์ŠคํŠธ

Section 6 : GameplayTags


GameplayTags

์ถ”๊ฐ€ํ•˜๊ธฐ

  1. ํ”„๋กœ์ ํŠธ ์„ธํŒ…์—์„œ ์ง์ ‘ ์ถ”๊ฐ€

  1. ๋ฐ์ดํ„ฐ ํ…Œ์ด๋ธ” ํ™œ์šฉํ•˜๊ธฐ

RowType : GameplayTagTableRow ๋กœ DT ๋งŒ๋“ค๊ณ 
ํ”„๋กœ์ ํŠธ ์„ธํŒ…์˜ ํ…Œ์ด๋ธ” ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•˜๊ธฐ

  1. .ini ํŒŒ์ผ์—์„œ ์ง์ ‘ ์ถ”๊ฐ€


GameplayEffect์™€ ๊ฒฐํ•ฉํ•˜๊ธฐ

Components์—์„œ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ

Tags This Effect Has (Asset Tags)

์ดํŽ™ํŠธ ์ž์ฒด๋ฅผ ์„ค๋ช…ํ•˜๋Š” ํƒœ๊ทธ ๊ฐœ๋…


Grant Tags To Target Actor

์ดํŽ™ํŠธ ํƒ€๊ฒŸ์—๊ฒŒ ํƒœ๊ทธ๋ฅผ ๋‹ฌ์•„์ค€๋‹ค.
์ดํŽ™ํŠธ ํšจ๊ณผ๊ฐ€ ๋๋‚˜๋ฉด ํ•ด๋‹น ํƒœ๊ทธ๋„ ํƒ€๊ฒŸ์—๊ฒŒ์„œ ์‚ฌ๋ผ์ง„๋‹ค.

  • ๋”ฐ๋ผ์„œ Instant Effect์—์„œ๋Š” ์˜๋ฏธ ์—†๋Š” ์ปดํฌ๋„ŒํŠธ (๋ฐ”๋กœ ์‚ฌ๋ผ์ง€๋‹ˆ๊นŒ)

์Šคํƒ ๊ฐœ๋…
ํƒœ๊ทธ๋„ ์ดํŽ™ํŠธ์ฒ˜๋Ÿผ ์Šคํƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
ํ•˜์ง€๋งŒ ์ดํŽ™ํŠธ์˜ ์Šคํƒ ์ƒํƒœ์— ๋”ฐ๋ผ ํƒœ๊ทธ์˜ ์Šคํƒ๋„ ๋‹ฌ๋ผ์ง„๋‹ค.

  • ์ดํŽ™ํŠธ๊ฐ€ ์Šคํƒ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ
    : ํƒœ๊ทธ๋Š” 1ํšŒ๋งŒ ์Šคํƒ๋œ๋‹ค.
    ex - ์Šคํƒ ๊ฐ€๋Šฅํ•œ ํšŒ๋ณต ์ดํŽ™ํŠธ๋ฅผ 4๋ฒˆ ๋ฐ›์•˜๋”๋ผ๋„ ํƒœ๊ทธ ์Šคํƒ์€ 1ํšŒ,
    ์Šคํƒ ๊ฐ€๋Šฅํ•œ 1๊ฐœ์˜ ์ดํŽ™ํŠธ ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณธ๋‹ค.

  • ์ดํŽ™ํŠธ๊ฐ€ ์Šคํƒ๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ
    : ํƒœ๊ทธ๊ฐ€ ๊ณ„์† ์Šคํƒ๋œ๋‹ค.
    ex - StackingType None ์ดํŽ™ํŠธ๋ฅผ 4๋ฒˆ ๋ฐ›์•˜์œผ๋ฉด ํƒœ๊ทธ ์Šคํƒ๋„ 4ํšŒ ์Œ“์ธ๋‹ค.


์ด์™ธ์—๋„ `Block Abilities with Tags`๋“ฑ ํƒœ๊ทธ์— ๊ด€๋ จ๋œ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์Œ.

GameplayEffect Delegate ํ™œ์šฉ

์ดํŽ™ํŠธ๊ฐ€ ์ ์šฉ๋  ๋•Œ ๋ถˆ๋Ÿฌ์˜ค๋Š” 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

  • ํƒœ๊ทธ๋ฅผ ๋‹ด๊ธฐ์— ์ตœ์ ํ™”๋œ ์ปจํ…Œ์ด๋„ˆ (TArray๋Œ€์‹  ์ด ์ปจํ…Œ์ด๋„ˆ ์‚ฌ์šฉ ๊ถŒ์žฅ)

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);
				}
			}
		}
	);

DataTable ์ •๋ณด๋กœ UI ๋ฉ”์‹œ์ง€ ๋„์šฐ๊ธฐ

DataTable

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)์—์„œ ๋ฉ”์‹œ์ง€ ์œ„์ ฏ ์ƒ์„ฑ ๋ฐ ํ‘œ์‹œ


Attribute ํด๋žจํ•‘

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()));
}

GhostGlobe

ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ”๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ค„์–ด๋“œ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ๊ฒŒ์ด์ง€๋ฅผ ๋ง๋Œ€๋Š” ํšจ๊ณผ.

๋ฐ˜ํˆฌ๋ช…ํ•œ ํ”„๋กœ๊ทธ๋ ˆ์Šค๋ฐ”๋ฅผ ํ•˜๋‚˜ ๋” ๋งŒ๋“ค๊ณ  ์›๋ž˜ ๊ฒŒ์ด์ง€๊ฐ€ ๋ณ€ํ™”ํ•  ๋•Œ ๋”œ๋ ˆ์ด๋ฅผ ์ฃผ๊ณ  ์ถ”๊ฐ€ ๊ฒŒ์ด์ง€๊ฐ€ ๋ณ€ํ™”ํ•˜๋„๋ก ์„ค์ •.

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

profile
์ •๋ฆฌ์™€ ๊ธฐ๋ก

0๊ฐœ์˜ ๋Œ“๊ธ€