元Unity使いがUE4を使っているお話

令和初のインフルエンザで謹慎してるので記事を書きます。

訂正：12月18日、非同期とRxの部分について訂正しました。

まず簡単に自分の経歴を紹介します。

・Unity歴：Unity3.5～Unity5.6まで5年ほど仕事で2DアクションとRPGがっつり
・UE4歴：UE4.19～UE4.23で1年半ほど仕事、3DアクションとRPGがっつり

今回は通信回りは抜き、クライアントの話で話します。
またUnityのDOTSについては私は明るくないので、MonoBehaviourに慣れ親しんだ人向けになります。
あと私はUE4を根っこまで調べてるようなハッカーでもなく広めようとしてるエヴァンジェリストでもないし、C++も11世代で止まってるのですが、好きな部分もあるし、いいなと思っている部分もあるので、とりあえず自分がUnityからの移行で躓いたようなところを書いています。
若干口調が断言的ですがエンタメだと思って読んでください。

# 心得

UE4とうまくやるコツは「動かなくても寛大な心でエラー文を読んで、何を言ってるかわからなくてもとりあえず対応していく」です。

# UE4はオープンソース

UE4はコードがすべてGitHubに上がっています。
ただEpicGamesにお願いしないとリポジトリは見られないので、Organizationに入れて～とお願いしましょう！
ちなみにEpicGames Launcherからであればビルド済みのUE4をインストールできます。

単純に触りたいだけであればLauncherからDL、エンジンの中身ちゃんと見たいとか、製品でちゃんと作る場合はGitHubからソースコードを落として自前ビルドするのがオススメです。

# 環境と言語とガベコレ

OSはWindowsオススメです。
ちょっと後で理由を説明します。

UE4の使用言語はC++です。
UE4オススメのIDEはVisualStudioです、UE4.23の時代ならVS2019でいいでしょう。
Windows 10 SDKが必要ですが、面倒ならVisualStudio Installerでこれにチェック入れておけばOKです。たぶん。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330809/32cc7b0a-fefc-d2da-6b70-c16de087e4e0.png)

で、C++だとメモリ管理大変なのではないかというお気持ちがあるのですが、UE4の文法にちゃんと乗っている限りはガベコレが効きます。
というより、STLは基本的には使いません、使う場合もありますが。
あとC++のバージョンはコンパイラにもよりますが、~~C++ 11と思っておいてください~~4.22からC++17にも正式対応しているそうです。
ご指摘ありがとうございます。

コンパイラにもよるというのは、某コンシューマ機向けやiOSならClang、普段はVCとかだからです。
なのでWindowsで通っていてもiOSでビルド通らないとかいう話は普通にあります。

https://forums.unrealengine.com/development-discussion/engine-source-github/25515-using-clang-to-compile-on-windows
WindowsでもClangにするという技もありますが、記事が古いのと自分はまだ試せていないので割愛します。

で、C++とは別にBlueprintっていう魔法の言語があります。
https://docs.unrealengine.com/ja/Engine/Blueprints/index.html
あとで詳しく話しますが、Blueprintは癖が強いので使いどころはちゃんと考えましょう。

## ソースコードからビルドする

用意するもの

・Ryzen 9 3950X以上のCPU
・DDR4-2666 32GB以上のメモリ
・NVMe対応の爆速SSD 512GB以上
・GitHubとやりとりできる一式
・VisualStudio
・折れない気持ち

macだと500万コースですね、知らんけど。
CPUはゲーム用がいいと思います。
メモリは16GBだとそもそもビルド通りません。
~~UE4はオープンソースで無料とは…~~

SATAのSSDならまだ希望はありますが、HDDは廃棄処分の業者に投げてください。
容量ですが平気で200GBとか持っていくので、定期的にお掃除が必要です。
信じらんない？ちょっと試そうとしただけでこの状態だぜ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330809/ff451aab-4a6e-c8f3-e05c-2161967097c8.png)

CloneはDepth=1でReleaseブランチを取得すると今の最新のリリース版が取れるはずなので大丈夫。

ちなみに当方のPCですがお金が足りずRyzen 5 3600Xです、サンタさんお待ちしております。
HDDでわざとやってみたんですが、Cloneから起動まで一晩コースです。

EpicGames Launcherからなら1時間弱のDLさえがんばれば大丈夫のはずです。

## ソリューションの作り

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330809/12021e83-89dd-d96d-ecd1-90f543da691a.png)

こんな感じで、UE4というエンジン側のプロジェクトと、Project（これは任意の名前にできる）という自分のプロジェクトができます。
基本はこっちの自分用のプロジェクトにソースコードを追加していきます。

# 実際にUE4を使ってみる

簡単なところはUnityとUE4のまとめみたいなのがあると思うので割愛します。
アウトラインがヒエラルキで、コンテントブラウザがプロジェクトみたいな感じです。
Unity使っていると「あーあれね」みたいな機能がたくさんあります。

## シーンに変わるものはレベル

これは似たような感じに受け取れると思います。
Unityではマルチシーンでシーン分割をしますが、UE4ではサブレベルという仕組みでシーン分割をします。
サブレベルを使うことでオープンワールドのようなものの分割読み込みをする感じです。

また、各レベルにGameModeというものが設定でき、GameModeに必要な情報（出現している敵への参照など）を持っておくと便利です。
GameModeは各レベルでレベルが遷移されると消えるのですが、ゲームの起動時から終了時までずっといるやつもいて、そいつはGameInstanceになります。
自分はGameInstanceにマスタやユーザデータ、通信のクライアントなどを登録して各所から引けるようにしています。
この辺はUnityにはない便利な機能なので覚えておくといいでしょう。

## uGUIに変わるものはUMG

uGUIもトレンドとしては可変解像度というよりは、アンカーで位置指定と、縦(or横)の解像度を固定して倍率かけるというような感じだと思いますが、UMGもそうです。
コンシューマで使うことも多いので基本的にはフルHD基準ですね。
アニメーションもタイムラインを使うので、UnityのAnimator/Animationと似たような感じになります。

ただ、注意点としては、ボタンなどのパーツを参照する場合、Unityの場合はMonoBehaviourにpublic Buttonなどの変数を作って外から挿す、みたいなことをすると思うのですが、UE4の場合はボタンはWidgetというGameObjectのようなものに登録されます。
なのでクリックイベントはWidget経由で取得しないといけません。

~~UIや通信が主力になるスマフォゲームなどはUnityのほうが作りやすいと思います。~~

## 非同期とRxは~~ない~~あります

ここですが、訂正になります。
もともとUnityやってた人が～ということで、C#の言語機能として用意されている拡張メソッドや~~async/await構文が使えない~~、という意味で書いてたのですが、圧倒的に正しく書けてなかったです。
コルーチンとasync/awaitはSTL使えばできるそうです。
https://qiita.com/tan-y/items/ae54153ec3eb42f80638
https://qiita.com/tan-y/items/6033ab9e7298999bf214
MSがC++に提案してたところで記憶が止まっていました、すみません。
C++20で標準になるそうです。

まず、RxについてはReactiveXの1つにRxCppというのがあります。
存在は知っていたのですが、使ったことはないです。
ただこの手のライブラリをプロジェクトで使う場合、ほかのエンジニアも読み書きできるという前提で使うべきなので、その辺はプロジェクトの状況によって導入を決めてください。
私は興味はあったので、近いうちに個人で試してみようとおもいます。
https://github.com/ReactiveX/RxCpp

非同期についてはUE4の各仕組みで用意はされています。
非同期ロードなどはAPIとしてありますし、自前で非同期に処理を投げる場合もFAutoDeleteAsyncTaskなどを使用してスレッドの管理などはしなくてよくなっています。
https://docs.unrealengine.com/en-US/API/Runtime/Core/Async/FAutoDeleteAsyncTask/index.html

だた、ぶっちゃけコールバックな非同期APIが現役で、templateも満足にBPとのつなぎで使えず、RxをBPで使えないのって、それはもうないに等しいでしょう、と言うのが本音です。

~~UIや通信が主力になるスマフォゲームなどはUnityのほうが作りやすいと思います。~~

## GameObjectに変わるものはActor

レベルに配置されるすべてのものはActorというクラスを継承しています。
まんまUnityのGameObjectと一緒と思って大丈夫です。

## 物理エンジン

中身は普通にPhysxです、UnityはHavokになるんですっけ…
なんかオープンソースになってるらしいので気になる人はどうぞ。
https://www.unrealengine.com/ja/blog/nvidia-opens-physx-code-to-ue4-developers

## MonoBehaviourに変わるものはComponent

ここが実は一番大事で、Unityだと以下のようになると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330809/cf305b8e-0364-19e4-84c5-5b579f0c4b98.png)

Unityの某お人のブログを参考にしているわけではないです、単純に面倒くさいので手書きです…
GameObjectに多数の機能を持ったMonoBehaviourが張り付いているイメージです。
GameObjectはObjectを継承していますが、GameObjectはsealedクラスなので継承はできないです。
その代わりにMonoBehaviourで機能を簡単に追加できるようになっています。

UE4ではこの考えがガラッと変わります。
UE4には以下のようなクラスがデフォルトの継承関係であります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330809/9ae14f28-fc8e-3fe6-eb2f-a7c9aeb45471.png)

各説明は以下です。
ちなみにUE4にはPrefix/Surfix文化が色濃くあります。
基本はUXXXですが、Actorを継承しているものはAXXXになります。
郷に入れば郷に従え、従いましょう。

| クラス | 機能 |
|:---|:---|
| UObject | 基本のやつ |
| AActor | レベルに配置できるやつ |
| APawn | 入力やAIとかで操作できるやつ |
| ACharacger | SkeletalMesh持ってるやつ |

で、PlayerとNPCを作る場合はCharacterを継承したものを用意します。
MonoBehaviourでやるようなことを継承でやる部分が多いです。

じゃあComponentは何に使うのかというと、例えばPawnを継承したGateとACharacterを継承したNPC両方で使うような機能をComponentにします。
CharacterMovementなどはよく使うComponentになります。

# C++層とBlueprint層

Unityにはない概念として、コーディングで行う層と、ビジュアルスクリプティングで行う層が明確に分かれています。
できることは大差はないのですが、ここをちゃんと分離して考えられるようになると、UnityでMVPresenterを達成するときと同じような柔軟さが生まれます。
UnityでのViewはシーン上に配置されたもので、PresenterはMonoBehaviour、Model層はピュアC#のパターンが多いかなと思います。

## そもそもBlueprintについて

Blueprintが面倒なので略してBPといいます。
BPというとビジュアルスクリプティングのことだ、と思いがちなのですが、実際にBPという場合は「エディタで扱える形にした型、アクタ」という意味になります。
Blueprintの型は必ず何らかのC++のクラスを継承しています。
ACharacterを継承したBP_Npcを作るという感じです。
BPのクラスを作って初めてレベルに配置ができたり、初期値の設定ができたり、Componentの取り付けができたりします。
そしてそのBP_Npcの制御をビジュアルスクリプティングでできるわけです。

BPのいいところは、Unityと違ってデフォルトでリファレンスビューアという使用アセットの参照を取れるツールがあるのですが、C++経由で行うとこれが非常に厄介で、テスト用の画像が使われているのか使われていないのかわからなくなりがち、になります。
このリファレンスビューアを最大限発揮するためにはBP側で参照を持ちつつ、ロジックはC++で行うという戦略をとる必要があります。

## BPを作るときにはペアで基底のC++クラスを用意すること

ゲームを作るときに「3回殴ったら倒れる村人」を用意したいとします。
この時、BP側でACharacterを継承したBP_NpcというBPを用意します。
これだけだと不十分で、たとえば殴られた時のイベントなどを制御しなきゃいけません。

BP_Npcに処理を書けばいいじゃんとなりがちなのですが、これはMVPでのView層に書くようなものだと思ってください。
書けなくはないですが、あとから後悔するやつです。
BP側はイベントを取る程度にとどめておきましょう。

じゃあACharacterを拡張するのかという話になりますが、エンジン側のコードに手を入れるのはエンジン側のバグ修正をやるときや、機能を追加する自信があるときのみがいいです。
自分はエンジン側のコードまで追ってバグを治した程度しかないです。

じゃあベストの答えは何かというと、「ACharacterを継承したANpcを用意して、ANpcを継承したBP_Npcを用意する」です。
ANpcには殴られた時の具体的な処理やイベント、関数などを記述します。
で、BP側でイベントを取ってC++側の関数を呼びます。
BP側でイベントを取るのは簡単だからです。HogeAsObservableがないのです。
なので明確にどうというのはないのですが、C++側に寄せられるものはC++に、BP側はできるだけ薄く、を心がけるといいかなと思います。

ちなみにこのC++とBPの関係は先に述べたGameModeとGameInstanceにも適用できます。

## BPの使いどころ

BPの使いどころなんですが、実際BPだけで組んでパフォーマンスを出したプロジェクトなどもあるそうなんですが、大変そうなので個人的には基本はC++に寄せたほうがいいと思っています。
が、例外があり、ビジュアルスクリプティングで作業をする人たち、特にレベルデザイナやプランナの人たちはBPでフィールドのギミック（壊れる樽とか）を作ったりすると思います。
そういうときはC++で作られている部分とつなぎこむ部分（セーブデータへのアクセスAPIなど）を用意してあげたり、レビューをしてあげたりするといいと思います。
パフォーマンスの問題は常にあるので、その辺に注意してあげるのがいいです。

# まとめ

まず強いPCを買いましょう。
あとは耐えながら頑張りましょう。
UE4は楽しいぞ。

といいつつ、AControllerやBehaviorTreeやUE4のUnityビルド（クソややこしい）について何も話してないですね…
それはまたの機会に…