關於Unity 2018的實體組件系統(ECS)二

孫廣東  2018.5.20git

 

關於Unity 2018的實體組件系統(通用名稱ECS)二github

 

將介紹如何在Unity上使用實體組件系統(一般稱爲ECS)。json

此次的內容是Unity提供的ECS API的基本用法,一個小應用程序和並行化。編輯器

 

它不包括與Unity的GameObject / Component的合做,以及實際使用。ide

 

 

獲取可使用ECS的編輯器優化

Unity2018 和以後的版本均可以!this

 

您能夠從 https://github.com/Unity-Technologies/EntityComponentSystemSamples 下載官方的一個Demo。操作系統

 

以後,下載與您本身的操做系統匹配的編輯器並安裝它。.net

 

 

建立一個可使用ECS的項目翻譯

我將建立一個項目,但我沒法使用ECS。

要啓用ECS,須要兩件事。

 

  • 使使用 .NET 4.x
  • 重寫 manifest.json

正常啓動Unity並打開 Edit> PlayerSettings> PlayerSettings。

以後,將Scripting Runtime Version腳本運行時版本更改成Stable (.net 4.x)。

 

 

接下來是重寫manifest.json。

因爲在項目的Root文件夾/ Packages中有一個名爲manifest.json的文件,所以咱們將按照https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/TwoStickShooter/Pure/Packages/manifest.json 與此處相同的方式重寫內容。

 

準備工做完成。

 

最小的ECS項目

首先,嘗試儘量地構建最有意義的功能。

此次要組織的功能就是這樣

  • 統計每一個幀

 

一、 沒有使用 ECS的代碼 :

首先我會試着用MonoBehaviour來組織它。這是一個很是簡單的代碼。

編寫完成後,您能夠將Counter組件添加到適當的GameObject中。

using UnityEngine;

public class Counter : MonoBehaviour{ public int count;

void Update () { count++; }}

 

接下來,讓咱們對應於ECS。有三件事要作

它是什麼?麻煩? ECS就是這樣

 

  • CountData 計數的值
  • CountSystem 實際計數
  • ECSMain 實體

ComponentDatas.cs

using Unity.Entities;

 

// 實體

public struct CountData : IComponentData

{

public int count;

}

 

CountSystem.cs

using Unity.Entities;

 

public class CountSystem : ComponentSystem

{

// System所需的ComponentData列表

struct Group

{

public int Length;

public ComponentDataArray<CountData> countData;

}

 

[Inject] Group group; // 注入請求的ComponentData

 

// 調用每一幀

protected override void OnUpdate()

{

for(int i=0; i<group.Length; i++)

{

var countData = group.countData[i];

countData.count++;

group.countData[i] = countData;

}

}

}

ECSMain.cs

using UnityEngine;

using Unity.Entities;

 

public class ECSMain : MonoBehaviour

{

void Start ()

{

// 獲取EntityManager

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

 

// 定義實體的原型

var sampleArchetype = entityManager.CreateArchetype(typeof(CountData));

 

// 實際上基於原型生成實體

entityManager.CreateEntity(sampleArchetype);

}

}

 

 

 

 

以後,若是您將ECSMain附加到適當的對象並Play,則第一步完成。

在Play期間,打開Window > EntityDebugger,當它從Systems列表中找到CountSystem時,它會變白,而且若是實體存在 。

 

 

 

若是沒有實體,那麼您有可能在沒有CountData的狀況下建立實體,或者您沒有首先建立實體。另外,若是您沒有系統,則建立ComponentSystem的代碼有問題。

 

 

 

一點評論

看如下內容。

對於每一個角色的 ECS 是以下所示。

 

 

那麼,首先ComponentData,這裏重要的是struct(結構)並繼承IComponentData。

將它用做ComponentData時,這兩個都是必需的。

 

 

建立實體ECSMain是一種建立實體的翻譯,但它從MonoBehaviour事件中調用它,等等。

 

正如你在註釋中看到的那樣,

 

  • 獲取EntityManager
  • 建立實體原型
  • 根據原型信息建立實體

這是一個流程。

 

彷佛沒有必要考慮ComponentData存儲在原型中的順序以及建立它的時機。只有內在的東西纔是重要的。

 

 

 

最後一個關於CountSystem做爲ComponentSystem。這是一個兩部分組成。

 

  • 組的定義
  • 處理內容

首先是Group的定義和實際injection的代碼。

 

ComponentDataArray包含(指向)請求組件的指針,而Length包含具備請求ComponentData的實體數目。

 

在 [Inject] 中,自動注入對請求組的引用。

 

 

 

 

 

下半部分代碼... OnUpdate() 部分只需添加數字。請注意,組的內容是一個結構,所以您不能直接分配它。

 

 

增長系統的例子

接下來我會嘗試增長系統

 

若是計數器超出範圍,則該過程的內容就像刪除同樣。

功能解釋忽略了更多的效率。

 

 

ECS基本上由相似皮帶輸送機的流程任務組成,系統處理一些ComponentData並將其傳遞給下一個系統....

 

所以,「添加計數器並在計數器超出範圍時移除計數器」

 

  • 稱爲「實體包括計數器」的容器
  • 向系統添加計數器
  • 系統 檢查計數器並丟棄它,若是它是無用的

 

 

 

爲了實現這一點,我會再增長一些。

 

  • Common ComponentData 獲取範圍
  • 計數超出範圍時刪除實體的 系統
  • CountSystem之間的依賴關係

 

代碼在這裏:

ComponentDatas.cs

using Unity.Entities;

 

// 実體

public struct CountData : IComponentData

{

public int count;

}

 

[System.Serializable]

public struct RangeData : ISharedComponentData

{

public int min, max;

}

ECSMain.cs

using UnityEngine;

using Unity.Entities;

using Unity.Collections;

 

public class ECSMain : MonoBehaviour

{

[SerializeField] RangeData range;

 

EntityArchetype sampleArchetype;

 

void Start()

{

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

sampleArchetype = entityManager.CreateArchetype(typeof(CountData), typeof(RangeData));

}

 

private void Update()

{

if(Input.anyKey)

{

var entityManager = World.Active.GetOrCreateManager<EntityManager>();

var entity = entityManager.CreateEntity(sampleArchetype);

entityManager.SetSharedComponentData<RangeData>(entity, range);

}

}

}

RangeSystem.cs

using Unity.Entities;

using Unity.Collections;

using Unity.Jobs;

 

[UpdateAfter(typeof(CountSystem))]

public class RangeSystem : ComponentSystem

{

struct Group

{

public int Length;

public EntityArray entities;

[ReadOnly] public ComponentDataArray<CountData> countData;

[ReadOnly] public SharedComponentDataArray<RangeData> rangeData;

}

 

[Inject] Group group;

 

protected override void OnUpdate()

{

for (int i=0; i<group.Length; i++)

{

var range = group.rangeData[i];

var data = group.countData[i];

if ( data.count > range.max || data.count < range.min )

{

PostUpdateCommands.DestroyEntity(group.entities[i]);

}

}

}

}

 

解釋一下代碼:

 

首先,咱們添加了RangeData,它是用於範圍判斷的ComponentData。

可是,因爲該「範圍信息」在大多數數據中具備相同的值,所以使用對多個實體公用的IShardComponentData。

還添加了Serializable屬性,以即可以使用Inspector進行設置。

 

 

 

ECSMain添加了這個CountData。

 

(1) 首先,RangeData顯示在Inspector上,以便編輯,(2) RangeData做爲類型添加到原型中,(3) RangeData設置在建立的Entity中。

 

以後,咱們經過按下按鈕來改變實體的類型。

 

 

最後是系統。

雖然它是一個系統,當它超出範圍時刪除實體......固然,它有必要得到「範圍」。所以,在(2) 中,RangeData包含在組中。

 

在③中,使用DestroyEntity刪除實體。

 

這裏值得注意的是Update ① 和 [ReadOnly] 。這兩個用法大體相同,彷佛若是[ReadOnly]存在,它將在使用[WriteOnly]等的系統以後被調用。一樣,若是有UpdateAfter,它將在指定的系統以後被調用。

 

 

 

 

 

 

並行化

在這段時間結束時,嘗試並行化ECS處理。目標是增長計數。

 

當處理負載至關長或者有不少對象時,並行化多是一個好結果。

CountSystem.cs

using Unity.Entities;

using Unity.Jobs;

 

public class CountSystem : JobComponentSystem

{

AddCounterJob job;

 

protected override void OnCreateManager(int capacity)

{

base.OnCreateManager(capacity);

// 作一份工做

job = new AddCounterJob();

}

 

// 發佈工做

protected override JobHandle OnUpdate(JobHandle inputDeps)

{

return job.Schedule(this, 64, inputDeps);

}

 

[ComputeJobOptimization] // Burst編譯器的優化屬性

struct AddCounterJob : IJobProcessComponentData<CountData> //請求ComponentData

{

public void Execute(ref CountData data)

{

data.count++;

}

}

}

 

下圖是處理大約6000個實體的時間比較。因爲它將並行和burst結合在一塊兒,因此存在很大的差別。

 

 

 

可是,有不少地方不能使用並行,由於這種數據處理和行爲在可用數據和行爲方面受到限制。在某些狀況下,若是您使用C# Job System,您可能能夠作更多...

相關文章
相關標籤/搜索