網上已經有比較多的DOTS的資料了,這裡就簡單介紹一下。DOTS,Data-Oriented Technology Stack ( 資料導向型技術棧)的縮寫,是Unity退出的面向多線程程式設計的解決方案 ,其包含了 C# Job System、Entity Component System (ECS) 、Burst等元件組成。這裡推薦一個up做的比較系統的筆記來參考一下(https://www.yuque.com/dev666/rxitsg/chtnhs 感謝這位叫做dev666的部落客的分享)裡面有相當多的幹貨資料,對DOTS的實作原理、具體使用、API等都有詳細的分析,感謝!
我主要還是看了ECS這一塊的東西,感覺比較适合開發包含大量重複性且着色器渲染一緻模型的應用場景。ECS沒有了狀态,隻有大量的實體(Entity),實體上的挂載的元件(Component),對元件進行操作的系統(System)。通過對實體添加對應的元件來标記實體可以具有的能力,然後通過系統來過濾指定一個或一組元件,間接賦予實體能力,已經跟傳統的面向對象不太一樣了。附上個參考圖

參照着這個項目做出了demo(https://www.yuque.com/dev666/rxitsg/lfdqbo),這是個純ECS的小遊戲項目,場景不需要挂載任何腳本直接建立空場景就能夠運作,下面附上開發環境的配置情況
Unity 2019.3.0f6
Enities preview.33-0.0.12
Hybrid Render preview.13-0.0.1
Mathematics preview.20 0.0.12
Universal RP 7.1.8
在配置好開發環境後,unity可能會報以下錯誤
這是引用的插件找不了RenderPipeline的相關引用方法,并不影響程式使用,可以直接屏蔽掉引用了RenderPipeline.beginCameraRendering的代碼。(估計是ECS需要RenderPipeline但現版本的unity并沒有提供相關的類庫)
附上工程的下載下傳路徑
連結:https://pan.baidu.com/s/1v3BqFsVU2Zza4FTDDZF-tA
提取碼:0hnc
工程的運作截圖
這個demo可以說是純ECS實作的,沒有Mono的代碼,通過給實體添加元件并利用系統實作能力的形式,實作了UI顯示,輸入控制,球體建立與下落、碰撞檢測、得分判斷等等功能。
再說明下這個工程需要注意的地方
項目是使用了自定義的渲染管線,是以我直接下載下傳了URP插件(想省事的話可以直接下載下傳Core RP Library)需要手動建立Render Pipeline Asset檔案并拖拽到project settings的Graphic上
直接建立空場景不需要Camera直接運作就能看到項目的運作,同時要把Game視窗設定成Free Aspect,因為裡面的UI就是手動建立的,并不是使用UGUI
一個項目最好隻包含一個ECS的項目,因為ECS大多數類都不需要挂載到場景中,很可能會重複定義引起混淆。
下面是關于ECS使用的個人總結:
1.Component可以置空當作TAG來用
public struct Player : IComponentData { }
public struct Ball : IComponentData { }
2.在方法頭中申明[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
即使不挂載場景也可以在運作時觸發
3.EntityManager的擷取方法
a.通過World.Active.EntityManager擷取
b.繼承ComponentSystem的類 可以直接調用EntityManager
4.
擷取單例
GetSingleton<Game>() 擷取單例的Component
GetSingletonEntity<Player>() 擷取單例的Entity
設定單例
SetSingleton<Game>(game)
5.
擷取Entity上的Component
Position playerPosition=EntityManager.GetComponentData<Position>(player);
增加Entity上的Component
EntityManager.AddComponent(visibleReadyUIQuery, typeof(Disabled));
删除Entity上的Component
EntityManager.RemoveComponent(invisibleReadyUIQuery, typeof(Disabled));
以上三個可以對Entity、EntityQuery進行操作
6.篩選Query 一般在OnCreate中初始化
private EntityQuery query;
protected override void OnCreate()
{
query=GetEntityQuery(new EntityQueryDesc
{
All=new[]{},//必須同時都有的Component組
None=new[]{},//隻要有了就會被排除的Component組
Any=new[]{} //隻要存在任意一個Component就符合的組
}
);
}
All、None、Any都是ComponetType[]類型 ,則元素都是ComponentType.ReadOnly(Component)
GetEntityQuery也可以直接使用,不需要All None Any
GetEntityQuery(ComponentType.ReadOnly<GameOverUI>(), ComponentType.ReadOnly<Disabled>());
7.在ComponentSystem中的update裡删除Entity
PostUpdateCommands.DestroyEntity(entities[i])
8.周遊query的結果操作
using (NativeArray<ArchetypeChunk> chunks = this.query.CreateArchetypeChunkArray(Allocator.TempJob))
{
foreach (ArchetypeChunk chunk in chunks)
{
}
}
9.擷取chunk裡面的Enity或者Component
ArchetypeChunkEntityType entityType = GetArchetypeChunkEntityType();
NativeArray<Entity> entities = chunk.GetNativeArray(entityType);
ArchetypeChunkComponentType<Position> positionType = GetArchetypeChunkComponentType<Position>();
NativeArray<Position> positions = chunk.GetNativeArray(positionType);
10.ComponentSystem的執行順序在類頭申明
在指定的組裡面運作
[UpdateInGroup(typeof(InitializationSystemGroup))] 初始化
[UpdateInGroup(typeof(PresentationSystemGroup))] 邏輯與運算
[UpdateInGroup(typeof(SimulationSystemGroup))] 圖形處理
自定義組
public class InputHandlingSystemGroup : ComponentSystemGroup { }
自定義組并規定它的執行順序
[UpdateInGroup(typeof(SimulationSystemGroup))]
[UpdateBefore(typeof(UpdateSystemGroup))]
public class InputHandlingSystemGroup : ComponentSystemGroup { }
待補充