[UE4] C++で動的にアクターを生成（スポーン）する方法で一番実用的だった方法

# 環境
- OS：Ubuntu 16.04 LTS
- UE4バージョン：4.22.1
- エディタ：Visual Studio Code

# はじめに
UE4でアクターを動的にスポーンする必要があったので調査・実装した。実装方法は複数見受けられたが、その中で一番実用的だと思ったものを紹介する。

結果（再生→アクタースポーン）
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356592/14db05f7-8e9e-ef40-7f88-193468d1dee6.png)
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356592/2ad1e363-efa4-08f9-d720-dc886cd6dfbd.png)


# スポーン方法

## 一番実用的だった方法

さっそく、一番実用的だった方法を紹介する。  
スポーンしたいアクターブループリントのパスを指定してクラスを取得し、そのクラスのアクターをスポーンする方法である。

- アクターブループリントを作成しておく（今回は test という名前で作成）
- アクターをスポーンするために利用する cpp ファイルに後述のコードを記述する
- 上記処理をブループリントから呼び出す（今回はレベルブループリントの BeginPlay に記述した）

```cpp
FString path = "/Game/test.test_C"; // /Content 以下のパスが /Game 以下のパスに置き換わり、コンテントブラウザーで名前が test なら test.test_C を指定する。
TSubclassOf<class AActor> sc = TSoftClassPtr<AActor>(FSoftObjectPath(*path)).LoadSynchronous(); // 上記で設定したパスに該当するクラスを取得
if (sc != nullptr)
{
    AActor* a = GetWorld()->SpawnActor<AActor>(sc); // スポーン処理
    a->SetActorLocation(FVector(-600, 200, 200)); // 確認しやすいように座標を設定
}
```

この方法は後述の方法と比べ、以下が優れていると感じた。

- アクターブループリントのパスを変数とすれば任意のアクターを動的生成できる
- 記述、振る舞いともにシンプル

## その他のスポーン方法①

スポーンしたいアクターブループリントのパスを指定してブループリントを取得し、そのブループリントのクラスのアクターをスポーンする方法。

- cppに記述する内容を下記のものに変更する

```cpp
FString path = "/Game/test.test"; // この方法のときは、パスの末尾に _C を付与しない
UBlueprint* bp = FindObject<UBlueprint>(NULL, *path); // 上記で設定したパスに該当するブループリントを見つける
if (bp != nullptr)
{
    AActor* a = GetWorld()->SpawnActor(bp->GeneratedClass); // スポーン処理
    a->SetActorLocation(FVector(-600,200,200)); // 確認しやすいように座標を設定
}
```

※ この方法ではアクターブループリントが読み込まれていないときに実行してもアクターがスポーンされないため、一度対象のアクターをクリックするか、アセットを再ロードするか、ワールドに配置しておく等で読み込まれている状態にしておく必要がある  
再ロードの例
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/356592/4c2347a2-4221-befd-7b86-21c2e2eb3c4a.png)


上記の※で記した内容がこの方法のデメリットである。

## その他のスポーン方法②

コンストラクタで事前にスポーンしたいアクターブループリントのクラスを取得しておき、そのクラスのアクターをスポーンする方法。

- 処理を記載するcppクラスのヘッダファイルにクラスのメンバ変数として以下のコードを記述する

```cpp
// クラスのメンバ変数として以下を記述する
TSubclassOf< class AActor > sc = nullptr;
```

- 該当クラスのコンストラクタに以下のコードを記述する

```cpp
FString path = "/Game/test.test_C";
static ConstructorHelpers::FObjectFinder< UClass > found(*path); // 上記で設定したパスのオブジェクトを取得する
sc = found.Object; // 上記で発見したオブジェクトのクラスを取得する
```

- cppに以下のスポーン処理のコードを記述する

```cpp
if (sc != nullptr)
{
    AActor* a = GetWorld()->SpawnActor<AActor>(sc); // スポーン処理
    a->SetActorLocation(FVector(-600,200,200)); // 確認しやすいように座標を設定
}
```

この方法のデメリットは、記述箇所が複数に渡るのと、コンストラクタに引数をつけることが若干手間であるのと、コンストラクタ内に処理を記載しなければならないため不便であることである。

## その他
上記の方法以外にも、アクター自体をC++で記述してスポーンする方法もあった。アクターのスポーン自体は非常に簡単な記述になるが、アクターに様々なスタティックメッシュコンポーネントやマテリアルを設定するときにコードで記述すると見た目の調整が難しいことが課題であった。

# まとめ
繰り返しになってしまうが、最初に紹介した手法が以下の点で優れているため、アクターをスポーンするときの参考にしてほしい。

- アクターブループリントのパスを変数とすれば任意のアクターを動的生成できる
- 記述、振る舞いともにシンプル

# 最後に
ヒトやモノをデータ化＆解析してみたい、という方。
３D技術と深層学習を組み合わせて、何か面白いサービスを作ってみたい！、という方。

弊社では一緒に働いてくれる仲間を大募集しています。

ご興味がある方は下記リンクから是非ご応募ください！
https://about.sapeet.com/recruit/

# 参考
[アクタのスポーン](http://api.unrealengine.com/JPN/Programming/UnrealArchitecture/Actors/Spawning/)
[Unreal Engine Spawn Blueprint Actors with C++](https://www.youtube.com/watch?v=Z-mbe4k5Wa4)
[UE4: C++ コード から C++ クラスまたは Blueprint のアクターを FindObject して SpawnActor する方法](https://usagi.hatenablog.jp/entry/2017/10/17/123000)