Skip to content

UE5 C++ Gameplay Tags 가이드

Gameplay Tags는 UE5에서 제공하는 계층적 이름 기반 레이블 시스템입니다. FName 비교보다 안전하고, bool 플래그 배열보다 확장성이 뛰어납니다.

Character.State.Alive
Character.State.Dead
Character.Status.Stunned
Ability.Combat.Melee.Slash
Ability.Combat.Ranged.Arrow
비교 항목bool 플래그FNameGameplay Tags
계층 쿼리불가불가MatchesTag
에디터 드롭다운없음없음자동 생성
런타임 추가가능가능제한적
GAS 연동없음없음네이티브 지원

Config/DefaultGameplayTags.ini:

[/Script/GameplayTags.GameplayTagsSettings]
+GameplayTagList=(Tag="Character.State.Alive",DevComment="캐릭터 생존 상태")
+GameplayTagList=(Tag="Character.State.Dead",DevComment="캐릭터 사망 상태")
+GameplayTagList=(Tag="Character.Status.Stunned",DevComment="기절 상태")
+GameplayTagList=(Tag="Character.Status.Silenced",DevComment="침묵 상태")
+GameplayTagList=(Tag="Ability.Combat.Melee",DevComment="근접 공격 카테고리")
+GameplayTagList=(Tag="Ability.Combat.Melee.Slash",DevComment="베기 공격")
+GameplayTagList=(Tag="Ability.Combat.Ranged.Arrow",DevComment="화살 공격")
+GameplayTagList=(Tag="Effect.Damage.Fire",DevComment="화염 피해")
+GameplayTagList=(Tag="Effect.Damage.Ice",DevComment="냉기 피해")

1.2 C++에서 네이티브 태그 정의 (UE5.1+)

Section titled “1.2 C++에서 네이티브 태그 정의 (UE5.1+)”
// GameplayTags.h — 프로젝트 전역 태그 상수
#pragma once
#include "NativeGameplayTags.h"
namespace GameplayTags
{
// 상태 태그
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Character_State_Alive)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Character_State_Dead)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Character_Status_Stunned)
// 어빌리티 태그
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_Combat_Melee)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Ability_Combat_Melee_Slash)
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Effect_Damage_Fire)
}
GameplayTags.cpp
#include "GameplayTags.h"
namespace GameplayTags
{
UE_DEFINE_GAMEPLAY_TAG(TAG_Character_State_Alive, "Character.State.Alive")
UE_DEFINE_GAMEPLAY_TAG(TAG_Character_State_Dead, "Character.State.Dead")
UE_DEFINE_GAMEPLAY_TAG(TAG_Character_Status_Stunned, "Character.Status.Stunned")
UE_DEFINE_GAMEPLAY_TAG(TAG_Ability_Combat_Melee, "Ability.Combat.Melee")
UE_DEFINE_GAMEPLAY_TAG(TAG_Ability_Combat_Melee_Slash, "Ability.Combat.Melee.Slash")
UE_DEFINE_GAMEPLAY_TAG(TAG_Effect_Damage_Fire, "Effect.Damage.Fire")
}

#include "GameplayTagsManager.h"
#include "GameplayTags.h"
// 태그 조회 (문자열로)
FGameplayTag StunnedTag = FGameplayTag::RequestGameplayTag(TEXT("Character.Status.Stunned"));
// 네이티브 태그 사용 (컴파일 타임 안전)
FGameplayTag MeleeTag = GameplayTags::TAG_Ability_Combat_Melee;
// 유효성 확인
if (StunnedTag.IsValid())
{
UE_LOG(LogTemp, Log, TEXT("Tag: %s"), *StunnedTag.ToString());
}
// 계층 비교
FGameplayTag SlashTag = GameplayTags::TAG_Ability_Combat_Melee_Slash;
// MatchesTag: 자신이 다른 태그의 자식이면 true
// "Ability.Combat.Melee.Slash".MatchesTag("Ability.Combat.Melee") = true
bool bIsSubset = SlashTag.MatchesTag(MeleeTag); // true
// MatchesTagExact: 정확히 같은 태그일 때만 true
bool bExact = SlashTag.MatchesTagExact(MeleeTag); // false

3. FGameplayTagContainer — 태그 집합

Section titled “3. FGameplayTagContainer — 태그 집합”
FGameplayTagContainer StatusContainer;
// 태그 추가
StatusContainer.AddTag(GameplayTags::TAG_Character_State_Alive);
StatusContainer.AddTag(GameplayTags::TAG_Character_Status_Stunned);
// 포함 확인
bool bIsAlive = StatusContainer.HasTag(GameplayTags::TAG_Character_State_Alive);
// 계층 포함: "Character.Status.Stunned"를 가지면 "Character.Status"도 HasTag 반환
FGameplayTag CharStatusParent = FGameplayTag::RequestGameplayTag(TEXT("Character.Status"));
bool bHasAnyStatus = StatusContainer.HasTag(CharStatusParent); // true
// 정확한 태그만 확인
bool bExactMatch = StatusContainer.HasTagExact(CharStatusParent); // false
// 컨테이너 간 비교
FGameplayTagContainer RequiredTags;
RequiredTags.AddTag(GameplayTags::TAG_Character_State_Alive);
bool bHasAll = StatusContainer.HasAll(RequiredTags); // 전부 포함
bool bHasAny = StatusContainer.HasAny(RequiredTags); // 하나라도 포함
// 태그 제거
StatusContainer.RemoveTag(GameplayTags::TAG_Character_Status_Stunned);
// 순회
for (const FGameplayTag& Tag : StatusContainer)
{
UE_LOG(LogTemp, Log, TEXT("Status: %s"), *Tag.ToString());
}

UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// 단일 태그 (에디터 드롭다운 제공)
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTag CharacterRoleTag;
// 태그 컨테이너
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagContainer DefaultAbilityTags;
// 런타임 상태 태그
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Tags")
FGameplayTagContainer ActiveStatusTags;
// 태그 쿼리 (에디터에서 복잡한 조건 설정)
UPROPERTY(EditDefaultsOnly, Category = "Tags")
FGameplayTagQuery AbilityActivationQuery;
};

5. FGameplayTagQuery — 복잡한 조건 쿼리

Section titled “5. FGameplayTagQuery — 복잡한 조건 쿼리”
// C++에서 쿼리 빌드
FGameplayTagQuery Query = FGameplayTagQuery::BuildQuery(
FGameplayTagQueryExpression()
.AnyTagsMatch()
.AddTag(GameplayTags::TAG_Character_State_Alive)
.End()
);
FGameplayTagContainer TargetTags;
TargetTags.AddTag(GameplayTags::TAG_Character_State_Alive);
bool bMatches = Query.Matches(TargetTags); // true
// 더 복잡한 쿼리: (Alive AND NOT Stunned)
FGameplayTagQuery ComplexQuery = FGameplayTagQuery::BuildQuery(
FGameplayTagQueryExpression()
.AllTagsMatch()
.AddTag(GameplayTags::TAG_Character_State_Alive)
.End()
);

6. 실전 예시 — 상태 관리 컴포넌트

Section titled “6. 실전 예시 — 상태 관리 컴포넌트”
StatusComponent.h
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class MYGAME_API UStatusComponent : public UActorComponent
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Status")
void AddStatus(FGameplayTag StatusTag);
UFUNCTION(BlueprintCallable, Category = "Status")
void RemoveStatus(FGameplayTag StatusTag);
UFUNCTION(BlueprintPure, Category = "Status")
bool HasStatus(FGameplayTag StatusTag) const;
UFUNCTION(BlueprintPure, Category = "Status")
bool CanActivateAbility(const FGameplayTagContainer& AbilityTags) const;
private:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Status",
meta=(AllowPrivateAccess="true"))
FGameplayTagContainer ActiveStatuses;
// 어빌리티 차단 태그: 이 상태들이 있으면 어빌리티 사용 불가
UPROPERTY(EditDefaultsOnly, Category = "Status")
FGameplayTagContainer BlockAbilityTags;
};
StatusComponent.cpp
void UStatusComponent::AddStatus(FGameplayTag StatusTag)
{
if (StatusTag.IsValid())
{
ActiveStatuses.AddTag(StatusTag);
}
}
void UStatusComponent::RemoveStatus(FGameplayTag StatusTag)
{
ActiveStatuses.RemoveTag(StatusTag);
}
bool UStatusComponent::HasStatus(FGameplayTag StatusTag) const
{
return ActiveStatuses.HasTag(StatusTag);
}
bool UStatusComponent::CanActivateAbility(const FGameplayTagContainer& AbilityTags) const
{
// BlockAbilityTags 중 하나라도 ActiveStatuses에 있으면 사용 불가
return !ActiveStatuses.HasAny(BlockAbilityTags);
}
// 사용 예시
void AMyCharacter::OnStunned()
{
if (UStatusComponent* Status = FindComponentByClass<UStatusComponent>())
{
Status->AddStatus(GameplayTags::TAG_Character_Status_Stunned);
}
}
bool AMyCharacter::TryUseAbility(const FGameplayTagContainer& AbilityTags)
{
if (UStatusComponent* Status = FindComponentByClass<UStatusComponent>())
{
if (!Status->CanActivateAbility(AbilityTags))
{
UE_LOG(LogTemp, Warning, TEXT("Ability blocked by status"));
return false;
}
}
// 어빌리티 발동...
return true;
}

  • FGameplayTag::RequestGameplayTag(TEXT("...")) 대신 UE_DEFINE_GAMEPLAY_TAG로 네이티브 태그 선언 권장 (오타 방지, 컴파일 오류 조기 감지)
  • HasTag vs HasTagExact: 계층 포함 vs 정확 일치
  • MatchesTag: 자신이 다른 태그의 자식이면 true (계층 상속)
  • UPROPERTY로 선언 시 에디터에서 드롭다운으로 선택 가능
  • GAS와 함께 사용 시 UAbilitySystemComponent의 태그 관련 API와 자연스럽게 통합