這裏主要講Entitas的執行原理,不講Entitas的代碼生成方面。緩存
ECS(實體-組件-系統)是一種經常使用於遊戲開發的架構模式。
實體: 實體只是一個ID或一個容器,用來標記或存儲一系列組件。
組件: 沒有任何邏輯,單純用來存儲數據。
系統: 循環處理特定的組件。
ECS主要強調了兩個方面:
1.用數據的組合去描述對象,而不是繼承。
2.數據和邏輯的分離。架構
Unity採用了EC的設計思路,和傳統ECS不一樣,Unity的Component除了存儲數據,還保留了操做Component中數據的方法。
Unity中的Entiy就是GameObject,Component就是GameObject上掛載的組件各類組件,如Transform。
GameObject是各類Component的容器,自己並無實際意義(與ECS中Entity的定義略有不一樣,GameObject包含了tag、name、activeSelf等屬性。若是是在純粹的ECS系統中,tag等屬性應該做爲Component掛載在GameObject)。
好比場景中的一個Cube,由Transform、MeshFilter、MeshRenderer、BoxCollider四個組件組成。咱們能在場景中看到這個Cube是由於Unity從MeshFilter獲得了Mesh信息,告訴了GPU這是一個立方體,從MeshRenderer中的到了渲染這個Mesh的信息,告訴GPU這個Mesh上的UV對應的是哪張貼圖的座標,渲染成什麼顏色等信息。從Transform中得知了該將這個Cube渲染在哪一個位置,旋轉多少度等。Unity經過BoxCollider和Transform信息去作碰撞檢測。(在Cube的渲染這個例子中,能夠把Unity自身看做ECS中的System的集合,由於Unity中的各個模塊獲取了這個Cube中特定Component中的信息,根據這些信息作一些事情)
Unity中的EC與傳統ECS最大的兩個區別就是:
1.Entity上帶着一些屬性數據name、tag等,Component不只有數據,還集成了大量的方法。好比在Unity中但願旋轉一個Transform會直接調用Transform的Rotate方法,而在傳統ECS中,極可能是在Cube這個Entity上掛載一個Rotate組件,而後由專門的RotateSystem去處理這個轉動。
2.沒有System對Component進行統一的處理。框架
Entitas是一個用C#實現的ECS框架,提供了方便的代碼生成功能。
用法的介紹官方項目寫的比較詳細,這裏就很少作介紹。ide
也就是說整個ECS系統的內部數據維護(Group、Collector、EntityIndex)複雜度主要放在Entity的修改上了。
在給一個Entity添加一個Component時,不只僅是對Entity進行了修改,還會經過事件將這個添加傳遞給Context,Context遍歷全部Group,找到知足此次修改條件的Group,對全部受到影響的Group進行修改。而後再經過Group將此次修改事件分發到Collector或其餘監聽該Group的模塊中去。
這種方式帶來的好處十分明顯,那就是獲取一種類型的Entity(也就是一個Group),只有第一次會遍歷全部的Entity生成這個Group,以後再獲取該類型Entity的複雜度就只有O(1)。
可是也有必定的隱患,當Group和Collector比較少時,這不是一個高消耗操做,可是Group、Collector不少,且在每一幀對Entity進行頻繁修改的時候。這可能會成爲一個高消耗操做。函數
1.在銷燬一個Entity時,會移除Entity身上全部的Component,而後再進行回收。在移除Component時可能會經過Group把這個移除事件發送到監聽Remove行爲的Collector中,Collector會持有這個被銷燬的Entity。因此在filter、或execute時不能直接依賴Collector的收集條件,還須要對Entity的Component作獨立的判斷。
其實任什麼時候候filter都須要對Entity的Component作判斷,由於Collector收集的Entity極可能在其餘地方被改變。ui
2.Entity不該該被ECS系統外的模塊持有,由於系統外對Entity的持有不會被自動引用計數(能夠本身添加)。可能會致使一個Entity被銷燬而後又從池子中從新取出來, 外部模塊對這個Entity的引用沒有改變,但已經可能不是本身持有的那個Entity了。
須要避免在外界持有Entity或經過持有uuid間接從context中持有這個Entity。設計
3.在replaceComponent時,發送了Remove、Add、Update三個事件,而不是隻發送了Update事件。code
4.在代碼生成時,對單Componet的Matcher進行了緩存,如遊戲中經常使用的Postion和Name等Component,可是對組合Component的Matcher沒有進行緩存。所在在兩個不一樣的ReactiveSystem中使用Matcher相同的Collector時,如:orm
//1,2表明Postion和Name的Index //在使用代碼生成時會生成相似Matcher.Position、Matcher.Name的靜態函數,方便開發者使用 context.CreateCollector(Matcher.AllOf(1,2));
這樣會生成兩個Matcher相同的Group實例。
若是在乎這一點的話能夠本身對Matcher進行緩存。對象
在對ECS架構模式的理解和Entitas的使用上我仍是一個新手,只是剛剛開始使用,若是有什麼寫的不對的地方,各位大佬能夠留言指正。