ECS(Entity Component System)導入

この記事はUnityのEntity Component Systemを紹介する記事です。
AWSのElastic Container Serviceに関する内容ではありませんのでご注意ください。

Unityのバージョンは2018.4.11で試しています。

# ECSとは？

ECSとは「エンティティ」「コンポーネント」「システム」の三つの要素からなるソフトウェアアーキテクチャパターンです。 
ゲームプログラム全体を大きく三つの要素に分解して、それぞれの責務や関係性を規定することでゲームを管理しようというものです。
Web出身のエンジニアにとってはMVCの様な物とイメージすればスムーズに理解できるかと思います。

## Entity
ゲーム世界のモノを表します。
エンティティ自体は機能を持たず(持たせてはいけない)、これをシステムが操作します。

## Component
コンポーネントは、Entityの追加情報です。誤解しやすいのはオブジェクトとして独立していなく、単なるデータであることです。 
位置情報、HP等といった状態それぞれがコンポーネントとなり、 エンティティに関連付けられます。
個人的にComponentの理解が結構難しいと感じました。MVVMでいう、VとVMの関係がEntityとComponentの関係に近いと感じています。
※違う場合ご指摘いただけると大変ありがたいです。。。

## System
Webアプリで言うところのロジック、ゲームで言うところの仕様を実現するための物です。
従来のやり方であった、StartやUpdate系はこちらにあたります。

概念的な説明は以上です。
説明を省いてしまいましたが、C#からUnityに移ってきた人が一番驚くのは**クラスではなく構造体を使う事でパフォーマンスを上げる**というアプローチだと思います。

「C#でゲーム作るってパフォーマンス的に大丈夫なの？もっとエンタープライズ向けの言語なんじゃないの？」
って言う疑問に解決するための技術なのではないかととても期待しています。

それでは、実際にECSに触れてみましょう。

# 事前準備

## Entitiesのインストール

UnityのPackage Manegerから、Entitiesをインストールしましょう。
※現在プレビュー版のため、検索しても出てこない場合はプレビュー版の表示を許可しましょう。
![Entities.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/b92141a3-e5a2-8b09-ccd5-c41cec5df22f.png)

## PlayerSettingsの設定

PlayerSettings - Other Settingsを、下の画像の通りにしましょう。
![configuration.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/26144a9b-e9ba-3342-4f60-aa707c5c345f.png)
※Scripting Define Symbolsに「UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP」を書き加え、余計な物が自動生成されない設定を推奨している記事もありますが、本当に初めて触るなら追記は不要と思います。


## .Netの設定

Unity 2018.4.11でScriptを生成したら、ターゲットフレームワークが4.7.1のため開けない警告が出ました。
このバージョンに関わらず、上記警告を回避するためにはVisual Studioのツール→ツールと機能を取得から取得しましょう。
![VisualStudio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/775c0235-f75e-fcd5-f98c-8dacb9dbd825.png)

## GameObjectにEntityを追加する。

追加したGameObjectをEntityとして扱うには、Game Object EntityをAdd Componentする必要があります。
![AddEntity.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/882fab44-bf50-6777-01f4-09c3f0a83607.png)

下に書くコードの例ではCubeを追加していますので、Cubeを追加してもらうと結果が分かりやすいと思います。

## 表示しておくと便利

Entity DebugerというEntityの状態を監視する機能がUnityから提供されています。
何か問題が発生した際にこれがないと原因が分かりづらいので、ぜひ追加しましょう。
![ViewEntityDebugger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/187a556e-a465-9296-36d0-89c2a45973c1.png)

こんな感じでEntity一覧を見る事が出来ます。
![EntityDebuger.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36448/9558366b-c650-3a3f-000b-a6d5a0baed9a.png)



# コードの比較

Cubeをくるくる回すScriptを非ECS(従来型)とECSで書いてみます。

## 非ECS(従来型)の場合

```csharp:notECS.cs
using UnityEngine;

public class NotECS : MonoBehaviour
{
	public float speed;

    // Update is called once per frame
    void Update()
    {
		transform.Rotate(0f, speed * Time.deltaTime, 0f);
	}
}
```

特段解説の必要がないonce per frame毎に呼ばれるupdateメソッド内でy方向の角度を変えています。
ではこの何の変哲もないコードを、ECS版に書き換えます。

```csharp:UseECS.cs
using UnityEngine;
using Unity.Entities;

public class UseECS : MonoBehaviour
{
	public float speed;
}

class UseECS_System : ComponentSystem
{
	struct Components
	{
		public UseECS useECS;
		public Transform transform;
	}

	protected override void OnUpdate()
	{
		foreach(var e in GetEntities<Components>())
		{
			e.transform.Rotate(0f, e.useECS.speed * Time.deltaTime,0f);
		}
	}
}

```

単純なコードを例にしても、なかなかに大きな変更を強います。
従来プロパティとメソッドを同じクラス内で書いていましたが、
Entity(入れ物)とComponent System(振る舞い)に綺麗に分ける事が求められます。

個人的には非常に読みやすいし、手続き型からオブジェクト指向へ移行する時と同じ頭の使い方で移行可能と思います。
※ECSはパフォーマンスアップというとても分かりやすいメリットがあるため、やるだけ得だと思います。

導入としてはここまでです。触れてない内容が沢山あるので、次はもう少し詳しい内容を書きます。
一読くださりありがとうございました!!