天天看點

Unity ECS Manual [5]

Components(元件)

  元件是ECS體系結構的三個主要元素之一。它們代表你的遊戲或應用程式的資料。實體是索引你的元件集合的辨別符,而[System]提供行為。

  ECS中的元件是具有以下“标記接口”之一的結構:

  • IComponentData - 用于通用和[chunk components]。
  • IBufferElementData - 将[dynamic buffers]與實體關聯。
  • ISharedComponentData - 在一個原型中按值對實體進行分類或分組。欲了解更多資訊,請參見[Shared Component Data]。
  • Hybrid Components - 将UnityEngine元件添加到實體的一種方式。
  • ISystemStateComponentData - 将System特定狀态與實體相關聯,并檢測各個實體的建立或銷毀時間。有關詳細資訊,請參見系統狀态元件。
  • ISharedSystemStateComponentData - 是共享和系統狀态資料的組合。見系統狀态元件。
  • Blob assets - 雖然從技術上講不是“元件”,但您可以使用BLOB資産來存儲資料。BLOB資産可以由一個或多個元件使用BlobAssetReference引用,并且是不可變的。您可以使用Blob assets在資産之間共享資料,并在C# Jobs中通路該資料。

  EntityManager将元件的獨特組合組織成原型archetypes。它将具有相同原型的所有實體的元件一起存儲在稱為塊chunks的記憶體塊中。給定塊中的實體都具有相同的元件原型。

Unity ECS Manual [5]

  這張圖說明了ECS是如何按其原型來存儲元件資料塊的。共享元件和塊元件是例外,因為ECS将它們存儲在塊之外。這些元件類型的單一執行個體适用于适用塊中的所有實體。此外,你可以選擇在塊外存儲動态緩沖區。盡管ECS不在塊記憶體儲這些類型的元件,但在查詢實體時,你一般可以把它們和其他元件類型一樣對待。

General-purpose components(通用元件)

  ECS元件(不是托管的UnityEngine.Component 類的執行個體)是一個struct(結構),隻包含一個實體的執行個體資料。ECS元件不應包含除utility函數以外的方法來通路結構中的資料。你應該在系統中實作你所有的遊戲邏輯和行為。用面向對象的Unity系統來說,這類似于一個Component類,但它隻包含變量。

  Unity ECS API提供了一個名為IComponentData的接口,您可以在代碼中實作該接口來聲明通用元件類型。

IComponentData

  傳統的Unity元件(包括MonoBehaviour)是面向對象的類,包含行為的資料和方法。IComponentData是一個純ECS樣式的元件,這意味着它不定義任何行為,隻定義資料。您應該将IComponentData實作為 struct 而不是class,這意味着預設情況下它是按值複制的,而不是按引用複制的。您通常需要使用以下模式來修改資料:

var transform = group.transform[index]; // Read

transform.heading = playerInput.move; // Modify
transform.position += deltaTime * playerInput.move * settings.playerMoveSpeed;

group.transform[index] = transform; // Write
           

  IComponentData結構不得包含對托管對象的引用。這是因為ComponentData位于簡單的非垃圾回收跟蹤區塊記憶體中,這具有許多性能優勢。

托管IComponentData

  使用托管IComponentData(即,使用class而不是struct聲明的IComponentData)有助于以逐漸的方式将現有代碼移植到ECS,與ISharedComponentData中不适合的托管資料進行互操作,或對資料布局進行原型化。

  這些元件的使用方式與值類型IComponentData相同。然而,ECS在内部以一種非常不同(且速度較慢)的方式處理它們。如果不需要托管元件支援,請在應用程式的Player Settings(菜單:Edit > Project Settings > Player > Scripting Define Symbols)中定義Unity_Disable_Managed_Components以防止意外使用。

  由于托管IComponentData是托管類型,是以與值類型IComponentData相比,它具有以下性能缺陷:

  • 它不能與Burst編譯器一起使用
  • 它不能在job結構中使用
  • 它不能使用區塊記憶體
  • 它需要垃圾收集

  您應該嘗試限制托管元件的數量,并盡可能多地使用 blittable 類型。

  托管IComponentData必須實作IEquatable接口并重寫Object.GetHashCode()。此外,出于序列化目的,托管元件必須是預設可構造的。

  必須在主線程上設定component的值。為此,請使用EntityManager或EntityCommandBuffer。因為元件是引用類型,是以您可以更改元件的值,而無需在塊之間移動實體,這與ISharedComponentData不同。這不會建立同步點。

  但是,盡管托管元件在邏輯上與值類型元件分開存儲,但它們仍然為實體的EntityArchetype定義做出貢獻。是以,向實體添加新的托管元件仍然會導緻ECS建立新的原型(如果比對的原型還不存在),并且它會将實體移動到新的塊中。

有關示例,請參見檔案:/Packages/com.unity.entities/Unity.Entities/IComponentData.cs.