unity-Entity-Component-System模式

所謂的ECS模式全稱就是Entity-Component-System模式。很早就聽說過unity等引擎中廣泛地使用了這樣的模式,沒有細查。今天看了幾篇文章之後有了些許瞭解,故記敘此文作爲筆記。

一、問題提出

之前在寫STG框架的時候遇到了這樣的問題,以面向對象的思想對遊戲對象進行抽象,那麼可以實現一個基類GameObject。之後包括敵機、自機、子彈在內的所有對象都繼承這個基類並進行實現。

於是很容易設計出這樣一個基類:

[cpp] view plain copy
  1. classGameObject  
  2. {  
  3. private:  
  4.     // === 基礎屬性 ===  
  5.     fcyVec2 m_Position;  // 位置  
  6.     fcyVec2 m_Rotation;  // 方向  
  7.     fcyVec2 m_Scale;     // 縮放  
  8.        
  9.     // === 碰撞屬性 ===  
  10.     fcyVec2 m_Size;      // 大小  
  11. public:  
  12.     voidUpdate(floatdelta);  
  13.     voidRender(floatdelta);  
  14. };  

之後,繼承這個基類,分別實現GameBullet、GameEnemy……

這樣帶來的問題就是遊戲對象的邏輯往往在超類中被定死了,而一旦需要對邏輯作出修改,要麼重寫實現,要麼繼承基類進行覆蓋。此外,在C++中使用對象池優化時就會造成災難性的後果——一種類型一個池(儘管可以用通用的內存分配器,但是這樣還要考慮內存碎片等雜七雜八的問題)。

對於傳統的設計思路,在遊戲開發上就會導致“類災難”。於是ECS模式被提了出來,用於解決繼承帶來的問題。

二、ECS的解決之道

使用繼承去表述遊戲對象和邏輯會造成邏輯混雜、維護擴展困難的問題。

既然繼承出了問題,我們就用組合來解決吧。

於是在2002年的Game Dungeon Siege上,ECS模式被提了出來。

ECS全寫即“實例-組件-系統”的設計模式。簡言之,實例就是一個遊戲對象實體,一個實體擁有衆多的組件,而遊戲系統則負責依據組件對實例做出更新。

舉個例子,如果對象A需要實現碰撞和渲染,那麼我們就給它加一個碰撞組件和一個渲染組件;如果對象B只需要渲染不需要碰撞,那麼我們就給它加一個渲染組件即可。而在遊戲循環中,每一個系統都會遍歷一次對象,當渲染系統發現對象持有一個渲染組件時,就會根據渲染組件的數據來執行相應的渲染過程。同樣的碰撞系統也是如此。

也就是說遊戲對象需要什麼就會給自己加一個組件。而系統會依據遊戲對象增加了哪些組件來做出行爲。換言之實例只需要持有必要的數據,由系統負責邏輯就行了。這也就是ECS模式能和數據驅動很好結合的一個原因。

於是在上述問題中所有的派生類都消失了,只留下了GameObject。

三、沒有什麼是完美的

雖然ECS模式可以讓維護和擴展的成本降低——必要的時候你只要給對象增加組件、爲遊戲邏輯增加系統就可以擴展了。這種設計降低了耦合,也提高了可複用性。

但是很明顯的,ECS帶來了兩個缺陷:

1、數據共享

比如渲染組件需要對象的位置信息、碰撞組件也要對象的位置信息,那麼我們怎麼解決這裏的數據共享問題?

一種解決方法是把位置信息作爲組件抽象出來,但是這樣帶來的問題就是效率會降低,在處理渲染和碰撞的時候都會再去存取一次位置信息。

另一種解決方法是使用引用(比如使用C++中的智能指針)在構建對象的時候分配同一位置對象,然後傳遞引用給其他組件。

2、遍歷次數

當遊戲中數量巨大並且系統數量也增加時,很明顯整個算法的複雜度將不低於O(n*m),遍歷對象的次數將變得巨大。

比如碰撞檢測系統若是兩兩對象進行邏輯處理那麼速度上的損失將是十分巨大的。

這裏的一種解決方法是分集合處理,不再贅述。

四、參考文檔

http://blog.lmorchard.com/2013/11/27/entity-component-system

http://piemaster.net/2011/07/entity-component-primer/

http://www.richardlord.net/blog/what-is-an-entity-framework

http://en.wikipedia.org/wiki/Entity_component_system

http://blog.csdn.net/i_dovelemon/article/details/27230719

 

【完】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章