ue-gameplay-tags-messaging について
UE 5.8 の Gameplay Tags と疎結合なゲームメッセージングを扱う開発スキルです。タグの登録、照合、クエリ、エディターでの絞り込み、メッセージ設計を案内します。
主な機能
- 01ネイティブタグと設定ファイルでの定義
- 02タグコンテナの照合と階層セマンティクス
- 03タグクエリの構築と評価
- 04エディターのタグ絞り込み設定
- 05疎結合なゲームメッセージング設計
活用シーン
- 01C++ モジュールでネイティブタグを登録
- 02タグ階層に基づいてゲーム状態を確認
- 03複数タグ条件をデザイナー向けに設定
- 04システム間のハード参照なしでメッセージを送信
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ quodsoler/ unreal-engine-skills --skill ue-gameplay-tags-messagingインストール後、Claude Code で/ue-gameplay-tags-messagingを入力して読み込まれたか確認します。
同梱ファイルreferences/gameplay-messaging.mdreferences/gameplay-tag-reference.md
詳細
UE Gameplay Tags and Messaging
対象エンジン:UE 5.8。以下の API は 5.8 のヘッダーに基づいて検証済みです。古い形式は「非推奨 — 使用しないでください」に記載しています。
Gameplay Tags はプラグインではなく、組み込みのランタイムモジュールです。Build.cs の PublicDependencyModuleNames に "GameplayTags" を追加し、GameplayTagContainer.h/NativeGameplayTags.h/GameplayTagsManager.h をインクルードしてください。このスキルでは、タグ定義(ネイティブおよび ini)、FGameplayTag、FGameplayTagContainer、FGameplayTagQuery、UGameplayTagsManager、エディターでのフィルタリング、疎結合なゲームプレイメッセージングを扱います。これには、(5.8 では実験的な)AsyncMessageSystem プラグインも含まれます。
コンテキスト
.agents/ue-project-context.md が存在する場合は読み込んでください(モジュール名、規約、有効なプラグイン、GAS/ネットワーク設定)。ファイルがなくても作業を中断しないでください。
リクエストとコードベースから対象分野を特定してください。考えられる解釈によって異なるコードになる場合に限り、質問してください。
| リクエストの内容… | 参照先 |
|---|---|
| C++ でのタグ宣言、ネイティブタグマクロ、モジュール設定 | ネイティブタグの定義 |
.ini での宣言、データテーブル、タグの名前変更 | Ini およびデータテーブルのタグソース |
| タグのテスト、コンテナのメンバーシップ、親タグとの一致と完全一致 | 一致のセマンティクス |
| 複数タグの条件、AND/OR/NOT、デザイナーが作成するルール | タグクエリ |
| タグを公開するアクター、タグで構成するゲートや状態 | タグ駆動設計 |
| ネットワーク経由でのタグ送信、タグのコスト、ホットパス | レプリケーションとパフォーマンス |
| ハード参照を使わないシステム間のイベント配信 | 疎結合なメッセージング |
タグピッカー、Categories フィルタリング、チームごとのタグファイル | エディター UX とフィルタリング |
タグソース
タグはリクエストする前に登録する必要があります。UGameplayTagsManager が保持する単一のグローバル辞書には、次の 4 つのソースからタグが登録されます。
| ソース | 場所 | 用途 |
|---|---|---|
| ネイティブ | モジュールの .cpp にある UE_DEFINE_GAMEPLAY_TAG* | C++ で名前による比較に使うタグ |
| デフォルト ini | Config/DefaultGameplayTags.ini の +GameplayTagList= | デザイナーが作成するタグ |
| 追加 ini | Config/Tags/*.ini およびプラグインの設定ディレクトリ | チームごと、またはプラグインごとのタグリスト |
| データテーブル | GameplayTagTableList に指定された FGameplayTagTableRow の UDataTable | スプレッドシートからの一括インポート |
エディターでは、これらのソースを EGameplayTagSourceType(Native、DefaultTagList、TagList、RestrictedTagList、DataTable、Invalid)で表します。タグは階層構造になっています。MyGame.State.Stunned を登録すると、MyGame.State と MyGame も暗黙的に登録されます。
ネイティブタグの定義
パブリックヘッダーで宣言し、同じモジュールの .cpp 1つだけで定義します。マクロは、.cpp から使用されていることを static_assert で確認します。
// MyGameplayTags.h
#pragma once
#include "NativeGameplayTags.h"
MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_State_Stunned);
MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_Damage_Fire);
MYGAME_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(TAG_MyGame_Message_ScoreChanged);
// MyGameplayTags.cpp
#include "MyGameplayTags.h"
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_State_Stunned, "MyGame.State.Stunned", "Character cannot act");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_Damage_Fire, "MyGame.Damage.Fire", "Fire damage channel");
UE_DEFINE_GAMEPLAY_TAG_COMMENT(TAG_MyGame_Message_ScoreChanged, "MyGame.Message.ScoreChanged", "Score changed broadcast");
| マクロ | パラメーター | 効果 |
|---|---|---|
UE_DECLARE_GAMEPLAY_TAG_EXTERN | (TagName) | extern FNativeGameplayTag TagName; — ヘッダーに記述し、_API マクロを前置します |
UE_DEFINE_GAMEPLAY_TAG | (TagName, Tag) | 空の開発者コメントを付けて変数を定義します |
UE_DEFINE_GAMEPLAY_TAG_COMMENT | (TagName, Tag, Comment) | 同じ定義に、エディターに表示される開発者コメントを追加します |
UE_DEFINE_GAMEPLAY_TAG_STATIC | (TagName, Tag) | static — 対応するヘッダー宣言はなく、その .cpp 1つの中だけで参照できます |
Tag と Comment は引用符で囲まれた文字列リテラルです。マクロが Comment を TEXT() で囲むため、ここに TEXT("…") と書くとコンパイルできません。
FNativeGameplayTag は静的構築時に登録され、モジュールのアンロード時に登録解除されるため、プラグインのタグはプラグインとともに適切に削除されます。暗黙的に FGameplayTag に変換でき、GetTag() も公開しています。
const FGameplayTag Stunned = TAG_MyGame_State_Stunned.GetTag();
if (OwnedTags.HasTag(TAG_MyGame_State_Stunned))
{
return;
}
One Definition Rule: バイナリごとに、各タグ変数に対して UE_DEFINE_GAMEPLAY_TAG(または _COMMENT / _STATIC)をちょうど1つ定義してください。同じタグ文字列を2つのモジュールで定義しても問題ありません(マネージャーが登録を参照カウントします)。ただし、同じ 変数 を2回定義するとリンクエラーになり、ヘッダーで定義すると、それをインクルードするすべての翻訳単位で問題が発生します。
名前が実行時までわからないタグを登録するには、マネージャーを直接呼び出します。
const FGameplayTag Runtime = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName(TEXT("MyGame.Generated.Slot01")), TEXT("Generated at startup"));
起動後に AddNativeGameplayTag を呼び出すと、高速レプリケーションが無効になります(レプリケーションとパフォーマンスを参照)。CallOrRegister_OnAddNativeTagsDelegate から登録し、タグを 使用する コードは CallOrRegister_OnDoneAddingNativeTagsDelegate から実行します。
// MyGameModule.cpp — FDelegateHandle NativeTagsHandle; is a member of FMyGameModule.
#include "MyGameModule.h"
#include "GameplayTagsManager.h"
void FMyGameModule::StartupModule()
{
NativeTagsHandle = UGameplayTagsManager::CallOrRegister_OnDoneAddingNativeTagsDelegate(
FSimpleMulticastDelegate::FDelegate::CreateRaw(this, &FMyGameModule::OnTagsReady));
}
void FMyGameModule::ShutdownModule()
{
UGameplayTagsManager::UnregisterNativeTagDelegate(NativeTagsHandle);
}
登録がすでに完了している場合、CallOrRegister_OnDoneAddingNativeTagsDelegate はデリゲートをただちに実行し、CallOrRegister_OnAddNativeTagsDelegate は現在のモジュールのロード終了時に実行します(GameplayTagsManager.h:419-427)。そのため、後から呼び出しても順序に関する問題はありません。
Ini とデータテーブルのタグソース
UGameplayTagsSettings は UGameplayTagsList を継承する UCLASS(config=GameplayTags, defaultconfig) であるため、プロジェクト設定 → Gameplay Tags によって Config/DefaultGameplayTags.ini が書き込まれます。
[/Script/GameplayTags.GameplayTagsSettings]
ImportTagsFromConfig=True
FastReplication=False
NumBitsForContainerSize=6
NetIndexFirstBitSegment=16
+GameplayTagList=(Tag="MyGame.State.Stunned",DevComment="Character cannot act")
+GameplayTagList=(Tag="MyGame.Damage.Fire",DevComment="Fire damage channel")
+GameplayTagTableList=/Game/Data/DT_MyGameTags.DT_MyGameTags
+GameplayTagRedirects=(OldTagName="MyGame.State.Stun",NewTagName="MyGame.State.Stunned")
| キー | 型 | 意味 |
|---|---|---|
ImportTagsFromConfig | bool | ini で定義したタグのマスタースイッチ。UGameplayTagsManager::ShouldImportTagsFromINI() で読み取れます |
GameplayTagList | TArray<FGameplayTagTableRow> | Tag(FName)と DevComment(FString) |
GameplayTagTableList | TArray<FSoftObjectPath> | LoadGameplayTagTables によって読み込まれる FGameplayTagTableRow のデータテーブル |
GameplayTagRedirects | TArray<FGameplayTagRedirect> | OldTagName → NewTagName。UGameplayTagsList から継承されます |
CategoryRemapping | TArray<FGameplayTagCategoryRemap> | エンジンの Categories フィルターをプロジェクトのカテゴリに再マッピングします |
RestrictedConfigFiles | TArray<FRestrictedConfigInfo> | 名前付きの所有者だけが編集できるトップレベルタグ |
InvalidTagCharacters | FString | 改行などに加え、タグ名で使用できない文字 |
追加の ini ソースは Config/Tags/(自動的に追加されます)と、UGameplayTagsManager::Get().AddTagIniSearchPath(RootDir) に渡す任意のディレクトリに配置します。RemoveTagIniSearchPath を呼び出すと、それらを削除できます。Game Feature プラグインの設定ディレクトリもこの方法で登録されるため、そのタグはプラグインが有効な間だけ表示されます。
タグ名を変更する場合はリダイレクトが必要です。 FGameplayTagRedirect は { OldTagName, NewTagName } です。シリアライズには FGameplayTagRedirectors::Get().RedirectTag(OldName, OutTag) が使用されます(エンジン内部のクラスであり、エクスポートされていません)。リダイレクトがないと、古い名前を参照していたすべてのアセットで、無効なタグがエラーを出さずに読み込まれます。
ini とデータテーブルの詳細については、gameplay-tag-reference.md を参照してください。
マッチングのセマンティクス
FGameplayTag は 1 つの FName です。コンテナーには明示的に追加されたタグと、一時的に展開された親タグのリストが保持されるため、親タグを考慮したチェックは文字列解析ではなく、配列の検索になります。
| 呼び出し | レシーバー | セマンティクス | {"A.1"} と A の比較 |
|---|---|---|---|
MatchesTag(TagToCheck) | FGameplayTag | このタグまたは任意の親タグが TagToCheck と等しい | A.1.MatchesTag(A) → true;A.MatchesTag(A.1) → false |
MatchesTagExact(TagToCheck) | FGameplayTag | 名前が等しい | A.1.MatchesTagExact(A) → false |
MatchesAny(ContainerToCheck) | FGameplayTag | 親タグを展開したうえで、コンテナー内のいずれかのタグと一致する | A.1.MatchesAny({A,B}) → true |
MatchesAnyExact(ContainerToCheck) | FGameplayTag | コンテナーがこのタグを明示的に保持している | A.1.MatchesAnyExact({A,B}) → false |
HasTag(TagToCheck) | FGameplayTagContainer | 明示的なリストまたは親タグのリストに含まれる | {A.1}.HasTag(A) → true |
HasTagExact(TagToCheck) | FGameplayTagContainer | 明示的なリストのみを対象とする | {A.1}.HasTagExact(A) → false |
HasAny / HasAnyExact | FGameplayTagContainer | 1 つ以上含まれる;引数が空の場合は false | {A.1}.HasAny({A,B}) → true |
HasAll / HasAllExact | FGameplayTagContainer | すべて含まれる;引数が空の場合は true | {A.1,B.1}.HasAll({A,B}) → true |
Filter(OtherContainer) | FGameplayTagContainer | OtherContainer 内の任意のタグと一致するタグを含む新しいコンテナー。親タグも展開されます | {A.1,C}.Filter({A}) → {A.1} |
FilterExact(OtherContainer) | FGameplayTagContainer | 正確な名前による積集合 | {A.1,C}.FilterExact({A}) → {} |
空の引数に対する非対称な動作は意図的なものです。「何もないもののいずれか」は false、「何もないもののすべて」は true です。RequiredTags.IsEmpty() || Owned.HasAll(RequiredTags) のように書かれたゲートは冗長です。
FGameplayTagContainer MakeStateTags(const FGameplayTagContainer& ExtraTags)
{
FGameplayTagContainer Owned;
Owned.AddTag(TAG_MyGame_State_Stunned); // checks uniqueness and refills parents
Owned.AddTagFast(TAG_MyGame_Damage_Fire); // no uniqueness check — only when the tag is known to be new
Owned.AppendTags(ExtraTags);
Owned.RemoveTag(TAG_MyGame_State_Stunned);
if (!Owned.IsEmpty())
{
UE_LOG(LogMyGame, Log, TEXT("%d tags, first %s, last %s: %s"),
Owned.Num(), *Owned.First().ToString(), *Owned.Last().ToString(), *Owned.ToStringSimple());
}
return Owned;
}
親タグの取得:FGameplayTag::RequestDirectParent() は x.y に対して x を返し、FGameplayTag::GetGameplayTagParents() はタグとすべての親タグを含むコンテナーを返します。FGameplayTagContainer::GetGameplayTagParents() はコンテナー全体に対して同じ処理を行います。ParseParentTags(TArray<FGameplayTag>&) はマネージャーに触れることなく処理します。
AddTagFast は Contains のチェックを省略しますが、親タグは引き続き設定します。すでに一意であるとわかっているデータからコンテナーを構築する場合に使用し、ユーザー入力に対して AddTag の代わりに使用しないでください。
タグクエリ
FGameplayTagQuery はコンパイル済みのトークンストリームです。評価は低コストですが、構築にはコストがかかります。一度構築して保存し、繰り返し評価してください。
// MyBurnRule.cpp
#include "GameplayTagContainer.h"
#include "MyGameplayTags.h"
bool ShouldBurn(const FGameplayTagContainer& OwnedTags)
{
FGameplayTagContainer Elements;
Elements.AddTag(TAG_MyGame_Damage_Fire);
// (any element tag) AND NOT Stunned
FGameplayTagQuery ComplexQuery = FGameplayTagQuery::BuildQuery(
FGameplayTagQueryExpression()
.AllExprMatch()
.AddExpr(FGameplayTagQueryExpression().AnyTagsMatch().AddTags(Elements))
.AddExpr(FGameplayTagQueryExpression().NoTagsMatch().AddTag(TAG_MyGame_State_Stunned)));
return ComplexQuery.Matches(OwnedTags);
}
ショートカット形式を使うと、式ツリーを使わずに一般的なケースに対応できます。
FGameplayTagContainer Blocking;
Blocking.AddTag(TAG_MyGame_State_Stunned);
const FGameplayTagQuery BlockedQuery = FGameplayTagQuery::MakeQuery_MatchAnyTags(Blocking);
FGameplayTagQuery のショートカット:MakeQuery_MatchAnyTags、MakeQuery_MatchAllTags、MakeQuery_MatchNoTags、MakeQuery_ExactMatchAnyTags、MakeQuery_ExactMatchAllTags、MakeQuery_MatchTag。FGameplayTagQueryExpression の式動詞:AnyTagsMatch、AllTagsMatch、NoTagsMatch、AnyTagsExactMatch、AllTagsExactMatch、AnyExprMatch、AllExprMatch、NoExprMatch。AddTag、AddTags、AddExpr を使って値を渡します。
どちら側からでも評価できます。Query.Matches(Container) または Container.MatchesQuery(Query) を使用してください。どちらも同じ評価処理を呼び出します。
クエリを UPROPERTY として公開すると、デザイナーは追加作業なしでクエリエディターを使用できます。
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Gating")
FGameplayTagQuery ActivationQuery;
ReplaceTagsFast(Tags) と ReplaceTagFast(Tag) は、トークンストリームを再構築せずに、キャッシュ済みクエリのタグ辞書を入れ替えます。新しいコンテナーは同じサイズである必要があります。
タグ駆動設計
タグを所有するものは、無関係なシステムからキャストせずに問い合わせられるよう、IGameplayTagAssetInterface を通じてタグを公開する必要があります。
// MyTaggedActor.h
#pragma once
#include "GameFramework/Actor.h"
#include "GameplayTagAssetInterface.h"
#include "GameplayTagContainer.h"
#include "MyTaggedActor.generated.h"
UCLASS()
class MYGAME_API AMyTaggedActor : public AActor, public IGameplayTagAssetInterface
{
GENERATED_BODY()
public:
virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override;
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Tags", meta = (Categories = "MyGame.State"))
FGameplayTagContainer OwnedTags;
};
// MyTaggedActor.cpp
#include "MyTaggedActor.h"
void AMyTaggedActor::GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const
{
TagContainer.AppendTags(OwnedTags);
}
HasMatchingGameplayTag、HasAllMatchingGameplayTags、HasAnyMatchingGameplayTags は、インターフェースからそのまま利用できます。これらは GetOwnedGameplayTags を呼び出します。Blueprint では、同等の機能として UBlueprintGameplayTagLibrary::DoesTagAssetInterfaceHaveTag、HasAnyMatchingGameplayTags、GetOwnedGameplayTags を使用します。
カウント付きタグ: FGameplayTagContainer はセットなので、2 つのソースが Stunned を付与し、1 つが削除すると、タグはなくなります。複数のソースが同じタグを付与する可能性がある場合は、FGameplayTagCountContainer(GameplayEffectTypes.h:1102、GameplayAbilities プラグイン内)を使用してください。これは ASC が所有タグに使用するものです。UpdateTagCount(Tag, +1/-1, EGameplayTagReplicationState::None) でカウントを調整できます(単一タグ用のオーバーロードでは 3 番目の引数にデフォルト値がありません。UpdateTagCount(Container, Delta) は引数を 2 つ取ります)。GetTagCount(Tag) は子タグを含みます(A.B と A.C を追加すると、GetTagCount(A) == 2 になります)。GetExplicitTagCount は子タグを含みません。GetExplicitGameplayTags() は GetOwnedGameplayTags に渡す現在のセットを返します。RegisterGameplayTagEvent(Tag, EGameplayTagEventType::NewOrRemoved | AnyCountChange) は、バインド可能な FOnGameplayEffectTagCountChanged(void(const FGameplayTag, int32 NewCount))を返します。プロジェクトで GAS を使用している場合は、独自に所有する代わりに ASC のルーズタグを使用してください。
有効な設計ルール:
- タグはオブジェクトではなく、状態とカテゴリに名前を付けます。
MyGame.State.StunnedやMyGame.Damage.Fireは適切ですが、MyGame.Actor.Goblin03はタグを付けたクラス参照です。 - 階層の深さはクエリです。
HasTag(MyGame.Damage)が意味のある問い合わせになる程度に、階層を浅く保ちます。 - 分岐ではなく、判定条件を定義します。
if (Tag == SpecificTag)の連鎖ではなく、FGameplayTagContainerまたはFGameplayTagQueryプロパティを公開し、データに判断させます。 - ゲームプレイ用の型にタグを
FNameやFStringとして保存しないでください。FGameplayTagを保存します。検証、リダイレクト、レプリケーションに対応しています。
レプリケーションとパフォーマンス
FGameplayTag は単一の FName です。自由にコピーし、値渡しできます。コストが発生するのは、登録とシリアライズです。
| 項目 | ルール |
|---|---|
| 検索 | RequestGameplayTag は呼び出すたびにマップを検索します。ネイティブタグまたはメンバーに一度だけ解決し、ティックごとやヒットごとに解決しないでください |
| コンテナの構築 | AddTag は呼び出すたびに親配列を再構築します。AddTagFast は一意性のチェックを省略します。FGameplayTagContainer::CreateFromArray は配列全体の親を一度に構築します |
| ワイヤーフォーマット | FGameplayTag::NetSerialize と FGameplayTagContainer::NetSerialize は TStructOpsTypeTraits を通じて登録されます。レプリケートされるタグプロパティでは、すでにこれらが使用されています |
FastReplication=True | 名前の代わりにネットインデックスでタグをレプリケートします。クライアントとサーバーの辞書が同一である必要があるため、片側だけでプラグインがタグを追加すると動作しなくなります |
bDynamicReplication=True | 接続ごとにインデックスを割り当てます。FastReplication よりわずかにコストが高くなりますが、辞書が異なっていても対応できます。FastReplication が有効な場合は無視されます |
NetIndexFirstBitSegment | 最初のインデックスセグメントで使用するビット数です。CommonlyReplicatedTags に記載したタグには小さいインデックスが割り当てられ、1 つのセグメントに収まります |
NumBitsForContainerSize | レプリケートされるコンテナの要素数に使用するビット数です。実際のコンテナサイズに合わせて設定します |
UGameplayTagsManager::Get().DoneAddingNativeTags() はネイティブタグの登録を確定します。この呼び出し後はネットインデックスのテーブルがすでに構築され、ハッシュ化されているため(GetNetworkGameplayTagNodeIndexHash)、ファストレプリケーションを使用している場合、それ以上タグを追加するのは安全ではありません。
これらのコンテナを格納するプロパティのワイヤーコストと、プッシュモデルレプリケーションについては、ue-networking-replication を参照してください。
分離型メッセージング
要件に合う最も軽量な仕組みを選んでください。
| 必要なもの | 使用するもの |
|---|---|
| 1つのゲーム内にある少数の既知のリスナー | UGameInstanceSubsystem または UWorldSubsystem 上の動的マルチキャストデリゲート |
| タグでアドレス指定される、階層型、スレッド間対応、型付きペイロード | AsyncMessageSystem プラグイン(5.8 では Experimental) |
| アビリティのアクティベーションと GAS 側のイベント | SendGameplayEventToActor / RegisterGameplayTagEvent。ue-gameplay-abilities が所有します |
サブシステム上の動的マルチキャストデリゲートで十分なことが多く、追加コストもかかりません。
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FMyScoreChanged, AActor*, Scorer, int32, NewScore);
UPROPERTY(BlueprintAssignable, Category = "Score")
FMyScoreChanged OnScoreChanged;
リスナーをタグ階層でアドレス指定する必要がある場合や、ゲームスレッド外で実行する必要がある場合は、AsyncMessageSystem を使用してください。.uproject でプラグインを有効にし、PublicDependencyModuleNames に "AsyncMessageSystem" を追加します。このプラグインはすでに GameplayTags に依存しています。手順、シグネチャの完全な記述、バインドオプション、エンドポイントについては、gameplay-messaging.md に記載されています。
// MyScorePayload.h
#pragma once
#include "StructUtils/InstancedStruct.h"
#include "MyScorePayload.generated.h"
USTRUCT()
struct FMyScorePayload
{
GENERATED_BODY()
UPROPERTY()
int32 NewScore = 0;
};
// MyScoreComponent.cpp — queue side
#include "AsyncMessageWorldSubsystem.h"
#include "AsyncMessageSystemBase.h"
#include "MyGameplayTags.h"
#include "MyScorePayload.h"
void UMyScoreComponent::BroadcastScore(int32 NewScore)
{
TSharedPtr<FAsyncMessageSystemBase> Sys = UAsyncMessageWorldSubsystem::GetSharedMessageSystem(GetWorld());
if (!Sys.IsValid())
{
return;
}
FMyScorePayload Payload;
Payload.NewScore = NewScore;
Sys->QueueMessageForBroadcast(FAsyncMessageId(TAG_MyGame_Message_ScoreChanged.GetTag()),
FInstancedStruct::Make<FMyScorePayload>(Payload));
}
エンジンには含まれていません: UGameplayMessageSubsystem とその GameplayMessageRouter は Lyra のサンプルコードで、Lyra プロジェクトにコピーされたものであり、Engine/ には同梱されていません。#include "GameFramework/GameplayMessageSubsystem.h" を使わないでください。解決できません。Lyra のファイルを独自のモジュールに移植するか、AsyncMessageSystem を使用してください。
エディターの UX とフィルタリング
meta = (Categories = "…") はタグピッカーを1つのサブツリーに制限します。メタデータキーは ObjectMacros.h の namespace GameplayTagsManager で宣言されている Categories と GameplayTagFilter です。
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category = "Damage", meta = (Categories = "MyGame.Damage"))
FGameplayTag DamageType;
UFUNCTION(BlueprintCallable, Category = "Damage")
void ApplyElement(UPARAM(meta = (GameplayTagFilter = "MyGame.Damage")) FGameplayTag Element);
UGameplayTagsManager::GetCategoriesMetaFromField は最初に Categories を読み取り、次に GameplayTagFilter にフォールバックします。GetCategoriesMetaFromFunction(Func, ParamName) は Blueprint ピンのフィルターを解決する際に使用されます。どちらも、ルートをカンマ区切りで並べたリストを受け取ります。
UGameplayTagsSettings の FGameplayTagCategoryRemap(BaseCategory → RemapCategories)は、Mover や GAS の Categories 値など、エンジン側のフィルターを独自のサブツリーにリダイレクトし、エンジンのプロパティに独自のタグを表示します。UGameplayTagsDeveloperSettings(config=EditorPerProjectUserSettings)には、ピッカーから新しいタグを追加する際に使用するユーザーごとの FavoriteTagSource と DeveloperConfigName が含まれています。IGameplayTagsModule::OnGameplayTagTreeChanged と OnTagSettingsChanged を使うと、辞書の変更時にエディターツールを更新できます。
非推奨 — 使用しないでください
| 出力しないでください | 5.8 で使用 | 出典 |
|---|---|---|
UGameplayTagsManager::OnLastChanceToAddNativeTags() | CallOrRegister_OnAddNativeTagsDelegate、または AddNativeGameplayTag を直接使用 | GameplayTagsManager.h:415 の UE_DEPRECATED(5.8) |
CallOrRegister_OnDoneAddingNativeTags | CallOrRegister_OnDoneAddingNativeTagsDelegate | この名前は存在したことがありません。GameplayTagsManager.h:429 |
UGameplayTagsManager::GetSingleTagContainer(Tag) | FindTagNode(Tag) または FGameplayTag::GetSingleTagContainer() | GameplayTagsManager.h:472 の UE_DEPRECATED(5.4) |
FGameplayTagContainer::AddParentsForTag | ParseParentTags または UGameplayTagsManager::ExtractParentTags | GameplayTagContainer.h:615 の UE_DEPRECATED(5.4) |
UGameplayTagsManager::ShouldClearInvalidTags() | なし — 無効なタグはクリアされません | GameplayTagsManager.h:594 の UE_DEPRECATED(5.5) |
ClearInvalidTags ini キー | 削除してください | GameplayTagsSettings.h:115 の UE_DEPRECATED(5.5) |
[/Script/Engine.Engine] 配下の +GameplayTagRedirects | [/Script/GameplayTags.GameplayTagsSettings] 配下の同じキー | 「非推奨の場所」エラー、GameplayTagRedirectors.cpp:26-56 |
EGameplayTagMatchType::Explicit / IncludeParentTags | 各呼び出しで Exact サフィックスを使用(HasTagExact、MatchesTagExact) | この列挙型は 5.8 に存在しません |
Container.HasTag(Tag, MatchTypeA, MatchTypeB) | HasTag(Tag) または HasTagExact(Tag) | 引数 1 つの形式のみです。GameplayTagContainer.h:299,316 |
Container.MatchesAll(Other) | HasAll(Other) / HasAllExact(Other) | このメンバーはありません。GameplayTagContainer.h:379,402 |
Container.Matches(Query) | Container.MatchesQuery(Query) または Query.Matches(Container) | GameplayTagContainer.h:464,803 |
MakeQuery_MatchAnyTagsExact | MakeQuery_ExactMatchAnyTags | GameplayTagContainer.h:857 |
DEFINE_GAMEPLAY_TAG / DECLARE_GAMEPLAY_TAG_EXTERN(UE_ なし) | UE_DEFINE_GAMEPLAY_TAG / UE_DECLARE_GAMEPLAY_TAG_EXTERN | NativeGameplayTags.h:31,41 |
IGameplayTagsModule::Get().GetGameplayTagsManager() | UGameplayTagsManager::Get() | モジュールが公開するのは 2 つの変更デリゲートのみです。GameplayTagsModule.h:47-50 |
UGameplayMessageSubsystem(Lyra サンプル。エンジンにはありません) | サブシステムのデリゲート、または AsyncMessageSystem | Engine/Source または Engine/Plugins のどこにも存在しません |
よくある間違い
マネージャーにタグが登録される前にリクエストする: 静的初期化中やモジュールの起動直後に RequestGameplayTag(FName("MyGame.X")) を呼び出すと、空のタグが返されます。ネイティブタグ変数を使用するか、CallOrRegister_OnDoneAddingNativeTagsDelegate 内で検索を行うようにしてください。
同じネイティブタグを2箇所で定義する: ヘッダー内の UE_DEFINE_GAMEPLAY_TAG、または2つの .cpp ファイルで同じ変数を定義すると、重複シンボルによるリンクエラーが発生します。ヘッダーで UE_DECLARE_GAMEPLAY_TAG_EXTERN を使って一度だけ宣言し、.cpp で一度だけ定義してください。タグをファイル内に限定する場合は、UE_DEFINE_GAMEPLAY_TAG_STATIC を使用してください。
完全一致させるべきところで MatchesTag を使う: MyGame.Damage.Fire.Napalm を含むコンテナに対して、Owned.HasTag(TAG_MyGame_Damage_Fire) は true になります。また、FireTag を指定すると、DamageType.MatchesTag(FireTag) はあらゆる火属性のサブタイプに対して true になります。末端のタグのみを対象とする必要がある場合は、HasTagExact / MatchesTagExact を使用してください。
ゲームプレイコードにタグ文字列をハードコードする: クラス内のあちこちに RequestGameplayTag(FName("MyGame.State.Stunned")) を記述すると、名前を変更してもコンパイルエラーもリダイレクトも発生しません。ネイティブタグを1つ定義し、すべての箇所で参照してください。
モジュール依存関係: Engine.Build.cs には "GameplayTags" が パブリック 依存関係として記載されているため、Engine に依存するモジュールは、タグコードを追加しなくてもコンパイルとリンクが可能です。それでも、依存関係が明示されるよう "GameplayTags" を追加してください(タグ型がパブリックヘッダーに現れる場合はパブリック、それ以外はプライベート)。そうすれば、将来 Engine への依存がなくなった場合にも依存関係が維持され、IWYU ツールからも認識されます。Engine に依存しないモジュール(まれです)では、追加が必要です。
リダイレクトなしで ini のタグ名を変更する: 古い名前を参照するすべてのアセットは無効なタグとして読み込まれ、WarnOnInvalidTags は最大でもログに記録するだけです。名前を変更するコミットと同時に、+GameplayTagRedirects=(OldTagName="Old",NewTagName="New") を追加してください。
FastReplication=True の状態で AddNativeGameplayTag を遅いタイミングで呼び出す: ネットインデックステーブルがすでに構築されているため、クライアントとサーバーで内容が一致しなくなります。モジュールの起動中に登録するか、代わりに bDynamicReplication を使用してください。
毎フレーム FGameplayTagQuery を構築する: BuildQuery はトークンストリームを生成します。コンストラクターまたは BeginPlay で構築して保存し、負荷の高い処理では Matches を呼び出してください。
Lyra メッセージルーターがあると思い込む: クリーンなプロジェクトでは #include "GameFramework/GameplayMessageSubsystem.h" を解決できません。このサブシステムはエンジンではなく、Lyra サンプルに含まれています。サブシステムのデリゲートまたは AsyncMessageSystem プラグインを使用してください。
関連スキル
ue-gameplay-abilities— GAS 側でのタグの使用方法:アビリティの有効化条件、付与されるタグ、RegisterGameplayTagEvent、ゲームプレイイベントue-state-trees— タグコンテナやクエリを評価する State Tree の条件とタスクue-game-features— プラグインスコープのタグ ini ソースと、それらを登録するアクティベーションのライフサイクルue-ai-navigation— Smart Object とビヘイビアタグのフィルタリングue-cpp-foundations—UPROPERTY/UFUNCTION指定子、デリゲート、メッセージングを担うサブシステムue-networking-replication— タグプロパティのレプリケーション、プッシュモデル、RPC のコストue-data-assets-tables— タグソースやタグをキーとするデータに使用するUDataTableアセット