1. 程式人生 > >Unity ECS學習筆記(一)

Unity ECS學習筆記(一)

ECS架構概述

ECS術語

實體Entity:像容器一樣

元件資料Component Data:要儲存在實體中的資料(不包括處理)

元件系統ComponentSystem:處理

組Group:元件系統執行所需的ComponentData列表

Unity官版ECS主要特徵如下:

  • 資料和行為分離
  • 在通常的Unity開發中,我們會將Monobehavior元件掛載到一個Gameobjec上,而ECS中,則將設計為將組建附加到Entity上
  • 使用一個池子(pool)來存放所有的Entity
  • 可以給Entity設定分組(group)
  • 通過matcher來獲取指定的Entity

ECS與Unity的GameObject /Component相比,有一個稍微接近的地方。如果完全粗略地說明,則它與以下專案匹配。

Entity=GameObject

ComponentData =Component的欄位

ComponentSystem =Component的Update方法

Group = 無

 

環境

需要環境如下:

  • Unity 2018及以上,理論上2017的最後幾個版本也可以,主要是要支援.net 4.6
  • 安裝ECS包

步驟

  • 下載最新版Unity,建議官方下載
  • 開Unity,新建一個專案:
  • 進入Unity後,設定.net版本:依次點選File - BuildSetting - PlayerSetting - Other Setting - Scripting Runtime Version 設定為.NET 4.x Equivalent,會提示重啟,點Restart重啟Unity即可。
  • 開啟專案目錄(即建立專案的資料夾),找到Packages目錄,並找到裡面的manifest.json檔案

  • 開啟manifest.json檔案,並將以下內容複製進去,並儲存:
{

"dependencies": {

"com.unity.entities": "0.0.12-preview.5"

},

"registry": "https://packages.unity.com",

"testables": [

"com.unity.collections",

"com.unity.entities",

"com.unity.jobs"

]

}
  • 在此進入Unity的環境時,會進行下載ECS包和匯入,匯入完成後,我們會發現頂部選單欄多了Jobs項,

  • 選單欄開啟Window - Packages Manager 也可以看到Entities已經安裝:

 

  • 例一:
  • 接著我們來寫個讓cube旋轉的測試樣例:
  • 新建一個Rotator.cs指令碼

程式碼如下:

using UnityEngine;

public class Rotator : MonoBehaviour {

    public int speed;
}
  • 沒錯,這個指令碼繼承自monobehavior,但是,他就只有一個欄位,即,只有資料
  • 再新建一個類,叫RotateSystem.cs,這個類我們讓它繼承ECS
using Unity.Entities;

public class RotateSystem : ComponentSystem

{

}
  • ComponentSystem來自Unity.Entities名稱空間,所以,在開頭需要進行引用。
  • 建立一個結構體,作為容器來儲存資料:
struct Components

{

    public Rotator rotator;

    public Transform transform;

}
  • Rotator就是上面建立的資料類,同時這裡還存了一個transform,因為我們需要使用transform的例項方法
  • 因為繼承了ComponnetSystem,所以這個類還需要實現基類的一個OnUpdate方法:
protected override void OnUpdate()

{

}
  • 這個方法同monobehavior一樣,也是每幀呼叫。
  • 在這個方法中,我們遍歷下場景的所有Entity,使用GetEntities介面進行遍歷即可
foreach (var item in GetEntities<Components>())

{

}
  • 然後就是對遍歷出來的子項做一些行為操作:
foreach (var item in GetEntities<Components>())

{

    item.transform.Rotate(0f, item.rotator.speed * Time.deltaTime, 0f);

}
  • 到這裡,程式碼算是告一段落了,我們需要在Unity中進行一些操作設定
  • 在Unity介面下的Hierrarchy視窗下右鍵建立一個Cube,然後掛載Rotator.cs指令碼
var deltaTime = Time.deltaTime;

foreach (var item in GetEntities<Components>())

{

    item.transform.Rotate(0f, item.rotator.speed * deltaTime , 0f);

}

 

  • 再給cube新增一個GameObjectEntity指令碼(ECS系統內建指令碼,不需要你自己寫)
  • 現在點選執行,並給cube身上的rotator指令碼設定speed的值,cube就可以轉起來了。
  • 你可以多複製幾十或者幾百個測試下效率。
  • 當然,上面那個遍歷指令碼還可以優化一下,就是將Time.delaTime快取一下,而不是放到迴圈裡去,
  • 最後我們可以通過Windows->Debug->Entity Debugger來檢視下資訊

例二:

建立一個Cube作為Player,點選Add Component新增GameObjectEntity指令碼,然後編寫InputComponent指令碼,編寫程式碼並新增的Cube上。

程式碼就這麼簡單,ECS中Component是資料容器,僅包含與Entity相關的值欄位。

using UnityEngine;

public class InputComponent : MonoBehaviour {

    public float Horizontal;
    public float Vertical;
}

接下來編寫移動的System,我們新建一個MovementSystem,用來做對移動行為的控制System

using Unity.Entities;

public class MovementSystem : ComponentSystem {

	private struct Components
    {
        public Transform Transform;
        public InputComponent InputComponent;
    }


	protected override void OnUpdate ()
    {
        var deltaTime = Time.deltaTime;
        var speed = 10.0f;

        //遍歷所有的所有包含結構體中元件的Entity
       foreach(var e in GetEntities<Components>())
        {
            var vector = new Vector3(e.InputComponent.Horizontal, 0, e.InputComponent.Vertical);
            e.Transform.Translate(vector * deltaTime * speed);
        }
    }
}

然後是InputSystem,程式碼如下:

using Unity.Entities;

public class InputSystem : ComponentSystem
{
	private struct Data
    {
        //結構體長度,即資料數量
        public readonly int Length;
        //獲取所有包含InputComponent的陣列
        public ComponentArray<InputComponent> InputComponents;
    }

    //Unity會自動注入滿足此欄位的物件
        [Inject] Data data;

    protected override void OnUpdate()
    {
        var horizontal = Input.GetAxis("Horizontal");
        var vertical = Input.GetAxis("Vertical");

        for (int i = 0; i < data.Length; i++)
        {
            data.InputComponents[i].Horizontal = horizontal;
            data.InputComponents[i].Vertical = vertical;
        }
    }
}

我們可以通過Entity Debuger來檢視下資訊,可以看到InputComponent下成功找到Entity 0這個物件了,說明我們的注入是成功的。

按下上下左右按鍵,我們的方塊成功移動起來了,可以看到使用ECS,我們Entity物件上僅僅只有包含資料的Component,而我們無需關心其他System是如何運作的,每個System只關心自己本身的實現就行了。