組件-實體-系統 Entiy-Compoent-System ECS架構整理


繼承體系的問題,為什么要用ECS

面向對象的問題

  • 當一個新的類型需要多個老類型的不同功能的時候,不能很好的繼承出來
  • 游戲開發后期會有非常多的類,很難維護
  • 游戲中子系統很多,它們對一個對象的關注點往往互不相關,比如渲染.網絡,戰斗數據,如果都對應一個基礎角色對象,這個類就會很大

ECS,通過組合而不是繼承的方法來進行實體的構建

  • ECS的設計目的是用來把大量的模塊進行集成並解耦,用最小的耦合來集成大量分散的系統
  • 每個System可以只關注實體有什么,而不是實體是什么,這是與OOP的最大區別
  • 在網絡同步的預測錯誤后可以很方便的糾正(所有元素都用Component分離了)
  • ECS的一個重要特性就是並發優勢,因為提供了數據隔離

Unity推薦ESC的原因

  • ECS專注於您正在解決的實際問題,即構成游戲的數據和行為。
  • 為了配合使用Job System和Burst 編譯器。
  • 從以對象為導向的設計轉到以數據為導向的設計,代碼更為容易,也更易於他人掌握。

示例

假設一個簡單的游戲,有石頭,樹,敵人,玩家三種物體
這個時候需要一個新的類型,可以攻擊的樹

  • 按照OOP的設計大致是這樣的
  • ECS的設計大致是這樣的

    EvilTree擁有: Position,AI,Sprite,AABB

ECS結構圖示

ECS基礎規則

* Entity輕量級,甚至只有一個Id;
* System沒有狀態, Component 不帶行為
* System不能調用其他System的函數,共享代碼要放到Utils里(如敵對關系),Utils函數無副作用;
* 組件里復雜的副作用要通過隊列的方式推遲處理,尤其是單例組件;

實體

一個實體指的是存在於你的游戲世界中的物體。實體在代碼上就是一個組件的列表。
由於實體的結構實在是太簡單了,所以很多實現都沒有專門的設計一個實體的數據結構。相反的,一個實體就是一個ID,所有組成這個實體的組件將會被這個ID給標記,從而明確的知道哪些組件是屬於哪個實體的。如果你想的話,你可以在運行時,動態的將組件從實體中移除或者增加一個或多個你感興趣的組件。比如說,如果玩家發出了一個冰系魔法,將敵人凍住,你只要簡單的將它的速度組件移除,那么敵人就靜止住了。

組件

沒有行為(改變數據),只是用來存儲一些數據(全部公開), 每一個組件都描述了實體的某個屬性特征。
每個System會以自己的角度對待組件,不同的觀察者區別對待主體
單例組件: 屬於單一匿名實體,可以直接訪問,存放System大部分狀態.比如Ipnut單例,從InputSys中剝離的數據.

系統

真正處理游戲邏輯的地方.
System不關注實體到底是什么,只關心組件集合,在這個集合上執行一組行為
只會有很少的System改變組件狀態,自己管理復雜性
系統會指明所需要的組件集合,由主邏輯篩選出所有滿足要求的實體

守望先鋒的ECS


EntityAdmin是個World,存儲了一個所有System的集合,和一個所有實體的哈希表(ID為unit32)。

單例組件

示例:命中處理System

  • ModifyHealthQueue組件,記錄實體身上所有傷害和治療效果
  • MovementState組件,移動數據處理
  • 一組Utility函數處理錯誤糾錯,回滾相關Component

幾個建議

  • System定義組件的組合時,可以把組件標記為只讀
  • 實體生命周期建議立即創建,延時銷毀
  • 某些遺留子系統不能接入ECS時,就不要強行接入,保持子系統的整潔
  • 事實證明,網絡同步真的很復雜,所以必須盡可能的與引擎其余部分解耦,ECS是解決這個問題的好辦法。

Unity中的ECS

在PackageManager中下載Entities

參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM