いんでぃーづ

ゲームいろいろ、いろいろ自由

Unity : ECS全然わからない状態から、とりあえず使えるようにする

ECSわかった系のスライドを読んでもよくわからなかったので、これはもう実際書いて覚えるしかないと思ったので書いてみました。
今回はGameObjectにつけた自作スクリプトをECSから操作するいわゆる HybridECS をやります。

環境:Unity2019.1.7
ECS preview.33 - 0.0.12

ECSを使えるようにプロジェクト設定

.Net4 を使う設定

メニューから File > Build Settings と選択し、ダイアログで Player Settings をクリック。

Other Settings 欄の Scripting Runtime Version で .Net 4.x Equivalent を選択する。

リスタートのダイアログが出てくるので Restart をクリック。

Entitiesパッケージのインストール

メニューから Windows > Package Manager で パッケージマネージャ を表示し、

  1. Show preview packages を有効に
  2. Entities を選択
  3. Install !

f:id:sugar_affordance:20190217072358p:plain
Entitiesパッケージ設定

Entityパッケージがインストールされていれば Packages/manifest.json に以下の行が追加されています。
パッケージマネージャからではなく、直接1行追加してもおk。

{
  "dependencies": {
    ...
    "com.unity.entities": "0.0.12-preview.33"
  }
}

自分の環境だとこのままだとエラーが出ていたので、

f:id:sugar_affordance:20190217074216p:plain

Assembly has reference to non-existent assembly 'Unity.PerformanceTesting' (Packages/com.unity.entities/Unity.Entities.PerformanceTests/Unity.Entities.PerformanceTests.asmdef)

Packages/manifest.json の末尾に以下を追加してエラー回避できました。

{
  "dependencies": {
    ...
    "com.unity.test-framework.performance": "0.1.49-preview"
  },
  "registry": "https://packages.unity.com",
  "testables": [
    "com.unity.entities",
    "com.unity.test-framework.performance"
  ]

ECSを使って実装してみる

今回はHybridECSですがECSだけで構成する Pure ECS というものもあるが、とりあえず今は使う予定がない。

Component スクリプトを作成

ふつうのコンポーネントを作るようにスクリプトを作成する。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ECSTestComponent : MonoBehaviour {

    public float speed;

}

インスペクタでオブジェクトごとにspeedに違う値を設定すると、違う動きにできます。

このスクリプトをふつうに GameObjectにつけます。 また、 Game Object Entity コンポーネントも同時にアタッチする。

f:id:sugar_affordance:20181028080612p:plain:w500

ComponentSystemスクリプトを作成

スクリプトを新規で作成し、

  1. まず using Unity.Entities; を先頭に追加。
  2. ComponentSystem クラスを継承させる。
  3. OnUpdate をオーバーライドしたり、操作したいコンポーネントをメンバに持つ構造体を定義したりする。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using Unity.Entities;

public class ECSTestSystem : ComponentSystem
 {
     struct TestComponents {
         public ECSTestComponent target;
     }

     protected override void OnUpdate()
     {
         foreach(var e in GetEntities<TestComponents>()) {
             // オブジェクトごとに回転させる
             e.target.transform.Rotate(
                0,
                e.target.speed * Time.deltaTime,
                0);
         }
     }

}

これはオブジェクトにアタッチさせる必要はありません。

Worldを自作する

ECSは World という単位でシステムを分けることができ、デフォルトでWorld作成されるが Editor上でも有効 になってしまい、TestRunner でシーンをロードする類のテストを実行したときに以下のようなエラーが吐かれた。

f:id:sugar_affordance:20190707100743p:plain

InvalidOperationException: Unity.Entities.SimulationSystemGroup has already been destroyed. It may not be used anymore.
Unity.Entities.ComponentSystemBase.CheckExists () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:334)
Unity.Entities.ComponentSystemBase.ShouldRunSystem () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:352)
Unity.Entities.ComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:801)
Unity.Entities.ComponentSystemBase.Update () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:287)
Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelegateWrapper.TriggerUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ScriptBehaviourUpdateOrder.cs:135)
InvalidOperationException: Unity.Entities.PresentationSystemGroup has already been destroyed. It may not be used anymore.
Unity.Entities.ComponentSystemBase.CheckExists () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:334)
Unity.Entities.ComponentSystemBase.ShouldRunSystem () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:352)
Unity.Entities.ComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:801)
Unity.Entities.ComponentSystemBase.Update () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:287)
Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelegateWrapper.TriggerUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ScriptBehaviourUpdateOrder.cs:135)

のでデフォルトのWorldは無効にして自分で作成するのがいいと思います。
Project Settings の Player の Scripting Define Symbols に以下を定義して、デフォルトで作成されないようにする。

UNITY_DISABLE_AUTOMATIC_SYSTEM_BOOTSTRAP;

f:id:sugar_affordance:20190707100712p:plain

World はスクリプトで以下のように作成します。

    static World MyWorld;
    static PresentationSystemGroup mySystemGroup;
    static ECSTestSystem testSystem;
    public static void CreateWorld() {
        if (MyWorld == null) {
            MyWorld = World.Active = new World("MyWorld");
            mySystemGroup = MyWorld.GetOrCreateSystem<PresentationSystemGroup>();
            testSystem = MyWorld.GetOrCreateSystem<ECSTestSystem>();
            mySystemGroup.AddSystemToUpdateList(testSystem);
            ScriptBehaviourUpdateOrder.UpdatePlayerLoop(MyWorld);
        }
    }

PresentationSystemGroup#AddSystemToUpdateList でComponentSystemを登録することでOnUpdateが呼ばれるようになるので忘れずに書きましょう。

不要になったWorldは削除します。

        ScriptBehaviourUpdateOrder.UpdatePlayerLoop(null);
        MyWorld.Dispose();
        MyWorld = null;
        World.Active = null;

ECSの登録を確認する

メニューから Window > Analysis > Entity Debugger とクリックすると、ECSの状態がわかります。

f:id:sugar_affordance:20181028081217j:plain:w500

f:id:sugar_affordance:20181028081257p:plain

使い方はまだよくわからん。

ゲームを実行する

ひとつの ComponentSystem スクリプトからまとめて複数のオブジェクトを回転させている。

f:id:sugar_affordance:20181028081331g:plain


・参考

Introduction to ECS - Unity

公式GitHubのECSサンプルとかもあります。

GitHub - Unity-Technologies/EntityComponentSystemSamples


“Unity” and Unity logos are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere, and are used under license.


免責事項

当サイトの広告バナー、リンクによって提供される情報、サービス内容について、当サイトは一切の責任を負いません。

また、当サイトの情報を元にユーザ様が不利益を被った場合にも、当サイトは一切の責任を負いません。

すべて自己責任でお願いします。