發(fā)布時間:2024-03-08 12:57:33 瀏覽量:276次
摘要
游戲編程設(shè)計和組織是困難而復雜的,為了簡化開發(fā)進程,會使用被稱為游戲引擎的游戲框架(framework),該框架包含了一組實用工具。本項的目的是探索游戲引擎設(shè)計和開發(fā)一個模塊化和可擴展的游戲引擎。本文中的設(shè)計是面向?qū)ο?OOP)的以及兩個實體組件系統(tǒng)(ECS)。OOP設(shè)計常用于計算機科學,使用對象層次來共享函數(shù)功能,ECS設(shè)計基于繼承之上的組合的概念,ECS中對象包含特性而不是繼承它們(特性)。然而,設(shè)計都有它們的弱點,例如OOP設(shè)計中的可擴展性問題,該問題來自于層次結(jié)構(gòu)的緊耦合性,在層次結(jié)構(gòu)的根附近進行的更改需要進行有效的代碼重構(gòu)。ECS解決了耦合問題,然而,問題存在于跨系統(tǒng)通信和共享組件。使用了兩個ECS設(shè)計來解決這個問題,分別是Cupcake 和 Artemis。通過一個簡單的游戲應(yīng)用來測試和分析設(shè)計的功能性。結(jié)合使用Cupcake 和 Artemis的優(yōu)點,本該提出了一個能最小化架構(gòu)問題的新ECS設(shè)計。
1 介紹
游戲開發(fā)是一個復雜的進程,它可能需要圖形、聲音、物理、網(wǎng)絡(luò)、AI以及輸入,一個常見的實踐是使用已經(jīng)實現(xiàn)一種技術(shù)的現(xiàn)有的庫來節(jié)省時間和精力。即便如此,將幾種技術(shù)結(jié)合到一個系統(tǒng)中可能也是一項艱巨的任務(wù)。游戲引擎通過提供制作游戲所需的框架和技術(shù)解決了這個問題。這使得游戲開發(fā)者可以跳過技術(shù)的實現(xiàn)來專注于游戲開發(fā)。
開發(fā)游戲引擎時遇到的最大問題是如何表示游戲?qū)ο?,游戲?qū)ο罂梢詮臎]有控制或交互的簡單2D圖像到具有控制、聲音、動畫和AI的異常復雜3D對象。在概念上,l很容易將游戲?qū)ο罄斫鉃楸硎居螒蛑芯哂卸鄠€功能的實體。
當試圖組織一個能夠處理特性組合的體系結(jié)構(gòu)時,問題就出現(xiàn)了。
一種常見的方法是使用面向?qū)ο蟮木幊?OOP)體系結(jié)構(gòu),然而,由于繼承和層次結(jié)構(gòu)的本質(zhì),在表示游戲?qū)ο髸r出現(xiàn)了困難。作為解決面向?qū)ο蟮挠螒驅(qū)ο髥栴}的答案,實體組件系統(tǒng)(ECS)變得非常流行。
本文將討論OOP的缺點、ECS的優(yōu)點、ECS的變體,并提出一種更加模塊化的ECS設(shè)計。
2 面向?qū)ο缶幊?OOP)
面向?qū)ο缶幊淌且环N可重用和模塊化的程序設(shè)計,它將信息表示為包含數(shù)據(jù)和邏輯的對象。面向?qū)ο蟮囊粋€獨特而實用的特點是繼承,這允許架構(gòu)創(chuàng)建共享特性和結(jié)構(gòu)的層次結(jié)構(gòu),這有助于促進代碼重用和組織。
游戲?qū)ο蟮膶哟谓Y(jié)構(gòu)會是什么樣子?OOP聽起來正是游戲引擎需要的代碼重用和組織。圖1是一個表示車輛和花盆的層次結(jié)構(gòu)的示例。當路徑如前面所示一樣簡單時,這就可以實現(xiàn),然而,當游戲?qū)ο箝_始共享功能時,問題就出現(xiàn)了。
2.1 OOP的問題
當涉及到層次結(jié)構(gòu)中的共享特性時,設(shè)計架構(gòu)就變得非常困難。圖1對于帶有聲音的靜態(tài)對象或者帶有聲音和控件(比如播放器外觀)的非渲染對象會發(fā)生什么變化?圖2顯示了添加了游戲?qū)ο蟮臐撛趯哟谓Y(jié)構(gòu)樹,我們的樹開始在特征和路徑上顯示冗余。添加到游戲?qū)ο蟮墓δ芙M合越多,層次結(jié)構(gòu)就會變得越復雜,這使得代碼難以管理和組織。
圖2-冗余的OOP層次結(jié)構(gòu)
這種復雜層次結(jié)構(gòu)的一個主要問題是處理游戲?qū)ο螅茈y創(chuàng)建一個函數(shù)來接受持有特定功能的各種類型的游戲?qū)ο?。諸如函數(shù)重載之類的解決方案很難維護,因為包含特定功能的每種類型的對象都需要自己的函數(shù)。這將強制所有不同組合使用非直觀的層次結(jié)構(gòu)或代碼重用。
這個復雜層次結(jié)構(gòu)的更糟糕的問題是可擴展性,每個子類都在很大程度上依賴于父類的結(jié)構(gòu)。如果沒有大規(guī)模的代碼重構(gòu),添加新特性或更改當前特性可能是困難的,也可能是不可能的。
3 實體組件系統(tǒng)
繼承之上的組合是解決面向?qū)ο蟮膶哟谓Y(jié)構(gòu)問題的一種方法。這個概念通過組合而不是繼承來增加功能,使系統(tǒng)更加模塊化和獨立。例如,使用ECS,車輛對象包含用于聲音或控制等特性的對象,而不是創(chuàng)建層次結(jié)構(gòu)鏈。這使得車輛對象更具動態(tài)性,因為更改特性就像添加或刪除對象一個簡單,而不需要主要代碼的重構(gòu)。
3.1 架構(gòu)
ECS由三個基本部分組成:實體、組件和系統(tǒng)。實體是與對象關(guān)聯(lián)的唯一id,組件是表示實體信息的數(shù)據(jù),系統(tǒng)在實體上運行邏輯,以利用或更改來自組件的數(shù)據(jù)。
在游戲開發(fā)中,游戲?qū)ο蟊划斪鲗嶓w,功能被表示為組件和系統(tǒng)。這可以看作是一個數(shù)據(jù)庫,其中實體是惟一的id,系統(tǒng)是數(shù)據(jù)庫表,組件是數(shù)據(jù)庫表中的數(shù)據(jù)。
圖3-ECS中的游戲?qū)ο?/p>
圖3顯示了游戲?qū)ο笤贓CS體系結(jié)構(gòu)中的樣子。車輛與一個惟一的id關(guān)聯(lián)。使用這個惟一的id,調(diào)用者通過創(chuàng)建與所需特性關(guān)聯(lián)的組件來附加特性。這允許系統(tǒng)使用組件中提供的數(shù)據(jù)處理實體和應(yīng)用動作。
3.2 優(yōu)點
ECS體系結(jié)構(gòu)的優(yōu)點在于它是獨立的,每個組件只不過是簡單的數(shù)據(jù)點,因此本質(zhì)上是與其他組件隔離的。系統(tǒng)需要特定的組件來運行其邏輯,這使得系統(tǒng)相對解耦,因為實體中包含的不同組件的數(shù)量不會改變系統(tǒng)解釋實體的方式。只要滿足組件需求,系統(tǒng)就會在實體上運行其邏輯。
圖4-實體組件系統(tǒng)(ECS)
圖4顯示了以前層次結(jié)構(gòu)轉(zhuǎn)換為ECS的設(shè)計。關(guān)于渲染系統(tǒng),花盆和揚聲器有什么不同?渲染系統(tǒng)是否關(guān)心揚聲器是否有聲音組件?向屏幕渲染對象是否需要聲音組件?這是ECS系統(tǒng)如何提高隔離性和強化代碼組織的一個例子。一個簡單的表格可以用來查看游戲?qū)ο蟀男┕δ?,而不是遵循一個復雜且長樹。
圖5-添加功能的ECS
ECS架構(gòu)的另一個好處是系統(tǒng)的模塊化和可擴展性。由于系統(tǒng)和組件是相對獨立的,所以很容易添加新特性。例如,向花盆中添加聲音與添加聲音組件一樣簡單。添加諸如爆炸之類的新特性可以與創(chuàng)建新系統(tǒng)和組件一樣簡單。更新的圖5顯示了新特性如何對引擎的總體結(jié)構(gòu)產(chǎn)生較低的影響。
3.3 缺點
雖然ECS系統(tǒng)可以解決OOP帶來的一些問題,但是它們有自己的一些問題,隔離和獨立是ECS系統(tǒng)的正反兩面。當設(shè)計需要共享組件和跨系統(tǒng)通信時,就會出現(xiàn)負面影響。
共享組件的問題是包含關(guān)系和處理順序,該概念促進系統(tǒng)耦合,這與ECS的隔離設(shè)計背道而馳。根據(jù)設(shè)計,共享組件的位置是不確定的,此外,處理實體的順序可能是至關(guān)重要的。例如,在引擎中的移動、碰撞和渲染,流程順序?qū)⒏目梢姷慕Y(jié)果。例如,移動、碰撞和渲染的順序可以創(chuàng)建這樣一種情況:由于尚未處理碰撞,對象將會穿透墻壁。
跨系統(tǒng)通信是ECS的另一個難點??缦到y(tǒng)通信對于事件發(fā)生這一情況是必要的。例如,一個球與地面相撞時應(yīng)該發(fā)出噪音。ECS的問題是碰撞和聲音系統(tǒng)是不同的,彼此是隔離的。解決這個隔離問題的兩種方法是向組件添加狀態(tài)或?qū)崿F(xiàn)消息傳遞系統(tǒng)。無論哪種方式,設(shè)計一種方法在保持系統(tǒng)獨立的同時連接它們都是困難的。
4 CUPCAKE ECS
CUPCAKE ECS架構(gòu)被設(shè)計成一個模塊化的ECS系統(tǒng),其目標是在不影響架構(gòu)的情況下方便地添加或刪除系統(tǒng)。這就要求系統(tǒng)之間是完全獨立的,永遠不要使用或引用任何其他系統(tǒng)。理想情況下,這將創(chuàng)建一個用戶可以插入和添加新特性的引擎,并有望提高代碼重用度和用戶之間的共享。
用戶如何使用Cupcake的一個例子是從基本ECS框架開始。這將包括管理系統(tǒng)、實體的實用工具,以及創(chuàng)建新系統(tǒng)和組件的框架。接下來,用戶將從插件(系統(tǒng))列表中選擇所需的功能。例如,用戶可以選擇一個功能列表,如聲音的FMOD, 3D渲染的OpenGL, 物理的Bullet。最后,安裝腳本將插件和框架編譯成靜態(tài)庫和一組頭文件。結(jié)果將是一個高度可定制的、特定于用戶的引擎。
4.1 架構(gòu)
Cupcake架構(gòu)分為幾個部分:引擎、管理器和系統(tǒng)。圖6顯示了Cupcake的基本架構(gòu)。引擎是所有系統(tǒng)、管理器和實體的頂層接口,它負責運行游戲循環(huán)和管理系統(tǒng)和實體。該引擎通過提供添加和刪除附加實體來管理實體,同時為每個實體維護一個惟一的id,通過提供正在處理的系統(tǒng)和空閑系統(tǒng)兩個列表來管理系統(tǒng),正在處理中的系統(tǒng)由引擎游戲循環(huán)進行處理。
圖6-Cupcake架構(gòu)
系統(tǒng)負責管理組件和實現(xiàn)幾種抽象方法。抽象方法包括init、release和update(用于正在處理的系統(tǒng))。使用于FOD播放聲音的系統(tǒng)的一個例子,是一個包含聲音和位置的組件列表的系統(tǒng)。init函數(shù)將初始化FMOD庫文件,release函數(shù)將釋放所有與系統(tǒng)綁定的資源,如組件和FMOD庫。update函數(shù)用于更新移動對象的聲音位置。
4.2 Cupcake 方案
Cupcake包含與任何具有共享組件和跨系統(tǒng)通信的ECS系統(tǒng)相同的通用問題。為了解決共享組件的問題,Cupcake在引擎外部有一個外部組件集。這些外部組件在創(chuàng)建時被傳遞給系統(tǒng),這允許多個系統(tǒng)之間具有相同的組件集,而不需要任何方法來保持數(shù)據(jù)的同步。此外,它還保持了系統(tǒng)之間的獨立性。共享組件的一個例子是渲染和物理系統(tǒng)的位置,通過引用相同的組件列表,物理系統(tǒng)對位置所做的任何更改都將自動用于渲染。
采用外部消息系統(tǒng)解決了系統(tǒng)間的交叉通信問題。此消息傳遞系統(tǒng)由句柄、觸發(fā)器和消息組成。觸發(fā)器是針對特定條件在每個循環(huán)中執(zhí)行的一段邏輯,根據(jù)這些條件,將向消息系統(tǒng)發(fā)送一條消息。消息句柄是為系統(tǒng)創(chuàng)建的對象,用于消息捕獲和基于消息的邏輯執(zhí)行。例如,一個玩家的移動需要三個部分,基于玩家輸入執(zhí)行的觸發(fā)器,當觸發(fā)器注冊了一個玩家輸入(事件)時,它將向系統(tǒng)發(fā)送適當?shù)膍ove消息,比如向前移動,然后,這個向前移動的消息句柄被物理系統(tǒng)捕獲,然后物理系統(tǒng)將被調(diào)用,根據(jù)該句柄移動玩家。
4.3 分析
Cupcake系統(tǒng)通過提高系統(tǒng)的獨立性和采用數(shù)據(jù)驅(qū)動架構(gòu),保持了實體組件系統(tǒng)的基礎(chǔ)本質(zhì)。解決常見ECS問題的方法是有效的,但是還有改進的余地。
共享組件是解決共享數(shù)據(jù)問題的一個相對簡單的解決方案。外部共享組件的問題是包含共享組件的內(nèi)容的模糊表示。除非明確指示,否則不清楚調(diào)用者應(yīng)該在何處生成或獲取共享組件。通過要求調(diào)用者被指示這個外部列表應(yīng)該從哪里來,暴露了一個脆弱的設(shè)計。它允許調(diào)用者為相同的組件創(chuàng)建重復列表,這將達不到共享組件的目的。
事實證明,外部消息傳遞系統(tǒng)工作得相對較好。消息傳遞系統(tǒng)的外部性有助于提高系統(tǒng)獨立性,并允許調(diào)用者定制消息的行為。外部消息傳遞系統(tǒng)的問題在于其與引擎的集成性較弱,創(chuàng)建一個關(guān)于如何處理跨系統(tǒng)通信的標準會更有用。通過將消息傳遞集成到引擎中,系統(tǒng)更有可能圍繞標準消息傳遞系統(tǒng)進行設(shè)計。
最后,Cupcake的一個缺陷是引擎中去除了實體。由于組件存儲在系統(tǒng)中,所以沒有簡單的方法可以從系統(tǒng)中刪除實體。調(diào)用者必須手動地從各個系統(tǒng)中釋放組件來刪除實體。這就留下了一個問題––允許在設(shè)計系統(tǒng)時不實現(xiàn)在特定實體上釋放數(shù)據(jù)的函數(shù)。
5 ARTEMIS ECS 框架
由Gamadu創(chuàng)建的Artemis ECS框架是為游戲開發(fā)而設(shè)計的,該設(shè)計與Cupcake很相似。實體是惟一的id,組件是數(shù)據(jù),系統(tǒng)使用數(shù)據(jù)來處理邏輯。Artemis框架最初是用Java編寫的,但是本文將使用C來適配Artemis框架,從Java到C,有幾個特性沒有實現(xiàn),所以該分析只對C++而而言是準確的。
5.1 架構(gòu)
Artemis框架包含一個中心化的World對象,該對象是這個框架的接口。World對象包含所有manager并運行游戲循環(huán),此框架中使用的manager用于系統(tǒng)、實體、組(group)和標記(tag)。系統(tǒng)和實體的manager類似于Cupcake,它們用于管理實體或系統(tǒng)。組和標記管理器是簡單的系統(tǒng),用于將實體組織在一起并向特定實體添加標記,通過將一些字符串關(guān)聯(lián)到一組實體或單個實體來實現(xiàn)的。
Artemis中的實體管理器是惟一的,因為它將所有組件存儲在引擎中,這是通過一個二維數(shù)組完成的,其中第一個標識符是組件類型,第二個標識符是實體id。實體管理器還為每個活動實體管理惟一的id。
Artemis中的系統(tǒng)要管理需要處理的實體列表,這是通過為每個組件類型分配標識符來實現(xiàn)的。使用組件類型,系統(tǒng)可以通過過濾只處理有效的實體。為了訪問數(shù)據(jù),調(diào)用者必須創(chuàng)建組件mapper,以便從實體管理器獲取組件。
5.2 分析
Artemis有一個獨特的解決方案來解決共享組件問題,通過將組件附加到實體管理器,這使得所有系統(tǒng)都可以訪問組件,這也使得組件在使用它們的系統(tǒng)之間自動同步。此外,它還消除了誰包含共享組件的歧義問題,因為所有組件都存儲在同一個位置。這在調(diào)用者需要刪除實體時非常有用,因為實體管理器可以搜索組件列表并刪除與實體關(guān)聯(lián)的所有數(shù)據(jù)。
Artemis的一個問題是缺乏跨系統(tǒng)的通信,系統(tǒng)之間唯一共享的是可以用作消息的組件。然而,由于創(chuàng)建和刪除組件的開銷很大,因此這可能是一種開銷很大的消息傳遞方法。
最后,Artemis最大的限制是組件和系統(tǒng)類型的限制,與組件和系統(tǒng)關(guān)聯(lián)的惟一id是用位(bit)完成的,比特數(shù)被限制在32個,這就產(chǎn)生了一個問題,當用戶超過組件或系統(tǒng)限制時,過濾就會失效。新組件分配了未定義的類型,這樣就允許將無效實體傳遞給系統(tǒng)(譯注:言外之意是有問題的)。
6 提出的架構(gòu)
本文提出的ECS系統(tǒng)架構(gòu)是Cupcake和Artemis的結(jié)合,Cupcake解決了跨系統(tǒng)通信問題,并保持了系統(tǒng)的獨立性。通過在實體管理器中本地化所有組件,Artemis解決了共享組件的問題。這兩種技術(shù)的結(jié)合解決了ECS的問題,同時保持了模塊化。
6.1 架構(gòu)
這個架構(gòu)像Cupcake和Artemis將有一個中心接口對象稱為引擎(engine),引擎將負責管理器和游戲循環(huán)。引擎所包含的管理器是系統(tǒng)、實體、資源和消息。引擎還負責使用系統(tǒng)管理器處理“正在處理的系統(tǒng)”的每個游戲循環(huán)。
圖7-引擎對象
系統(tǒng)和實體管理器的工作方式與Artemis相同,其中組件存儲在實體管理器中。組件類型將具有唯一id,以便允許系統(tǒng)過濾組件類型,通過使用組件id,系統(tǒng)可以創(chuàng)建具有適當組件的有效實體列表并處理它們。
新增的資源管理器存儲組件可能共享的信息。對象的mesh是多個組件共享數(shù)據(jù)的一個例子,例如,如果游戲中存在50個相同的敵人,那么為每個實體創(chuàng)建重復的mesh數(shù)據(jù)將會非常昂貴。資源管理器將處理在實體之間共享完全相同數(shù)據(jù)這一理想情況。
消息管理器將負責跨系統(tǒng)通信,與Cupcake一樣,它將由調(diào)用者創(chuàng)建的處理程序(handler)組成,這些處理程序捕獲消息并在系統(tǒng)中執(zhí)行邏輯。系統(tǒng)將負責向消息處理程序發(fā)送消息,而不是觸發(fā)器。
7 使用ECS的項目
在這個項目中,實現(xiàn)了兩個不同的ECS系統(tǒng),并在一個簡單的游戲環(huán)境中使用。Cupcake引擎是用C編寫的,用于測試應(yīng)用程序Cron。使用基于Artemis框架的C開發(fā)了用于CPE 476項目Carrota的引擎。
7.1 Cron
圖8-Cupcake測試應(yīng)用
開發(fā)Cupcake引擎時,創(chuàng)建了一個測試應(yīng)用程序來測試引擎的功能。圖8顯示了示例測試應(yīng)用程序。球體代表玩家,用戶可以在其中使用控件移動對象。此外,位置音頻是基于球的位置。這些立方體代表了物理作用于它們的測試對象,它們播放恒定的音頻。這是用來確保3D音頻正常工作。
7.2 Carrota
圖9-Carrota兔子
圖10-Carrota商店菜單
圖11-Carrota甜甜圈
利用Artemis框架為CPE 476項目開發(fā)了ECS引擎,使用該引擎創(chuàng)建一個FPS防御游戲。該引擎的特性包括:2D/3D/文本呈現(xiàn)、聲音、碰撞、物理、動畫、framebuffer對象和陰影,其中每個功能都是相對獨立。
8 未來的工作
在未來的工作中,將提出的ECS方案繼續(xù)發(fā)展和完善,首先構(gòu)建框架,然后實現(xiàn)功能。希望能夠?qū)崿F(xiàn)支持3D渲染和實時圖形的功能,最終目標是創(chuàng)建一個冗長的框架,其中包含多個可以跨引擎共享的特性。
參考文獻
翻譯原文:
https://pdfs.semanticscholar.org/829b/9107c32bb20965400d22a6dad14f56b9b7b5.pdf
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設(shè)計領(lǐng)域和數(shù)字藝術(shù)教育的重要性,歡迎點擊咨詢報名。
2. 手機游戲如何開發(fā)(如何制作傳奇手游,都需要準備些什么?)
?如何制作傳奇手游,都需要準備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現(xiàn)在的手游,說明時代在進步游戲在更新,更趨于方便化移動化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費、一鍵制作炫酷特效,適合新手小白??靵碓囋嚕?/span>
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇?!短烀嬗肪哂卸嗑€劇情多結(jié)局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經(jīng)濟體系揭秘,不同玩家角色的經(jīng)濟活動
Bigtime加密游戲經(jīng)濟模型分析,探討游戲經(jīng)濟特點,幫助玩家更全面了解這款GameFi產(chǎn)品。
6. 3D動畫軟件你知道幾個?3ds Max、Blender、Maya、Houdini大比拼
當提到3D動畫軟件或動畫工具時,指的是數(shù)字內(nèi)容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術(shù)動畫的軟件程序。但是,在3D動畫軟件中還包含了其他類型的...
7. 3D動漫建模全過程,不是一般人能學的會的,會的多不是人?
步驟01:面部,頸部,身體在一起這次我不準備設(shè)計圖片,我從雕刻進入。這一次,它將是一種純粹關(guān)注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
8. 如何自己開發(fā)一款游戲(游戲開發(fā)入門必看:五大獨立游戲開發(fā)技巧)
?游戲開發(fā)入門必看:五大獨立游戲開發(fā)技巧無論您是剛剛起步開發(fā)自己的第一款游戲,還是已經(jīng)制作了幾款游戲,本篇文章中的5大獨立游戲開發(fā)技巧都可以幫助您更好地設(shè)計下一款游戲。無論你對游戲有著什么樣的概念,都
?三昧動漫對于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應(yīng)并不會推出《巫師4》。因為《巫師》系列在策劃的時候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現(xiàn)《巫師4》
10. 3D打印技巧揭秘!Cura設(shè)置讓你的模型更堅固
想讓你的3D打印模型更堅固?不妨嘗試一下Cura參數(shù)設(shè)置和設(shè)計技巧,讓你輕松掌握!
最新文章
同學您好!