ECS的核心概念
ECS包含三個部分:實體(entities)、資料(components)、行為(system)。具體看下圖:
這個圖中,System讀取了多個實體的Translation和Rotation元件,然後經過計算處理,將結果更新到LocalToWorld元件中。
從圖中你可以看到,實體A和B還有Renderer元件,但是C並沒有。不過這並不會影響System的計算邏輯,因為這個系統不關心Renderer元件。
你還可以寫一個系統,需要處理Renderer元件,這樣系統就會忽略實體C。你還可以寫一個系統排除包含Renderer元件的實體,這樣系統就會忽略實體A和B。
下面對ECS中比較重要的幾個核心概念做一個梳理:
原型 Archetypes
多個元件的組合叫做一個原型。
比如一個3D物體可能會包含用於transform的元件,包括移動、旋轉、渲染,每個3D物體對應一個實體,但是他們都有同樣的元件,所以ECS會把他們分類成是一類原型。
在上圖中,實體A和B的原型都是M,實體C的原型是N。
你也可以通過在執行時新增或者移除component來改變一個實體的原型。例如:如果將實體B的Renderer元件移除,實體B的原型就會變成N。
記憶體塊 Memory Chunks
為什麼要先講原型的概念呢,因為一個實體的原型是什麼,決定了ECS會將實體的components也就是資料存在什麼地方。ECS按塊分配記憶體,每塊用一個ArchetypeChunk物件表示。
一個塊只包含一種原型,可以包含的多個實體的資料。如果一個塊的記憶體滿了,ECS會分配一個新的塊來儲存新的實體的components。
如果你修改了實體的元件,那就相當於修改了實體的原型,這時候ECS會將實體的元件資料移到另外一個塊中。
原型和記憶體塊的關係是一對多的關係。這就意味著,如果想查詢給定的一組component型別的所有實體,只需要在這些原型中搜尋即可。這樣會比在所有的實體中查詢效率高很多。
ECS在儲存實體到記憶體塊中沒有特殊的排序,當建立一個實體或者實體的原型發生變化時,ECS會將它放到對應原型的第一個還有空間的記憶體塊中。記憶體塊中的資料會緊密排列。如果一個實體要被移出當前原型的記憶體塊,這時候會有個空位,ECS會把這個記憶體塊最後的實體資料移動到這個空位中。
注意:原型中的共享元件(後面會具體說這是個什麼東東)的資料也會影響實體會被存在哪個記憶體塊。同一個記憶體塊中的所有實體的共享元件中的資料值都是相同的。如果你修改了共享元件中的資料,這個實體會被移到另外一個塊中,有點類似修改了實體的原型。
將共享元件的實體分到一個記憶體塊中會提高處理他們的速度。比如Hybird Renderer(混合渲染)定義了RenderMesh元件來達成這個目的。
實體查詢
一個System根據什麼來決定處理哪些實體呢?這時候會用到一個叫實體查詢(Entity Query)的東西。實體查詢首先需要一些元件型別,然後根據你傳入的元件型別的組合,在包含這些元件的原型中查詢符合要求的實體。查詢時可以指定下面三種型別:
- All 必須包含All中所有的元件型別
- Any 必須包含Any中至少一個元件型別
- None 不能包含None中任意一個元件型別
一次實體查詢的結果會返回所有符合查詢要求的記憶體塊,你可以使用IJobChunk來迭代遍歷所有的元件。(IJobChunk後面會講。)
Jobs 作業
之前說過,ECS配合Job使用才能發揮多執行緒的威力。ECS提供了SystemBase類,其中包含Entities.ForEach方法,還包含了IJobChunk的Schedule()和ScheduleParallel()方法,可以在子執行緒中處理資料。Entities.ForEach是最簡單的方法,只需要幾行程式碼就能實現。IJobChunk可以用來處理比較複雜的情況。
ECS會在主執行緒排程Job,根據System的順序。當job排程後,ECS會追蹤哪些job在讀寫哪些元件。需要讀許可權的job需要等待前面寫許可權的job執行完,反之亦然。Job排程器會使用job依賴來決定哪些job可以並行,哪些必須序列。
System的組織
ECS通過World和group來組織system。預設情況下,ECS會建立一個預設的World,包含一些預定義的group組。它會找到工程中所有的System,例項化他們,並新增到預定義的group中。
你可以指定同一個group中system的Update的執行順序。Group也是一種system,所以你可以將一個group新增到另外一個group中。如果你沒有指定順序,system的執行順序會不太確定,並不會按照它們建立的順序。不過,同一個group中的所有system都會比下一個group中的system先執行。
System的Update是在主執行緒中執行的,不過可以使用Job將工作分配到子執行緒中。
ECS世界的視覺化建立(authoring)
在Unity中沒辦法直接視覺化地建立DOTS世界,但是,可以先用GameOjbect和MonoBehaviour來建立,然後通過轉換系統將GameObject轉換成實體和元件。這個我們後面也會細講。
來源:Unity官方平臺
原文:https://mp.weixin.qq.com/s/Tvtqz51Np7vWeYwKcQtHdQ
相關文章
- 洞明 Unity ECS 基礎概念Unity
- 核心概念
- Spark 的核心概念 RDDSpark
- Laravel中的核心概念Laravel
- ES 核心概念
- Redux 核心概念Redux
- Kubernetes核心概念
- 【RabbitMQ】核心概念MQ
- webpack (1)——核心概念的理解Web
- Laravel核心概念剖析Laravel
- RPC核心概念理解RPC
- Hyperledger Fabric 核心概念
- Webpack核心概念解析Web
- 物件導向思想的核心概念物件
- ElasticSearch核心概念和文件的CRUDElasticsearch
- vuex 中的核心概念及原理Vue
- Docker_02 核心概念Docker
- laravel核心概念總結Laravel
- webpack(2)webpack核心概念Web
- 資料中臺中的核心概念解析
- vue(23)Vuex的5個核心概念Vue
- 計算機網路的核心概念計算機網路
- vuex核心概念---action、getter、moduleVue
- Kubernetes概念及核心物件物件
- 多租戶系統的核心概念模型模型
- 遊戲核心概念確定的兩大因素遊戲
- 計算機網路的 89 個核心概念計算機網路
- Spring原始碼系列:核心概念解析Spring原始碼
- k8s——核心概念篇K8S
- Web教程:7個CSS核心概念WebCSS
- 3.k8s核心概念K8S
- PixiJS核心概念及簡單上手JS
- 30分鐘理解GraphQL核心概念
- CRM的核心概念,未來發展趨勢解析
- JMM 最最最核心的概念:Happens-before 原則APP
- Docker Swarm 核心概念及詳細使用DockerSwarm
- 領域驅動設計核心概念
- webpack 學習筆記:核心概念(上)Web筆記