Lua下的ECS框架

2021-10-12 12:39:18 字數 2051 閱讀 3118

**雲風的blog:

前段時間,我寫了一篇 **《守望先鋒》中的 ecs 構架 。最近想試試在 lua 中實現乙個簡單的 ecs 框架,又仔細琢磨了一下。

我思考後的結論是:ecs 並不是乙個新概念,它的提出其實是和語言相關的。ecs 概念的誕生起於遊戲行業,相關框架基本都是基於 c++ 來開發的。它其實是對 c++ 物件模型的乙個反思。ecs 針對元件組合物件,而反對 c++ 固有的基於繼承的物件模型。物件模型才是 ecs 的設計核心理念。而離開 c++ 的物件模型,ecs 並不是什麼新鮮的東西。

我的這個觀點也不新鮮,在 ecs 的 wikipedia 頁上也有類似的說法:

拋開理論不談,如果要在 lua 中實踐,我們到底可以做點什麼呢?

我認為需要有這幾個方面:

首先應該對 lua 加強型別系統。lua 的動態性天然支援把不同的元件聚合在一起,我們把不同的 component 放在一張表裡組合成 entity 就足夠了。但如果 component 分的很細的話,用很多的表組合成乙個 entity 物件的額外開銷不小。不像 c++ ,結構體聚合的額外開銷幾乎為零。我們完全可以把不同 component 的資料直接平坦放在乙個 table 中,只要鍵值不衝突即可。但是我們需要額外的型別資訊方便執行時從 entity 中萃取出 component 來。另外,如果是 c / lua 混合設計的話,某些 component 還應該可以是 userdata 。

從節省空間及方便遍歷的角度講,我們甚至可以把同類的 c component 聚合在一大塊記憶體中,然後在 entity 的 table 中只保留乙個 lightuserdata 即可。ecs 的 system 最重要的操作就是遍歷處理同類 component ,這樣天然就可以分為 c system 和 lua system 。資料的內聚性很高,可以直接區分開 c data 和 lua data 。

然後、就是方便的遍歷。ecs 的 system 需要做的就是篩選出它關心的 entity ,針對其中的 component 做操作。如果需要篩選結果大大少於全體 entity 數量,遍歷逐個判斷就會效率很低。好在在 lua 中,我們可以非常容易地做出 cache ,只需要遍歷篩選一次,在監控新的 component 的誕生就可以方便的維護遍歷用的集合了。

我寫了乙個初步的版本。打算等到實際使用起來再慢慢完善。

它可以實現成乙個純 lua 版,但我特地嘗試把裡面的兩個函式編寫了 c 的等價版,看起來可以提高不少效能。

這裡的 api 中, entity 全部使用唯一數字 id 標識,而不主張直接引用 entity 的 table 。這也是一般 ecs 框架的通用做法。數字 id 可以提高健壯性,還可以避免對已經銷毀的 entity 錯誤的引用。如果需要 c / lua 混合程式設計的話,在 c 中引用 id 也方便的多。

型別系統是這樣設計的:

每個 component 有乙個 16bit 的唯一型別 id ,每個 entity 是由若干 component 組合而成,我將它們的型別 id 公升序排列成乙個字串,作為整個 entity 的動態型別。然後 lua 中實現了乙個 cache ,可以從這個型別字串轉換成易用的型別物件。型別物件用來對 entity 做篩選,從裡面分離出 component 。這個型別字串的拼接我實現的是乙個 c 版本,雖然 lua 也能實現的出來,但是效率會低很多。

大部分 component 我主張直接平坦的放在 entity 物件表中,但若需要用 c 結構來承載,或單獨用乙個子表,也提供了 component 型別註冊方法,可以在 new component 時定義乙個專門的建構函式(以及 delete 時的析構函式)。

這裡還提供了遍歷包含特定 component 的 entity 集合 的迭代器。它由乙個弱表實現的 cache 來管理。在第一次遍歷時,會建立乙個集合,收集 entity 全體集合中符合要求的部分,把篩選出來的 id 記錄下來。一旦遍歷集合建立好,它還會跟蹤新的 component 的建立,自動加進來。

這裡的迭代器,我同時實現了 lua 版本和 c 版本。c 版本的效能會高一些,我認為這個 c 版本在遍歷相關集合時,效能表現不會差於用 c/c++ 實現的原生容器。

以上是對 entity 和 component 的支援。system 相關的方法,我還沒有想好可以做點什麼。等用到了再完善。

ECS框架學習 02

建立 命令元件,包含子彈射擊角度,子彈數量 建立playerview繼承自view,用來得到player子物體 射擊點 建立射擊系統,用來生成子彈 protected override void execute list entities else public static gameentity ...

ECS框架文件翻譯一 Entities

entities 實體 實體是ecs 實體元件系統 體系結構的三個主要元素之一。它們代表遊戲或程式中的單個 物體 乙個實體 e 既沒有行為也沒有資料,它只是將一系列相關聯的資料 於compnents 串聯在一起。系統 systems 提供行為。元件 components 儲存資料。實體本質上是乙個i...

理解ECS的概念和Unity中的ECS設計

ecs的概念很早就有了,最初的主要目的應該還是為了改善設計。e c s三者都有其意義,e c是組合優於繼承,主要用以改善oo的繼承耦合過重以及多繼承菱形問題。oop常見設計裡,每個gameobject有父類,子類繼承來實現不同型別的物件,很容易產生過多 過深的繼承以及多繼承,而這兩者理論上都不好 依...