天天看點

ECS入門之Hello WorldECS中的Hello World總結擴充閱讀

洪流學堂,讓你快人幾步。你好,我是跟着大智學Unity的萌新,我叫小新,最近在探索DOTS。

由于ECS概念過于複雜,還是看看如何Code吧, 咱們先來看下如何編寫一個最簡單的ECS代碼。

ECS中的Hello World

這就又要從Hello World說起了。

首先需要把DOTS的環境搭好。本課程最開頭講了如何安裝Entities包,如果還沒安裝好需要去複習一下。

DOTS開發101

這個Hello World需要做什麼呢?咱們用ECS來控制一個Cube的旋轉。

ECS咱們已經知道了分三個部分,咱們來看看這三個部分如何建立。

1、E:在場景中建立一個Cube

按照和之前一樣的方法,在場景中建立一個Cube物體。

但這樣并不是ECS中的Entity,可以使用一個腳本

ConvertToEntity

,将GameOjbect轉換成Entity。

ECS入門之Hello WorldECS中的Hello World總結擴充閱讀

這個腳本有一個屬性:ConversionMode:

  • Convert And Destroy:将GameObject轉換成Entities,并且銷毀GameObject。
  • Convert And Inject GameObject:将GameObject轉換成Entities,保留GameObject。

咱們在這選擇Convert And Destroy。

這樣咱們就有了一個E,這時候如果你運作呢,你就會發現場景裡有一個Cube,但是在Hierarchy中看不到這個Cube。

那如何檢視這個Cube上面的資訊呢?這時候需要使用Entity Debugger。打開方式是:Unity菜單欄

Window > Analysis > Entitiy Debugger

ECS入門之Hello WorldECS中的Hello World總結擴充閱讀

2、C:建立Component

下面來建立Component,這個Component和原來MonoBehaviour繼承的Component不是一個東西。

ECS中的Component需要使用一個結構體,實作

IComponentData

接口。如下代碼:

[GenerateAuthoringComponent]
public struct RotationSpeed_ForEach : IComponentData
{
    // 旋轉的速度
    public float RadiansPerSecond;
}
           

這個結構體中定義了一個float類型的資料,代表旋轉速度。

那上面的那個

[GenerateAuthoringComponent]

是做什麼的呢?

正常情況下,ECS中的Component并不能直接拖到物體上跟物體綁定。但是加了

[GenerateAuthoringComponent]

屬性後,可以将這個Component拖到GameObject上,并在腳本

ConvertToEntity

轉換時,自動将Component和轉換出來的Entities綁定。

現在寫好了就把這個RotationSpeed_ForEach元件添加到Cube上面吧。

3、S:用System控制Cube旋轉

using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

// 這個系統會更新所有擁有RotationSpeed_ForEach和Rotation元件的實體
public class RotationSpeedSystem_ForEach : SystemBase
{
    // OnUpdate在主線程上執行
    protected override void OnUpdate()
    {
        float deltaTime = Time.DeltaTime;
        
        // 排程job來讓cube進行旋轉
        Entities
            .WithName("RotationSpeedSystem_ForEach")
            .ForEach((ref Rotation rotation, in RotationSpeed_ForEach rotationSpeed) =>
            {
                rotation.Value = math.mul(
                    math.normalize(rotation.Value), 
                    quaternion.AxisAngle(math.up(), rotationSpeed.RadiansPerSecond * deltaTime));
            })
            .ScheduleParallel();
    }
}
           

1、首先注意命名空間的引用,在ECS中并沒有引用比如

UnityEngine

這種在Mono中常見的命名空間。

通常引用的命名空間就是這三個:

using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;
           

2、實作一個class,繼承SystemBase,然後重寫父類SystemBase裡的

OnUpdate

方法。

OnUpdate

方法和Mono中的Update方法類似,都是每幀執行一次,然們可以在裡面做更新的操作。

3、

float deltaTime = Time.DeltaTime;

這句代碼用來擷取目前幀的時間,但是要注意這裡面的Time并不是

UnityEngine.Time

,而是父類中定義的的Time。一定不要用混了。

4、Entities.WithName僅僅是調試使用,調試資訊或者Profiler中會顯示這個名字,友善你找到對應的代碼。

5、核心代碼是Entities.ForEach中的代碼,ForEach的參數是一個lambda匿名方法。其中ref的參數表示會寫入,in的參數表示是隻讀的參數。注意這些參數的修飾一定要準确使用,這樣Job才能正确的判斷每種資料的用途。

ECS中有實體查詢(entity query),可以根據傳入的參數類型,找到所有同時擁有這些Component的實體。比如上面代碼就會找到同時擁有Rotation和RotationSpeed_ForEach元件的所有實體。

6、lambda中的方法執行具體的内容。在這需要**注意需要使用新的數學庫

Unity.Mathematics

**而不是原來的

UnityEngine.Mathf

。上面代碼中是用原來的旋轉,乘以需要旋轉的四元數,得到旋轉後的結果。

咱們場景中隻有一個Cube,是以查詢到的Entity就隻有一個。如果有多個Entity都符合條件,那麼這個System就可以同時處理這些Entity。

總結

好了,到這咱們的ECS Hello World就完成了,但是其中很多代碼為什麼這麼寫,以及背後的原理都沒有講清楚。後面咱們詳細拆解一下每一部分代碼,掌握ECS的核心。

擴充閱讀

【擴充學習】在洪流學堂公衆号回複

DOTS

可以閱讀本系列所有文章,更有視訊教程等着你!

呼~ 今天小新絮絮叨叨的真是夠夠的了。沒講清楚的地方歡迎評論,咱們一起探索。

我是大智(微信:zhz11235),你的技術探路者,下次見!

别走!點贊,收藏哦!

好,你可以走了。

繼續閱讀