概要
動作確認環境: UE 5.4+
「敵の種類や状態をBoolやEnumで管理しているが、条件分岐が増えすぎて破綻しかけている…」――プロジェクトが大きくなるにつれ、bIsStunned、bIsSwimming、bIsFlying のようなフラグが際限なく増えていく経験は多くの開発者に共通する悩みです。
UEの Gameplay Tags は、こうした状態管理を階層的なタグ構造に置き換えることで、柔軟かつ拡張性の高いゲームシステムを構築するための仕組みです。タグの追加・削除だけでゲームロジックを拡張でき、既存コードの修正が最小限で済むのが大きな利点です。
Gameplay Tagsとは
Gameplay Tagsは、.(ドット)区切りで階層構造を持つ文字列ラベルです。ゲーム内のオブジェクトに概念的なタグ付けを行い、そのタグに基づいてロジックを駆動します。
たとえば、以下のような概念をタグで表現できます。
- オブジェクトの属性:
Character.Enemy.Zombie— キャラクターが敵であり、ゾンビであることを示す - 状態や能力:
Movement.Mode.Swimming— キャラクターが泳いでいる状態 - イベント:
GameplayEvent.RequestReset— ゲームリセットの要求
Event.Movement.Dash というタグは3つの階層を持ちます。これにより、Event.Movement に属する全タグをまとめてチェックする部分マッチングが可能です。新しい移動方法を追加したいときは、Event.Movement.Teleport のようにタグを1つ追加するだけで、既存の Event.Movement を監視しているロジックが自動的にそのタグも認識します。Enumのように定義を変更して回る必要がありません。
タグの定義方法
Gameplay Tagsをプロジ ェクトで使うには、まずタグ辞書にタグを登録する必要があります。定義方法は3つあり、プロジェクトの規模やワークフローに応じて使い分けます。
1. プロジェクト設定で直接追加
最もシンプルな方法です。小規模プロジェクトやプロトタイプに適しています。
- プロジェクト設定 > GameplayTags > Import Tags From Config を有効化
- Manage Gameplay Tags ボタンで Gameplay Tag Manager を開く
- Add (+) をクリックし、Name・Comment・Sourceを入力して追加
タグは右クリックで名前変更・削除・サブタグ追加が可能です。大規模プロジェクトでは Config/Tags ディレクトリに機能別の .ini ファイルを分けると、チーム間での競合を避けやすくなります。
2. データテーブルからインポート
行タイプ GameplayTagTableRow のデータテーブルを作成し、プロジェクト設定の Gameplay Tag Table List に登録します。.csv / .json からのインポートにも対応しているため、外部ツールやスプレッドシートでタグを管理したい場合に便利です。エディタ実行中でもデータテーブルの変更が反映される点も利点です。
3. C++で定義する(ネイティブタグ)
C++でタグを定義すると、コンパイル時にタグの存在が保証され、タイポによるバグを防げます。NativeGameplayTags.h で提供されるマクロを使用します。
// MyTags.h
#pragma once
#include "NativeGameplayTags.h"
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Movement_Walking);
UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_Movement_Swimming);
// MyTags.cpp
#include "MyTags.h"
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Movement_Walking,
"Movement.Mode.Walking", "Default character movement");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_Movement_Swimming,
"Movement.Mode.Swimming", "Character is swimming");
必須:
Build.csのPublicDependencyModuleNamesに"GameplayTags"モジュールを追加してください。追加しないとリンカーエラーが発生します。
利用可能なマクロの一覧です。
| マクロ | 用途 |
|---|---|
UE_DECLARE_GAMEPLAY_TAG_EXTERN | .hファイルでタグを外部宣言 |
UE_DEFINE_GAMEPLAY_TAG | .cppファイルでコメントなし定義 |
UE_DEFINE_GAMEPLAY_TAG_COMMENT | .cppファイルでツールチップコメント付き定義 |
UE_DEFINE_GAMEPLAY_TAG_STATIC | ファイルローカルなタグを定義(DECLAREとペアにする必要なし) |
大規模プロジェクトでの実装例は Lyra Sample Game の LyraGameplayTags.h / .cpp が参考になります。タグをカテゴリ別にヘッダーファイルに整理するパターンが確認できます。
ランタイムでのタグ取得
ネイティブタグを定義せず、文字列からタグを動的に取得することも可能です。
FGameplayTag Tag = FGameplayTag::RequestGameplayTag(FName("Movement.Mode.Walking"));
データテーブルやコンフィグからタグ名を読み込むケースで便利ですが、文字列のタイポに対してコンパイル時のチェックが効かないため、頻繁にアクセスするタグはネイティブ定義を推奨します。
Tag ContainerとTag Query
Tag Container(FGameplayTagContainer)
ゲーム内のオブジェクトは通常、複数のタグを同時に持ちます。たとえばあるキャラクターが「敵」であり「ゾンビ」であり「毒状態」であるような場合です。FGameplayTagContainer は、こうした複数タグをまとめて管理するためのコンテナです。
// タグコンテナの基本操作
FGameplayTagContainer TagContainer;
// タグの追加・削除
TagContainer.AddTag(TAG_Movement_Walking);
TagContainer.RemoveTag(TAG_Movement_Walking);
// 条件チェック
bool bHas = TagContainer.HasTag(TAG_Movement_Walking); // 特定タグを持つか
bool bAny = TagContainer.HasAny(OtherContainer); // いずれかを持つか
bool bAll = TagContainer.HasAll(OtherContainer); // すべて持つか
HasTag は階層の親タグでもマッチします。たとえば Movement.Mode.Walking を持つコンテナに対して Movement.Mode で HasTag を呼ぶと true が返ります。これが部分マッチングの仕組みです。完全一致のみを判定したい場合は HasTagExact を使います。
| メソッド |
|---|