【Unity DOTS】ECSを始めるには

こんにちは、Densyakunです。
Unity ECSを始めるために必要な準備、注意点について紹介します。

この記事では、自分がUnityでECSをやろうと思ったときに、困ったことなどがたくさんありましたので、
見つけたことなどを紹介しています。
少しでも参考になれば幸いです。

#### 注意
- UnityのECSは2019年7月現在開発中の機能で、情報が少ないです。Unityに慣れていない人には向いていません。（と言っても、この記事を見ている人は、向いていると思いますが。）
 - 沼が多く、とっつきにくいです。ですが、早いうちにやっておくと良いと思います。
 - **Unityのゲームを高速化する上では必要**とも言える機能です。特に、**大量のオブジェクト**を追加、管理、動作するゲームにはECSを導入することをおすすめします。実際に**約5倍の高速化**を図ることができます。（C# Job System、Burst使用の場合）
 - **Unityのバージョンは最新版（Beta版！！！）にしてください。でないと古いバージョンのECSしか利用できません！！（後述）**
- 私はECSについてはあまり詳しくありません。高速化について調べているうちにECSを知り、始めました。
- 推測もありますので、正確な情報ではない可能性があります。あくまでも参考程度に見てください。

## Entity Component System (ECS) とは
- 簡単に言うと、（コンピューターにとって効率かつ高速な動作をするための）ゲームの設計、考え方のようなもの
- Unityに限る話ではない（Unityで導入するECSをUnity ECSと呼ぶ）
- HYBRID ECS と、 PURE ECS がある。HYBRID ECSは従来のシステムとECSを混ぜたもので、PURE ECSは完全にECSによってできたゲームらしい（私はよく分かっていない）。

## Unity ECS について
- **開発中の機能**であるため、使い方が変わる可能性が高い
 - 以上の理由から、**使い方などの情報が殆ど無い**ため、使い方を自分で調べる必要がある（クラスやメソッド、パッケージが違ったり、名前が変わってたり、ググってもわからんなので、パッケージの中からそれっぽいのを探して見つける）

まずはじめに、なんとなく理解するために、こちらの記事を見ることをおすすめします。
http://tsubakit1.hateblo.jp/entry/2018/03/25/180203

ECSの仕組みは説明すると難しいのですが、
簡単に説明すると、ECSは処理をCPUやメモリの特性に合わせることで高速化します。

なのでおそらく、従来のScriptのような使い方をしたり、MonoBehaviourと連携することは向いていません。
uGUIなどの従来のものは、従来の方法で作ってください。

# Unity ECS の使い方

## Unityを最新版にする（ココ重要）
ECSを利用するにはUnityプロジェクトにパッケージを導入する必要がありますが、
2019年6月現在Unity 2018.4.1f1ではEntities 0.0.12-preview.24が最新バージョンとなってしまいます。

**preview.32などの最新のECSを利用するためには、Unity2019を利用する必要があります。**

現在、Unity2019はベータ版となっています。
UnityからHelpを押してDownload Beta...を押すと、ダウンロードページに飛びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/236865/b51afb1a-5113-5b0c-eeab-7bc17d305262.png)
**またはこちらからページに移動してください。**
https://unity3d.com/unity/beta

「**Join our Open Beta program**」を押すと最新版のダウンロードページに移動します。
ページ上部の「**Download Unity** （バージョン）」を押すとページ中間に移動します。

現在のバージョンを利用するには、**Unity Hubというランチャー**が必要になりました。
**Unity Hubを持っていない方**は、「**Download Unity Hub**」を押してください。
Unity Hubを持っている、もしくはUnity Hubをインストールしたら、
「**Install version from Unity Hub**」を押すと、Unity Hubで最新版がダウンロードされます（ボタンを押すとブラウザで警告が出る場合がありますので、確認してください）。



あとは、Unity Hubの方でインストールの設定をしてください。

## 必要なパッケージをインストール
Unityの**Window->Package Manager**からパッケージをインストールできます。

Package Managerの上の「All packages」または「In Project」となっているところを押して、
「**All packages**」にしてください。
ここが「All packages」だとすべてのパッケージ、
「In Project」だとプロジェクトに導入されているパッケージのみが表示されます。

その横にある、Advancedを押して、**Show preview packages**を押して、
プレビュー版のパッケージを表示するようにしてください。
Unity ECSにおいて必須なEntitiesパッケージは現在プレビュー版となっています。

そしたら、必要なパッケージを導入してください。

### ECSに関する主なパッケージ
- Entities（**必須**）
- Jobs
 - C# Job Systemというもので、合わせて使うと更に高速化できます（ここでは解説しません）。
- Burst
 - これも合わせて使うと、**更に高速化**することができます（ここでは解説しません）。
- Mathematics
 - 計算によく使うため、入れといたほうが良い
- Hybrid Renderer
 - ECSで従来のMeshやMaterialを使ってメッシュを描画するには、これがあると便利になる
- Unity Physics
 - ECSでは従来の物理シミュレーション（PhysX）が利用できない
 - ECSで重力や衝突をシミュレーションするにはこれを使う

## GameObjectとの違い
Unity ECSではGameObjectなどと分離されたシステムで、
Scriptが止まっていてもECSは動作します。

Unity ECSは主に**World**、**ComponentSystem**、**Entity**、**Component**などにより構成されています。
これを見ると仕組みや使い方などが詳しくわかります。
[【Unity】 ECS まとめ（前編） - エフアンダーバー](https://www.f-sp.com/entry/2019/04/18/175747)

**World**（ワールド）は従来のScene（シーン）のようなものです。
全てはWorldの中で動作します。

**Entity**（エンティティ）は英語で実体のことです。従来のGameObjectのようなものになります。

**Component**（コンポーネント）はEntityが持っている**データ**になります。

**ComponentSystem**（コンポーネントシステム）は、World内で実際に処理を行うものになります。
Systemとも呼ばれます。
SystemがEntityが持っているComponentをいじることで、
Entityに働きを持たせることができます。

ほかにも移動や時間などの各機能別にSystemを作成することでゲームを動作させることもできます。

Entityは**EntityManager**が持っています。
EntityManagerはEntityを管理するSystemです。
EntityはWorldが持っているものではありません。

## 基本的な使い方
### Worldを作成する
[ソース](https://gist.github.com/Densyakun/34324fd89d0500d33d00659c7fcfede7)
Worldを作成しEntityManagerを追加するScriptです。
OnDisableでWorldを破棄しています。

Worldは複数作成する事ができますが、推薦されていません。

#### 自動的に追加される Default World
初期の状態では、**Default Worldが自動的に追加**されていますが、
Worldを自作する場合は無駄になることや、**すべてのSystemがすでについている**ため、高速化の観点から**不要**だと言われています。

**Project Settings**の**Player**の**Other Settings**にある、
`scriptingDefineSymbols`に、`UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP`を追記して**Enterを押して**少し待つと、
**Default Worldを自動的に追加しないように設定できます**。
scriptingDefineSymbolsに複数記入する場合は、`;`で区切ることができます。

### MeshとMaterialの描画について
**2019年7月現在、以前の方法ではできません。（`EndFrameTransformSystem`と`RenderingSystemBootstrap`がない）**
MeshとMaterialの描画については今後見つかり次第追記します。

### Physicsについて
Unity Physicsパッケージが必要です。
こちらを参考: （テラシュールブログ）

# ComponentSystemのメソッド
ComponentSystemでは主に**OnUpdate**メソッドをオーバーライドして処理を行いますが、
それ以外にもメソッドは存在します。

以前とは名前が変わっているのですが、
`OnCreate`、`OnDestroy`、`OnStartRunning`、`OnStopRunning`があります。
以前はOnCreateManagerとOnDestroyManagerという名前でした。

**OnCreate**は、
World.CreateManager()などによりSystemが作成されたときに呼び出されます。

**OnStartRunning**は、
ScriptBehaviourUpdateOrder.UpdatePlayerLoop(World)を実行するときに呼び出されます。

**OnUpdate**は、
ScriptBehaviourUpdateOrder.UpdatePlayerLoop(World)を実行してから、
ScriptBehaviourUpdateOrder.UpdatePlayerLoop(null)を実行するまでの、
フレームごとに呼び出されます（MonoBehaviourのUpdateのようなものです）。

**OnStopRunning**は、
World.Dispose()を実行すると呼び出されます。
（**ScriptBehaviourUpdateOrder.UpdatePlayerLoop(null)では実行されません**）。

**OnDestroy**は上記と同じく、
World.Dispose()を実行すると呼び出されます。

処理順は、
OnCreate->OnStartRunning->OnUpdate (毎フレーム繰り返し)->OnStopRunning->OnDestroy
となります。

# こちらも参考
解説はここまでとなります。
詳しく知りたい方はこちらをご覧ください。

- [Unity DOTS の概要 - npaka](https://note.com/npaka/n/n4b61fe4d3087)
- [公式のドキュメント](https://docs.unity3d.com/ja/current/Manual/PackagesList.html)
- [Unity:はじめてのECS](https://qiita.com/simplestar/items/17b0886be0170f79aa2e) 古いバージョンのため、Hybrid Rendererが現在非対応
- [【Unity】Entity Component System入門(その1)【2018.2】](https://qiita.com/pCYSl5EDgo/items/caac60ee41058cde085a) 古いバージョンのため、Hybrid Rendererが現在非対応
- [【Unity】 ECS まとめ（前編） - エフアンダーバー](https://www.f-sp.com/entry/2019/04/18/175747)
- [【Unity】新しい物理演算、Unity Physicsについて](http://tsubakit1.hateblo.jp/entry/2019/04/20/231339)

# Entitiesにあるはずのものがない場合
現在の大きな問題点はここにあります。
実際使ってみようと思うと、Entitiesにあるはずのものがなくなっていたり、名前が変わっている場合があります。

ネット上には情報が少ないので、
パッケージの中に似ている名前のものがないか、パッケージが変わってないかなど、自力で調べてください。
見つけたらコメントに書いてもらえると助かります。

それか、もしかするとUnityのバージョンが古いのではないでしょうか。
冒頭にある通り、Unityを最新版（**ベータ版**）にしてください。

私は最初、Unity2019がベータ版であることを知らなかったので、
冒頭にある通り古いバージョンが最新版であると思っていました。
この記事を書いている途中でそれを知りました。
全部コードを書き直さないと...

# `A Native Collection has not been disposed, resulting in a memory leak. Enable Full StackTraces to get more details.`と表示される
エディターで、ゲーム実行中にScriptなどのファイルを更新した際のコンパイルで表示されることがあります。
私の環境ではECS側から、このエラーが最低で4つ出てきます。

これは、NativeArrayなどが、Disposeされていない事により、メモリーリークが発生するというエラーです。
このエラーは、ゲームの動作にはあまり問題はありません。

ECS側の問題で出てくる場合があるので、
気になりますが、今のところは修正されるまで気にしなくて大丈夫です。

ただし、自分の書いたコードでNativeArrayなどを使用している場合は、
高速化が悪くなるので、正しくDisposeするよう注意してください。

# さいごに
ここで紹介したものはほんの一部になります。

少しでも参考になれば幸いです。

ご覧いただきありがとうございました。