繼承體系的問題,爲何要用ECS
面向對象的問題
- 當一個新的類型須要多個老類型的不一樣功能的時候,不能很好的繼承出來
- 遊戲開發後期會有很是多的類,很難維護
- 遊戲中子系統不少,它們對一個對象的關注點每每互不相關,好比渲染.網絡,戰鬥數據,若是都對應一個基礎角色對象,這個類就會很大
ECS,經過組合而不是繼承的方法來進行實體的構建
- ECS的設計目的是用來把大量的模塊進行集成並解耦,用最小的耦合來集成大量分散的系統
- 每一個System能夠只關注實體有什麼,而不是實體是什麼,這是與OOP的最大區別
- 在網絡同步的預測錯誤後能夠很方便的糾正(全部元素都用Component分離了)
- ECS的一個重要特性就是併發優點,由於提供了數據隔離
Unity推薦ESC的緣由
- ECS專一於您正在解決的實際問題,即構成遊戲的數據和行爲。
- 爲了配合使用Job System和Burst 編譯器。
- 從以對象爲導向的設計轉到以數據爲導向的設計,代碼更爲容易,也更易於他人掌握。
示例
假設一個簡單的遊戲,有石頭,樹,敵人,玩家三種物體
這個時候須要一個新的類型,能夠攻擊的樹php
- 按照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)。html
單例組件
示例:命中處理System
- ModifyHealthQueue組件,記錄實體身上全部傷害和治療效果
- MovementState組件,移動數據處理
- 一組Utility函數處理錯誤糾錯,回滾相關Component
幾個建議git
- System定義組件的組合時,能夠把組件標記爲只讀
- 實體生命週期建議當即建立,延時銷燬
- 某些遺留子系統不能接入ECS時,就不要強行接入,保持子系統的整潔
- 事實證實,網絡同步真的很複雜,因此必須儘量的與引擎其他部分解耦,ECS是解決這個問題的好辦法。
Unity中的ECS
在PackageManager中下載Entitiesgithub