元件-實體-系統 (ECS \CES)遊戲程式設計模型

水木本源發表於2018-08-08

一般來說,我們實現遊戲實體都是採用物件導向的方法進行程式設計。每一個實體都是一個物件,並且需要一個基於類的例項化系統,允許實體通過多型來擴充套件。但是,這樣的方法,往往導致系統中出現大量的類,造成類爆炸的情況出現。隨著新的實體出現,我們發現很難在類繼承圖中新增新的實體,特別是當這個實體需要很多不同型別的功能的時候。你可以看下下面的一個簡單的類圖繼承。一個靜態的敵人,並不能夠很好的繼承出來。

 

為了解決這樣的問題,遊戲開發人員想出了通過組合而不是繼承的方法來進行實體的構建。一個實體,就是一群元件的聚合,通過這樣的方式,它具有以下物件導向方法所不具有的好處:

1.容易新增新的複雜的實體型別

2.容易定義新的實體資料

3.更加的高效率

 

下面是如何實現實體的一種方式。注意,這裡的元件都是純粹的資料,沒有任何的方法,在下面會詳細解釋為什麼這麼做。

 

元件

一個元件可以使用C中的結構體來進行設計。它沒有方法,只是用來儲存一些資料,並不在它之上進行動作。一個經典的實現方式是,每一個不同的元件都繼承至一個抽象的Componet類,通過這樣的方法我們能夠在執行時動態的新增元件,識別元件。每一個元件都描述了實體的某個屬性特徵。當他們單獨存在的時候,實際上是沒有任何意義的,但是當多個元件通過系統的方式組織在一起,就能夠發揮強大的力量。我們可以使用空的元件來對實體進行標記,從而能夠在執行時動態的識別它。

 

例子

  • Position(x,y)
  • Velocity(x,y)
  • Physics(body)
  • Sprite(images, animations)
  • Heath(value)
  • Character(name, level)
  • Player(empty)

 

實體

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

 

例子

  • Rock(Position, Sprite)
  • Crate(Position,Sprite,Health)
  • Sign(Position,Sprite,Text)
  • Ball(Position,Velocity,Physics,Sprite)
  • Enemy(Position,Velocity,Sprite,Character,Input,AI)
  • Player(Position,Velocity,Sprite,Character,Input,Player)

系統

注意,我在上面沒有提到任何和遊戲邏輯相關的話題。遊戲邏輯是系統需要進行的工作。一個系統就是對所有相關聯的元件記性操作,比如說,同一個實體的元件。舉個例子,人物的移動系統可能會對位置(Position),速度(Velocity),碰撞(Collider),和輸入(Input)進行操作。每一個系統,都會在每一幀中按照邏輯上的順序進行更新。如果要讓一個角色跳起來,我們只要檢測下Input中的keyJump按鍵是否被按下,如果是,那麼系統就會檢視下載Collider中是否有一個接觸了地面,如果是,就將這個實體的Velocity的y速度設定一下,讓這個物體跳起來。

由於系統只會對相關聯的元件進行操作,所以元件就定義了一個實體所應該具有的行為。比如說,如果一個實體有一個Position元件,但是沒有Velocity元件,那麼我們就知道,這個物體是靜止不動的,系統就不會對這個實體的Position元件進行操作了。當我們對這個實體增加了一個Velocity元件的時候,系統就會使用Velocity元件來對物體進行移動。這樣的行為可以使用被標記的元件來進行,被標記的元件能夠重複的使用在不同的上下文中。對一個實體,增加一個空的Player元件,將會為這個實體打上了Player的標籤,那麼PlayerControl系統,就會尋找帶有這個標籤的所有元件,然後使用Input中的資料,進行操作。

 

例子

  • Movememt(Position, Velocity) - 將速度增加到位置上去
  • Gravity (Velocity) - 使用重力來對速度進行加速
  • Render(Position, Sprite) - 繪製精靈
  • PlayerControl(Input, Player) - 更具Input中的資料控制Player
  • BotControl(Input, AI) - 更具AI代理和輸入的資料控制

結論

使用了CES系統之後,我們就可以避免使用大量的類了。實體就是你遊戲中存在的物體,它隱式的使用一系列的元件進行定義,這些元件都是純粹的資料,只有系統才能夠操作他們。

相關文章