為甚麼用ECS架構
優勢
直觀的分隔資料層、邏輯層、顯示層
記憶體分配工整,快取容易
世界資料快照容易
並行運行,各系統邏輯是獨立的
OOP

假設我有一些子彈,我要怎麼讓子彈飛行。
定義成一個子彈的類(Class),包含屬性(Field)、方法(Method),實例化這個物件。
所以整個世界中會有一堆的實例化出來的子彈物件,OOP會在子彈的類上實作一個飛行的方法,當主線程更新世界時,會更新所有的物件,若子彈上有更新的飛行方法就能去更新子彈的位置屬性。但是當這個物件越來越龐大時每當調用單一物件的屬性資料記憶體都要直接找到這個大顆的物件,"找"這個動作會在記憶體挖一個空間作快取,整個世界物件循環刷過一輪快取一下就滿了,當需要對某個屬性做操作時基本上是重新快取,在重複調用時效能非常差,而且GC非常耗效能。
1 | public class Object{ |
ECS

在ECS架構裡沒有物件的概念,物件可以看成由組件組成,組件是甚麼,組件就是很多類的資料像是位置、攻擊、ID、
像是假設子彈就是可以設計成以物理組件+碰撞組件+子彈組件,組成子彈這個實體(不是物件,自己不帶方法)。
世界的更新稱為System,會設計很多的System去直接更新帶規定組件的資料,System不會在乎這個物件是什麼,只要對應到System就直接修改組件的值,從這裡可以發現,世界更新時不用再取整個世界上的物件,直接依照系統的定義,更新資料,大大減少記憶體的負擔,並且每個系統邏輯是分開的,可以並行運行。資料在記憶體裡的容量也大幅減小,因為只有數組,並且在記憶體裡每種資料格式已經分類畫好不會像物件一樣不同大小。
1 | public struct Object_LifeTime : IComponentData{ |
1 | foreach (var (data, entity) in SystemAPI.Query<RefRW<Object_LifeTime>>().WithEntityAccess()){ |
1 | foreach (var (data, entity) in SystemAPI.Query<RefRW<System_OnDestroy>>().WithEntityAccess()){ |
架構依照開發需求做選擇
當然OOP也可以做得像ECS,例如用array分組物件,以interface模擬System。
ECS也可以為了貼近人性化或需要快速開發而模擬OOP。