UE4 GameplayTagについてのメモ

# 概要
UnrealEngine の GameplayTag についてのメモ書きです。

アクターやコンポーネントについているTagではありませんのでご注意ください。


## 環境
Windows10
Visual Studio 2017
UnrealEngine 4.22


## 参考
以下を参考にさせて頂きました、ありがとうございます。

[UE公式：Gameplay Tag](https://api.unrealengine.com/JPN/Gameplay/Tags/index.html)
[UE4 Gameplay Tagを使ってゲームプレイ時のタグ管理をより扱いやすくする](http://unrealengine.hatenablog.com/entry/2017/02/21/220000)
[UE公式：FGameplayTag](https://docs.unrealengine.com/5.3/en-US/API/Runtime/GameplayTags/FGameplayTag/)


# GameplayTagについて
ゲームプレイタグはアクタータグやコンポーネントタグとは違い、ゲームプレイ中のフラグ情報やステートの管理を想定した階層を持つラベルで、ゲームプレイ中でのタグの追加/削除が想定されています。

## アクタータグ
![Actortag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/1eb5b590-32b2-b2a1-9e0b-782c283ce3ae.png)

```cpp
// アクターのタグを確認する
if( OtherActor->ActorHasTag("Item")) {
	// OtherActorが "Item" というタグを持っている
}
```

## コンポーネントタグ
![ComponentTag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/42b48176-d304-8ad5-8d7c-62cb5cab7360.png)



# 実装準備
GameplayTagを使うための準備です。基本的にはC++から行います。

## Build.cs モジュールの追加
GameplayTagsモジュールを追加する必要があります。

```cs:Build.cs
using UnrealBuildTool;
 
public class MyProject : ModuleRules
{
	public MyProject(TargetInfo Target)
	{
		PublicDependencyModuleNames.AddRange(
			new string[]
			{
				"Core",
				"CoreUObject",
				"InputCore",
				"Engine",
				"Slate",
				"SlateCore",
				"UMG",
				"GameplayTags"	// ←これを追加する
			});
	}
}
```

## アクターに対する追加処理
GameplayTagを持たせたいアクターに対し、IGameplayTagAssetInterfaceインターフェイスを追加し、ゲームプレイタグコンテナをメンバ変数として定義します。
ゲームプレイタグコンテナとはゲームプレイタグを複数格納できるコンテナです。

```cpp:TestActor.h
#include "GameplayTags.h"
UCLASS()
class TEST_API AMyPawn : public APawn, public IGameplayTagAssetInterface
{
	GENERATED_BODY()

public:
	....


public:
	// ゲームプレイタグコンテナを取得（実装必須）
	virtual void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override{ TagContainer = GameplayTags; return; }

	// ゲームプレイタグコンテナ
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameplayTags")
	FGameplayTagContainer GameplayTags;

};
```


## Gameplay Tagの追加確認
「セッティング」->「プロジェクト設定」->「プロジェクト」->「ゲームプレイタグ」から[Gameplay Tag List] で追加確認ができます。

（例）UEサンプルActionRPGでの設定
![proj_gameplaytag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/7b677fd4-5d00-d746-a750-5e978439f01b.png)


<font color=red>＃ここのリストは別なプラグイン等で使っているタグ（AbilityTagなど）と共通になっていることに注意。</font>



# ゲームプレイタグを扱うメソッドについて
## GameplayTags/BlueprintGameplayTagLibrary.h
BPにてゲームプレイタグを扱うライブラリです。

### AddGameplayTag
タグを追加します。
![AddGameplayTag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/e42de3aa-5cad-01bb-b46a-6cf7db23623c.png)


### RemoveGameplayTag
タグを削除します。
![RemoveGameplayTag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/764d8310-d035-ad31-96a9-9e7e13a8c308.png)


### GetDebugStringFromGameplayTagContainer
デバッグ用：現在のゲームプレイタグを文字列で取得します。
![GetDebugFromGameplayTagContainer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/e7a625f7-b9f4-f108-0570-14d6fe2b4285.png)

C++では ToString()系で取得ができます。

```cpp
// タグコンテナが持っているゲームプレイタグの文字列を取得する。
FString _Str = TagContainer.ToStringSimple();

// ゲームプレイタグの文字列を取得する。
FString _Str = GameplayTag.ToString();
```


### HasTag
指定タグを持っているかを調べます。
bExactMatchは厳密なチェックをするかのフラグです。通常はfalseでいいと思いますが、タグの親を指定してまとめてチェックする際などはtrueにする必要があります。
![HasTag.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/132df9ba-157a-6c2c-1607-057cbcd34191.png)


## IGameplayTagAssetInterface
アクターに追加したインターフェイス IGameplayTagAssetInterface が持っているメソッドです。
所有タグの確認メソッドのみ実装されているようです。

### HasMatchingGameplayTag
指定タグを持っているか（指定タグの親を展開する）

(例１)"Event.Test1" を持っている場合、"Event"でHasMatchingGameplayTagした場合、trueになる
(例２)"Event"を持っている場合、"Event.Test1"でHasMatchingGameplayTagした場合、falseになる

```cpp:GameplayTagAssetInterface.h
UFUNCTION(BlueprintCallable, Category=GameplayTags)
virtual bool HasMatchingGameplayTag(FGameplayTag TagToCheck) const;
```


### HasAllMatchingGameplayTags
指定したタグ全てを持っているか（指定タグの親を展開する）

```cpp:GameplayTagAssetInterface.h
UFUNCTION(BlueprintCallable, Category=GameplayTags)
virtual bool HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const;

```


### HasAnyMatchingGameplayTags
指定したタグいずれかを持っているか（指定タグの親を展開する）

```cpp:GameplayTagAssetInterface.h
UFUNCTION(BlueprintCallable, Category=GameplayTags)
virtual bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const;
```


## GameplayTagContainer.h
GameplayTag や GameplayTagContainer のstruct定義にゲームプレイタグを扱うメソッドが定義されています。
C++でのゲームプレイタグの追加や削除はこれを使います。

### タグ追加
```cpp:GameplayTagContainer.h
void AddTag(const FGameplayTag& TagToAdd);
void AddTagFast(const FGameplayTag& TagToAdd);
bool AddLeafTag(const FGameplayTag& TagToAdd);
```
AddTagFast はチェックなしで追加するようです。
AddLeafTag は追加したタグの直接の親を削除するようです。


### タグ削除
```cpp:GameplayTagContainer.h
bool RemoveTag(FGameplayTag TagToRemove);
void RemoveTags(FGameplayTagContainer TagsToRemove);
```
親を指定して下の階層の子タグをまとめて削除するようなメソッドが見当たりません。。:disappointed_relieved:


# その他
## GameplayTagQueryについて
予めマッチングに使うクエリを作成しておいて、タグコンテナとのマッチに使います。
複数の場所で同じようなマッチングをする処理の手間を省くことができるようです。

```
// クエリを作成
FGameplayTagQuery _Query;
	_Query.Build(FGameplayTagQueryExpression()
		.AllTagsMatch()
		.AddTag(FGameplayTag::RequestGameplayTag(FName("Item.Coin")))
		.AddTag(FGameplayTag::RequestGameplayTag(FName("Item.Potion")))
	);

...

// クエリを使ってマッチチェック
if (_Query.Matches(MyGameplayTagContainer) ){
	// "Item.Coin" と "Item.Potion" のゲームプレイタグ両方を持っている
}

```

　
BP上で GameplayTagQuery型の変数を持つと専用エディタが使えるようになり、クエリをエディットできます。
![GameplayTagQuery.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303806/39ef6b97-a953-7c66-29ff-059a8a59d9b3.png)



## コードメモ
ゲームプレイタグコンテナへゲームプレイタグを追加するコードのメモです。

```cpp:
// タグコンテナにタグを足す
FGameplayTagContainer _Tags;
_Tags.AddTag(FGameplayTag::RequestGameplayTag(FName("Event.Test")));
```


# まとめ
使用用途としてはフラグやステート管理に使えると思います。
他には排他処理や発動条件管理などで使用でき、階層構造になっているため条件の追加がしやすいと思います。

アクターやコンポーネントにも（GameplayTagではない）Tagがあるため、いろいろ紛らわしいです。:thinking: