【UE4】C++アニメーションノードを見よう見まねで作ったメモ

[1]:http://papersloth.hatenablog.com/entry/2018/03/05/221735
[2]:http://historia.co.jp/archives/3097/
[3]:https://qiita.com/strv13570/items/7d43502b72aed478c669
[4]:https://qiita.com/Naotsun/items/dba9f767d06f2f86887c
[5]:https://qiita.com/go_astrayer/items/accf6772c38979ffecb5
[6]:https://qiita.com/go_astrayer/items/eb8b2d249018ac4f472f
[7]:https://docs.unrealengine.com/en-US/API/Editor/AnimGraph/UAnimGraphNode_Base/index.html
[8]:https://qiita.com/strv13570


> UE4.24

アニメーションノードを自作しようとして、あれこれ調べたり試したりしたメモ。

# 参考URL

- モジュール
    - [UE4 Moduleについて - PaperSloth's diary][1]
    - [［UE4］モジュールについて - ヒストリアブログ][2]
    - [ちょっとだけくわしくUE4モジュールの話【解説編】 - Qiita@strv13570][3]
- C++ アニメーションノード
    - [【UnrealC++】自作アニメーションノードを作る - Qiita@Naotsun][4]
    - [受け取ったポーズを返すだけのアニメーションノードを作ってみた - Qiita@go_astrayer][5]
    - [アニメーションノードをまとめたアニメーションノードを作ってみた - Qiita@go_astrayer][6]


# やることリスト

- Editor 用のモジュールの作成
    1. 新規C++プロジェクトの作成
    2. 新規モジュール用のフォルダとファイルを作る
    3. ～.Target.cs に新規モジュールを追加する
    4. ～.uproject に新規モジュールを追加する
    5. Visual Studio ソリューションを更新する
- C++ Anim Node の作成
    1. Runtime 側のモジュールに FAnimNode_Base の派生クラスを作る
    2. Editor 側のモジュールに UAnimGraphNode_Base の派生クラスを作る

# Editor 用モジュールの作成

> [UE4 Moduleについて - PaperSloth's diary][1] に書いてある通りにやっていけば、大体うまくいく。

アニメーションノードはRuntimeで動くものと、Editorで動くものの2つを作らなくてはならない。

- Anim Behavior Node (Runtime): アニメーションの計算をするノード
    - FAnimNode_Base の派生クラス(実際は構造体)
    - Runtime でも Editor でも動く必要がある。（…というか、Runtime で動くものは Editor でも動く…はず）
- Anim Graph Node (Editor): エディタで使うグラフノード
    - UAnimGraphNode_Base の派生クラス(こちらはクラス)
    - Runtime では動く必要がない。

このうち、Anim Graph Node は Editor 上で動くもの ＆ Editor でしか必要ないものなので、Editor用モジュールの方に入れなくてはならない。  
ということで、前提知識として「新しいモジュールの作り方」が必要。

## 新規C++プロジェクトを作成

Epic Games Launcher (など)から新規C++プロジェクトを作成する。

- 今回は「CustomAnimNode」というプロジェクトを作成したとする。
- 作成され、Visual Studio と UE4 Editor が立ち上がったら、どっちも殺すw（しばらく不要）

## Editorモジュール用のフォルダを作り、モジュールのためのファイルを作る

- CustomAnimNode/Source/ の下に「CustomAnimNode」フォルダができているはず。
- 「CustomAnimNode」フォルダと同列に「CustomAnimNodeEd」フォルダを新規作成する。
- CustomAnimNode/Source/CustomAnimNode/ から CustomAnimNodeEd/ へ、以下の3つのファイルをコピペする。
    - CustumAnimNode.Build.cs
    - CustomAnimNode.h
    - CustomAnimNode.cpp
- それらを以下のようにリネームする。(「Ed」をつけただけ）
    - CustomAnimNodeEd.Build.cs
    - CustomAnimNodeEd.h
    - CustomAnimNodeEd.cpp

## 上記３つのファイルを編集する

テキストエディタなら何でもいい。Visual Studio Code とかメモ帳とか。もちろん Visual Studio で編集してもよいが。  

> <font color="orange">ただし、Visual Studio ソリューションは開かない!!</font>
> 「Generate Visual Studio project files」を実行してから開くべし。（後述）
> ※ソリューションを開いてもいいのだが、変な操作をしないよう、念のため。

### CustomAnimNodeEd.Build.cs

```c#:CustomAnimNodeEd.Build.cs（変更前）
public class CustomAnimNode : ModuleRules
{
	public CustomAnimNode(ReadOnlyTargetRules Target) : base(Target)
	{
        // 以下略
```

```c#:CustomAnimNodeEd.Build.cs（変更後）
public class CustomAnimNodeEd : ModuleRules
{
	public CustomAnimNodeEd(ReadOnlyTargetRules Target) : base(Target)
	{
        // 以下略
```

クラス名とコンストラクタ名の２箇所を「CustomAnimNodeEd」に変更しただけ。

### CustomAnimNodeEd.h

IModuleInterface の派生クラスを作る。  

```c++:CustomAnimNodeEd.h（変更前）
#pragma once

#include "CoreMinimal.h"
```

```c++:CustomAnimNodeEd.h（変更後）
#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FCustomAnimNodeEdModule : public IModuleInterface
{
public:
    virtual void StartupModule() override {}
    virtual void ShutdownModule() override {}
    virtual bool IsGameModule() const override { return false; }
};
```

- "Modules/ModuleManager.h" のインクルードが必要。
- モジュールクラス名は「F(モジュール名)Module」
- IsGameModule() の返り値に注意。
    - このモジュールがランタイムモジュールの場合は true を返すこと。
    - 今回はエディタ用のモジュールなので false を返している。

### CustomAnimNodeEd.cpp

```c++:CustomAnimNodeEd.cpp（変更前）
#include "CustomAnimNode.h"
#include "Modules/ModuleManager.h"

IMPLEMENT_PRIMARY_GAME_MODULE( FDefaultGameModuleImpl, CustomAnimNode, "CustomAnimNode" );
```

```c++:CustomAnimNodeEd.cpp（変更後）
#include "CustomAnimNodeEd.h"

IMPLEMENT_MODULE(FCustomAnimNodeEdModule, CustomAnimNodeEd);
```

- "Modules/ModuleManager.h" のインクルードを消した。
    - 実際のところ FCustomAnimNodeModule クラスの関数定義は CustomAnimNodeEd.h じゃなくて CustomAnimNodeEd.cpp に書いてもよいのだが、なんとなく…  
    （多くの人が.cppに書ているようだ）
- IMPLEMENT_PRIMARY_GAME_MODULE() マクロを IMPLEMENT_MODULE() マクロに変更
    - IMPLEMENT_PRIMARY_GAME_MODULE() はアプリに１つだけ存在するゲームモジュールの意。（つまりはメインモジュール）
    - IMPLEMENT_MODUDLE() はその他のモジュールの意。
    - ただし、Runtime で動かしたいモジュールは IMPLEMENT_GAME_MODULE() マクロを使用すること！
        - その場合は、FCustomAnimNodeEd::IsGameModule() は true を返すようにすること！
- IMPLEMENT_MODULE() の第２引数は文字列ではない。（どうやら以前の UE4 バージョンでは文字列だったらしい）

## ～.Target.cs に追加モジュールを記載する

- CustomAnimNode/Source/ の下に CustomAnimNode.Target.cs と CustomAnimNodeEditor.Target.cs があるはず。
    - ～.Target.cs は Visual Studio のビルド構成「DebugGame」とか「Development」とか「Shipping」とか用。
    - ～Editor.Target.cs は Visual Studio のビルド構成「DebugGame Editor」とか「Development Editor」とか用。
    - 今回「エディタ用のモジュールを作る」とか言っているので、つい CustomAnimNodeEd と CustomAnimNodeEditor.Target.cs を混同してしまいがちなので注意。つまり～.Target.cs はビルド構成の話。
- 今回は Editor 用のモジュールを作っているので、「DebugGame Editor」とか「Development Editor」のビルド構成のみに必要。
    - なので、今回いじるのは「CustomAnimNodeEditor.Target.cs」だけ。

> ※ランタイム用のモジュールを作っているときは両方の編集が必要。

```c#:CustomAnimNodeEditor.Target.cs（変更前）
public class CustomAnimNodeEditorTarget : TargetRules
{
	public CustomAnimNodeEditorTarget( TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;
		DefaultBuildSettings = BuildSettingsVersion.V2;
		ExtraModuleNames.AddRange( new string[] { "CustomAnimNode" } );
	}
}
```

```c#:CustomAnimNodeEditor.Target.cs（変更後）
public class CustomAnimNodeEditorTarget : TargetRules
{
	public CustomAnimNodeEditorTarget( TargetInfo Target) : base(Target)
	{
		Type = TargetType.Editor;
		DefaultBuildSettings = BuildSettingsVersion.V2;
		ExtraModuleNames.AddRange( new string[] { 
			"CustomAnimNode",
			// add extra modules down below:
			"CustomAnimNodeEd"
		} );
	}
}
```

要するに、Editor用のビルド構成には、今回新たに作った「CustomAnimNodeEd」モジュールが必要ですよ、ということ。

## ～.uprojectにも追加モジュールを記載する

```json:CustomAnimNode.uproject（変更前）
{
	"FileVersion": 3,
	"EngineAssociation": "4.24",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "CustomAnimNode",
			"Type": "Runtime",
			"LoadingPhase": "Default"
		}
	]
}
```

```json:CustomAnimNode.uproject（変更後）
{
	"FileVersion": 3,
	"EngineAssociation": "4.24",
	"Category": "",
	"Description": "",
	"Modules": [
		{
			"Name": "CustomAnimNode",
			"Type": "Runtime",
			"LoadingPhase": "Default"
		},
        {
            "Name": "CustomAnimNodeEd",
            "Type": "Editor",
            "LoadingPhase": "Default"
        }
	]
}
```

- 新たに CustomAnimNodeEd というモジュールがあるよ、を記載。
- Type は "Runtime", "Editor" のほかに ~~"DevelopmentTool"~~ "DeveloperTool" などもある。
    - [ちょっとだけくわしくUE4モジュールの話【解説編】- Qiita@strv13570][3] などを参照のこと。

> 後日談 2020/02/12：修正
> ご指摘をいただきました。
> ①[ちょっとだけくわしくUE4モジュールの話【解説編】][3] へのリンクの間違いを修正しました。大変失礼しました。
> ②モジュールタイプの例として "DevelopmentTool" と書いておりましたが、正しくは：
> 【UE4.24～】〇DeveloperTool　×DevelopmentTool
> 【～UE4.23】〇Developer
> の間違いでした。


### Visual Studio ソリューションを更新する

ここまでやったら、Visual Studio ソリューションを開く一歩手前に来ている。

- .uproject を右クリックして、UE4 アイコンのついた「Genarate Visual Studio project files」を実行する。
- エラーが出ずにすんなり終わったら成功。
    - エラーが出た場合は、タイポなどのくだらないミスのはずなので確認すべし。
    - たいてい「Ed」の付け忘れとか、IMPLEMENT_MODULE() の書き忘れとかそんなの。
- ソリューション(.sln)を開いて、「CustomAnimNodeEd」のフォルダができていること、そのフォルダに「CustomAnimNodeEd.Build.cs」「CustomAnimNodeEd.h」「CustomAnimNodeEd.cpp」が追加されていることを確認せよ。
- ビルドが成功することを確認せよ。

#### 自分がやらかしたミス一覧

- CustomAnimNodeEd.cpp の #include "CustomAnimNodeEd.h" が #include "CustomAnimNode.h" のままになっている。  
- CustomAnimNodeEd.cpp の IMPLEMENT_MODULE() や IMPLEMENT_GAME_MODULE() が、IMPLEMENT_PRIMARY_GAME_MODULE() のままになっている。  
- CustomAnimNodeEd.cpp の IMPLEMENT_MODULE() の第一引数が FCustomAnimNodeEd になっている。正しくは「FCustomAnimNodeEdModule」 
- ～.Target.cs ファイルの「CustomAnimNodeEd」の追加忘れ。
- 特に .cs ファイルを修正した後、ビルドが通らないなら、.uproject の右クリックからの <font color="orange">Generate Visual Studio project files</font> をやり直せ。（Visual Studio を閉じなくてもできる） 

> ※IntelliSense に指摘されているところがあると、たいていミスってる。

## UE4 Editor を実行して、新規モジュールが読み込まれていることを確認する

ビルドが通ったら実行して UE4 エディタを立ち上げる。  

> - ビルド構成が「DebugGame Editor」もしくは「Development Editor」になっていることを確認せよ。
> - 実行に失敗した場合は、各ファイルのタイポを探せ。

メニューの Window > Developer Tools > Modules を実行すると、モジュール一覧ウィンドウが開く。この中に「CustomAnimNodeEd」が追加されていることを確認せよ。
（モジュール一覧ウィンドウは検索窓があるので、それを使うと速い。）

これでモジュール追加は完了！

# C++ Anim Node の作成

[受け取ったポーズを返すだけのアニメーションノードを作ってみた - Qiita@go_astrayer][5] と同様のものを作ってみる。

> 技術的には[【UnrealC++】自作アニメーションノードを作る - Qiita@Naotsun][4] が最も詳しい。ゼロから始めるときは、このサイトに従って進めるとよい。

## FAnimNode_Base の派生クラスの作成

こちらは Runtime 側モジュールで動く、アニメーションの実働クラス（Anim Behavior ノード）。
FAnimNode_Base 派生クラスは UE4 エディタからは作成できないので、Visual Studio で新規作成する。

- Visual Studio で「CustomAnimNode」フォルダを右クリックして、「追加(D)＞新しい項目(W)...」を実行し、AnimNode_PassThrough.h と AnimNode_PassThrough.cpp を作成する。
    - PassThrough: 「素通し」的なニュアンス。
- 出力先ディレクトリを設定しないと、変なところ(intermediateディレクトリなど)に出力されてしまうので注意。<font color="orange">毎回チェックすること！</font>
    - 「新しい項目の追加」ウィンドウの一番下に「場所(L)」欄がある。
    - ここでは「CustomAnimNode/Source/CustomAnimNode」に新規作成する。

### AnimNode_PassThrough.h

#### インクルードファイルを追加する。

```c++:AnimNode_PassThrough.h
#pragma once

#include "Animation/AnimNodeBase.h" // FAnimNode_Base (module: Engine)
#include "AnimNode_PassThrough.generated.h"
```

- クラス名は FAnimNode_Base だが、インクルードファイル名は AnimNodeBase.h なので注意。
    - つまり、インクルードファイル名には<font color="orange">アンダースコア(_)がない！</font>
    - ここに気づかずに何時間もハマった…
- AnimNode_PassThrough.generated.h はビルドが走ると作られる。
    - ビルド冒頭の UnrealHeaderTool で作られる。

### クラス(構造体)を作る

```c++:AnimNode_PassThrough.h
USTRUCT(BlueprintType)
struct CUSTOMANIMNODE_API FAnimNode_PassThrough : public FAnimNode_Base
{
    GENERATED_USTRUCT_BODY()
    // 続きはこれから書く
};
```

- [参考サイト][4]では USTRUCT() 内が空だが、ビルドエラーが出る。とりあえず USTRUCT(BlueprintType) にしてビルドを通している。（他の選択肢があるかもしれない…）
- モジュールAPI指定子を忘れずに！
    - ここでは CUSTOMANIMNODE_API。
    - 先に述べたように、このクラスは Runtime 用。なので CUSTOMANIMNODE<font color="orange">ED</font>_API じゃない。混同しないように注意！

> 後日談：
> USTRUCT(BlueprintInternalUseOnly) で良さそうだ。

### public なプロパティを追加。

```c++:AnimNode_PassThrough.h（一部）
public: // properties
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Links)
		FPoseLink SourcePose;
```

- Category = "Links" ではなく、Category = Links で正しい。（つまりダブルクォーテーションは不要）
- FPoseLink は IntelliSense でハイライトされるはず。
    - Anim Graph ノードに出てくる入力ポーズに相当。

### コンストラクタ

```c++:AnimNode_PassThrough.h（一部）
public: // ctors
	FAnimNode_PassThrough() {}
```

精神衛生上の都合で念のため書いているだけ。

### FAnimNode_Base のインターフェースをオーバーライドする

```c++:AnimNode_PassThrough.h（一部）
public: // FAnimNode_Base interfaces
	virtual void Initialize_AnyThread(const FAnimationInitializeContext& InContext) override;
	virtual void CacheBones_AnyThread(const FAnimationCacheBonesContext& InContext) override;
	virtual void Update_AnyThread(const FAnimationUpdateContext& InContext) override;
	virtual void Evaluate_AnyThread(FPoseContext& Output) override;
```

- それぞれ _AnyThread がついていない関数も用意されているが、そちらを使うとビルド時に DEPRECATED（非推奨） ワーニングが出る。

### AnimNode_PassThrough.cpp

#### インクルードファイル

```c++:AnimNode_PassThrough.cpp（一部）
#include "AnimNode_PassThrough.h" // itself
```

#### FAnimNode_Base の各インターフェースのオーバーライド

```c++:AnimNode_PassThrough.cpp（一部）
void FAnimNode_PassThrough::Initialize_AnyThread(
	const FAnimationInitializeContext& InContext)
{
	FAnimNode_Base::Initialize_AnyThread(InContext);
	SourcePose.Initialize(InContext);
}

void FAnimNode_PassThrough::CacheBones_AnyThread(
	const FAnimationCacheBonesContext& InContext)
{
	SourcePose.CacheBones(InContext);
}

void FAnimNode_PassThrough::Update_AnyThread(
	const FAnimationUpdateContext& InContext)
{
	SourcePose.Update(InContext);
}

void FAnimNode_PassThrough::Evaluate_AnyThread(
	FPoseContext& Output)
{
	SourcePose.Evaluate(Output);
}
```

まだ詳しくは分かっていないが：

- 参考サイトを見るに：
    - 親クラスの同名関数を呼び出すのは Initialize_AnyThread() だけっぽい。
    - おおむねトランスフォームの計算をしているのは Evaluate_AnyThread() っぽい。
- 今のところ(UE4.24.2)の実装を見ると：
    - Initialize_AnyThread()
        - 実装は空っぽ。
        - ドキュメントには「Called when the node first runs.（初回のみ呼び出し）」とある。
    - CacheBones_AnyThread()
        - 実装は空っぽ。
        - ドキュメントには「Called to cache any bones that this node needs to track (e.g. in a FBoneReference).（必要に応じてボーンをキャッシュする）」とある。
    - Update_AnyThread(): 
        - 実装は空っぽ。
        - ドキュメントには「Called to update the state of the graph relative to this node.（グラフの状態の更新に応じて呼び出される）」とある。
    - Evaluate_AnyThread()
        - 実装は check(false); ユーザーは親クラスの実装を呼び出さないで下さい！ってことだろう。
        - ドキュメントには「Called to evaluate local-space bones transforms according to the weights set up in Update().（Update()のウェイトセットアップにしたがってボーンのローカルトランスフォームを評価する時に呼び出される」とある。

ぶっちゃけ、Evaluate_AnyThread() 以外は保険で呼び出しておいた方が良いかもしれない。（当面はどちらでもよかろう…）

ここまで出来たらビルドが通ることを確認する。

## UAnimGraphNode_Base の派生クラスの作成

今度は Editor モジュールで動く、グラフノードの挙動を実装するクラス（Anim Graph ノード）。
UAnimGraphNode_Base は UE4 エディタの C++ クラスの追加から作れるので、UE4 エディタから追加を行う。

- UE4 エディタを立ち上げ、Contant Browser の右クリックメニューなどから新規 C++ クラスを生成する。
- 親クラスの選択ダイアログが出るので、AnimGraphNode_Base を選び、Next ボタンを押す。
    - 右上の「Show All Classes」チェックボックスにチェックをつける。
    - 検索窓に「AnimGraphNode_Base」と入力し、AnimGraphNode_Base を選択状態にする。
        - 「<font color="orange">U</font>AnimGraphNode_Base」ではないので注意。
- ファイル名指定ダイアログが出るので、ファイル名と出力先モジュールを指定して、Create Class ボタンを押す。
    - ファイル名は「AnimGraphNode_PassThrough」
    - 「CustomAnimNode (Runtime)」をクリックして、出力先モジュールを「CustomAnimNodeEd (Editor)」に変更する。
        - 自動的に出力先パスが CustomAnimNodeEd に変更される。
        - 自前で「Choose Folder」してしまうとややこしくなりがちなので注意。フォルダじゃなくてモジュールを選択すること！
    - Public, Private (とどちらも選択しない) は用途に応じて自由にどうぞ。
    - Create Class ボタンを押す前に、今一度全項目を見直しておいた方がいい。
- Create Class ボタンを押すと、クラスが生成され、コンパイルが始まる。
    - おそらく<font color="orange">コンパイルには失敗する</font>。
        - こういうメッセージダイアログが出ているはず:  
        Successfully added class 'AnimGraphNode_PassThrough', however you must recompile the 'CustomAnimNodeEd' module before it will appear in the Content Brwser.  Failed to automatically compile the 'CustomAnimNodeEd' module.  
        Would you like to open the Output Log to see more details?
        - 押すボタンは Yes でも No でもどちらでもいい。

次は UE4 Editor を閉じて、Visual Studio で作業する。

### 新規ファイルが意図しないフォルダに入っている！

コンパイルエラーを修正したいのだが、その前にどうしても気になるアレを。
ソリューションエクスプローラを見ると、/Games/CustomAnimNode/Source/CustomAnimNode/<font color="orange">Ed</font>/ の下に AnimGraphNode_PassThrough.h と .cpp が置かれている件。

超ビビるが、手動でファイルを移動<font color="orange">しなくていい！</font>。

- Windows のエクスプローラで .uproject を右クリックして、「Generate visual Studio project files」を実行する。
- 終わったら、Visual Studio に戻ると、外部でプロジェクトが変更されたダイアログが出るので、その変更を受け入れる。
- プロジェクトのロードが終わると、正しいフォルダに収まっているはず！

### コンパイルエラーの修正

コンパイルエラーの原因は UAnimGraphNode_Base に必要なモジュールが .Build.cs に指定されていないため。  
[UAnimGraphNode_Base - UE4 Document][7] を見ると AnimGraph モジュールが必要だと分かる。

> ※前もってモジュールが追加されていた場合は、コンパイルに成功する。
> どちらにせよ、後で修正できるので、成功しても失敗しても構わない。

#### CustomAnimNodeEd.Build.cs

- PublicDependencyModuleNames に AnimGraph を追加する。
    - Public にするのか Private にするのかは、今のところ気にしていない。
- Windows のエクスプローラで .uproject を右クリックして、「Generate Visual Studio project files」を実行する。
- ビルドする。

ところが、変なビルドエラーが出る！
FBlueprintNodeSignature がどうの、とか。
これも超ビビるが、

- 再び CustomAnimNodeEd.Build.cs に戻る。
- PublicDependencyModuleNames に "BlueprintGraph" を追加する。
    - BlueprintGraph モジュールは UAnimGraphNode_Base の一つ上のクラス UK2Node が含まれているモジュール。
- Windows のエクスプローラで .uproject を右クリックして、「Generate Visual Studio project files」を実行する。
- ビルドする。

今度は成功するはずである！

> 上の方に書いたことをもう一度書いておく:
> ～.cs ファイルをいじったら「Generate Visual Studio project files」を実行するクセをつけておこう！

```c#:現在のCustomAnimNodeEd.Build.csのPublicDependencyModuleNamesの内容:
		PublicDependencyModuleNames.AddRange(new string[] { 
			"Core", 
			"CoreUObject", 
			"Engine", 
			"InputCore",
			// add extra modules down below:
			"AnimGraph", // UAnimGraphNode_Base
			"BlueprintGraph" // UK2Node (base class of UAnimGraphNode_Base)
		});
```

これで UAnimGraphNode_PassThrough クラスの記述に進めるようになった。

### AnimGraphNode_PassThrough.h

#### GENERATED_BODY() マクロを GENERATED_UCLASS_BODY() に変更する

```c++:AnimGraphNode_PassThrough.h（変更前）
UCLASS()
class CUSTOMANIMNODEED_API UAnimGraphNode_PassThrough : public UAnimGraphNode_Base
{
	GENERATED_BODY()
};
```

この GENERATED_BODY() マクロを GENERATED_UCLASS_BODY() に変更する。
ちゃんと調べていないので、以下は勘だが…

- GENERATED_BODY() には、コンストラクタが内包されているので、手動でコンストラクタを記述しなくてよい。つまり、コンストラクタの中身はデフォルト動作（親クラスにお任せ）で、自前の初期化などは記述できない。
- GENERATED_UCLASS_BODY() は、コンストラクタの宣言は入っているが、実装は入っていない。つまり、.cpp ファイルに自前でコンストラクタの挙動を記述しなくてはならない。

なお、

- クラスの中身が GENERATED_BODY() だけの状態でビルドすると成功する。
- クラスの中身が GENERATED_UCLASS_BODY() だけの状態でビルドすると、引数が const FObjectInitializer& のコンストラクタの実装がない旨のリンクエラーが出る。

> 精神衛生上、自分でコンストラクタの動作を記述したい気分である。

```c++:AnimGraphNode_PassThrough.h（変更後）
UCLASS()
class CUSTOMANIMNODEED_API UAnimGraphNode_PassThrough : public UAnimGraphNode_Base
{
	GENERATED_UCLASS_BODY()
};
```

#### プロパティの追加

Runtime モジュールの方に作った FAnimNode_PassThrough 構造体をメンバーに持たせる。

```c++:AnimGraphNode_PassThrough.h（一部）
public: // properties
	UPROPERTY(EditAnywhere, Category = Settings)
		FAnimNode_PassThrough Node;
```

IntelliSense が FAnimNode_PassThrough で警告を出しているのは、未定義だからである。なので、インクルードファイルを足す。

```C++:AnimGraphNode_PassThrough.h（一部）
#include "CoreMinimal.h"
#include "AnimGraphNode_Base.h"
#include "CustomAnimNode/AnimNode_PassThrough.h" // FAnimNode_PassThrough
#include "AnimGraphNode_PassThrough.generated.h"
```

> ～.generated.h はインクルード群の最後にする必要があるので注意。

#### インターフェス(メソッド)の追加

とりあえずは[参考サイト][5]のマネをして、ノードのタイトル文字列だけ変更。

```C++:AnimGraphNode_PassThrough.h（一部）
public: // UEdGraphNode interfaces
	virtual FText GetNodeTitle(ENodeTitleType::Type InTitleType) const override;
```

コメントの通り、このインターフェースは UAnimGraphNode_Base の親(UK2Node)の親(UEdGraphNode)のものである。

### AnimGraphNode_PassThrough.cpp

#### コンストラクタの実装 (精神衛生上の問題!?)

実際に何かを実装するわけではないのだが、一応。

```C++:AnimGraphNode_PassThrough.cpp（一部）
UAnimGraphNode_PassThrough::UAnimGraphNode_PassThrough(
	const FObjectInitializer& InObjectInitializer)
	: Super(InObjectInitializer)
{
}
```

### ノードのタイトル文字列

```C++:AnimGraphNode_PassThrough.cpp（一部）
FText UAnimGraphNode_PassThrough::GetNodeTitle(
    ENodeTitleType::Type InTitleType) const
{
	return LOCTEXT("AnimGraphNode_PassThrough_Title", "Pass Through");
}
```

なお、LOCTEXT() マクロを使うために、#include 群の下あたりに LOCTEXT_NAMESPACE を定義しておく。

```C++:AnimGraphNode_PassThrough.cpp（一部）
#define LOCTEXT_NAMESPACE "AnimGraphNode_PassThrough"
```

また、精神の衛生のために、この .cpp の末尾で LOCTEXT_NAMESPACE を #undef しておく。

```C++:AnimGraphNode_PassThrough（一部）
#undef LOCTEXT_NAMESPACE
```

### ビルドする。だがエラーが出る。

この状態でビルドすると、複数のエラーの中に、「'AnimNode_PassThrough.generated.h': No such file or directory」が出ているはずである。

- AnimNode_PassThrough は Runtime モジュール用に作ったクラス(構造体)である。
- ところが、この UAnimGraphNode_PassThrough は Editor 用のモジュールで動く。つまり別モジュールのものである。

結論： CustomAnimNodeEd.Build.cs に「CustomAnimNode」モジュールを追加する。

```C#:CustomAnimNodeEd.Build.cs（一部）
		PublicDependencyModuleNames.AddRange(new string[] { 
			"Core", 
			"CoreUObject", 
			"Engine", 
			"InputCore",
			// add extra modules down below:
			"CustomAnimNode", // FAnimNode_PassThrough (my code)
			"AnimGraph", // UAnimGraphNode_Base
			"BlueprintGraph" // UK2Node (base class of UAnimGraphNode_Base)
		});
```

～.cs ファイルをいじったので、.uproject を右クリックして、<font color="orange">Generate Visual Studio project files</font> を実行する。
これでビルドが通るはずである。

> "～.generated.h" で No such file or directory エラーが出た時は、<font color="orange">モジュールの足し忘れ</font>を疑うべし！
> そして、モジュールを足したら <font color="orange">Generate Visual Studio project files</font> を実行すべし！

# 動作確認

UE4 Editor を起動して、Anim Blueprint を新規作成。（ABP_PassThroughとか）
こういう(↓) Anim Graph を組んで動くことを確認。

![20200209_01_AnimGraph01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/0a70a720-3dea-ff64-9374-80154dac5788.jpeg)

Pass Throughノードありでもなしでも、Walk_Fwd_Rifle_Ironsights が再生された！