UE5 C++ Gameplay Tags 가이드
개요 — Gameplay Tags란
Section titled “개요 — Gameplay Tags란”Gameplay Tags는 UE5에서 제공하는 계층적 이름 기반 레이블 시스템입니다. FName 비교보다 안전하고, bool 플래그 배열보다 확장성이 뛰어납니다.
Character.State.AliveCharacter.State.DeadCharacter.Status.StunnedAbility.Combat.Melee.SlashAbility.Combat.Ranged.Arrow| 비교 항목 | bool 플래그 | FName | Gameplay Tags |
|---|---|---|---|
| 계층 쿼리 | 불가 | 불가 | MatchesTag |
| 에디터 드롭다운 | 없음 | 없음 | 자동 생성 |
| 런타임 추가 | 가능 | 가능 | 제한적 |
| GAS 연동 | 없음 | 없음 | 네이티브 지원 |
1. 태그 등록
Section titled “1. 태그 등록”1.1 ini 파일 등록 (권장)
Section titled “1.1 ini 파일 등록 (권장)”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)}#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")}2. FGameplayTag — 단일 태그
Section titled “2. FGameplayTag — 단일 태그”#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") = truebool bIsSubset = SlashTag.MatchesTag(MeleeTag); // true
// MatchesTagExact: 정확히 같은 태그일 때만 truebool bExact = SlashTag.MatchesTagExact(MeleeTag); // false3. 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());}4. UPROPERTY 선언
Section titled “4. UPROPERTY 선언”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. 실전 예시 — 상태 관리 컴포넌트”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;};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로 네이티브 태그 선언 권장 (오타 방지, 컴파일 오류 조기 감지)HasTagvsHasTagExact: 계층 포함 vs 정확 일치MatchesTag: 자신이 다른 태그의 자식이면 true (계층 상속)- UPROPERTY로 선언 시 에디터에서 드롭다운으로 선택 가능
- GAS와 함께 사용 시
UAbilitySystemComponent의 태그 관련 API와 자연스럽게 통합