【遊戲性基礎系統】網絡
遊戲性基礎系統(gameplay foundation system):架構
1)運行時遊戲對象模型(runtime game object model)編輯器
2)關卡管理及串流(level management and streaming)函數
3)更新實時對象模型(real-time object model updating)性能
4)消息及事件處理(messaging and event handling)動畫
5)腳本 (scripting)編碼
6)目標及遊戲流程管理(objectives and game flow management)spa
其中1)運行時對象模型是最複雜的,一般它須要提供如下功能:設計
1)動態地產生(spawn)及消滅(destroy)遊戲對象。指針
2)聯繫底層引擎系統
3)實時模擬對象行爲
4)定義新遊戲對象類型
5)惟一的對象標識符(unique object id)
6)遊戲對象查詢(query):根據ID查找對象,或是根據任意條件作高級查找,如尋找玩家20m之內的全部敵人
7)遊戲對象引用(reference)
8)有限狀態機(finite state machine, FSM)
9)網絡複製(network replication)
10)存檔及載入遊戲、對象持久性(object persistence)
【運行時對象模型架構】
遊戲對象模型的2種架構:
1)以對象爲中心(object-centric):每一個對象含一組屬性及行爲,這些都會封裝在那些對象實例的類之中。遊戲世界只不過是遊戲對象的集合。容易產生單一龐大的類層次結構(monolithic class hierarchy)。一個類越是在類層次結構中越深的地方,就越難以理解、維護及修改。由於要理解一個類,就須要理解其全部父類。
此方式最大的問題是,當設計層次選擇了某個標準,就很難甚至不可能用另外一個徹底不一樣的標準分類。好比按物種分類的生物,要按顏色分類就很差辦。mix-in類能夠改善改方式。一個類能夠派生自主要繼承層次結構中的一個且僅一個類,但也能夠繼承任意數量的mix-in類(無基類的獨立類)。一般更好的作法是合成(composition)或聚合(aggregation),而不是繼承他們。
把Window派生自Rectangle類。然而,一個視窗並非一個長方形,它只擁有一具長方形,用於定義其邊界。所以,這個設計問題的更好解決方法是把Rectangle的實例安置於Window類之中,或是令Window擁有一個Rectangle的指針或參考。面向對象設計中,「有一個」的關係稱爲合成(composition),合成的對象與主對象有一樣的生命週期。對於主對象與子對象生命週期不一樣步的設計,稱爲聚合(aggregation)。
要下降遊戲類層次結構的寬度、深度、複雜度,一個十分有用的方法是把「是一個」關係改成「有一個」關係。業界成熟的方式是使用組件模式:
1)「樞紐」HUB組件模式
2)通用組件模式
3)純組件模式
2)以屬性中心(property-centric):每一個遊戲對象僅以惟一標識符表示。咱們先定義遊戲對象可能含有的屬性集合,而後爲每一個屬性建表。此設計更能有效地使用內存,由於咱們只需存儲實際上用到的屬性。SoA(struct of array)的性能優於AoS(array of struct)
【世界組塊的數據格式】
一、二進制對象映像,把每一個對象的二進制映像(binary image)寫入文件,對於指針和虛函數表須要特殊處理。
二、序列化(serialization),XML解析之慢衆所周知。
三、生成器(spawner)是遊戲對象的輕量、僅含數據的表示方式,可用於運行時實例化及初始化遊戲對象。
【遊戲世界的加載和串流】
遊戲加載系統主要有2個功能:
1)人磁盤加載遊戲世界組件及其它用到的資產至內存中。
2)管理這些資源的內存分配及釋放。
加載包括:
1)簡單的關卡加載,玩家須要等待關卡載入,期間會顯示靜態或簡單動畫的二維加載畫面。
2)串流加載,即預加載
3)關卡加載區域,區域之間可能會有重疊,每一個區域配有一個表,列出玩家位於該區域時內存應該包含的世界組塊。
內存管理採用池分配器,爲每種類型對象生成一個池分配器,避免內存碎片。
遊戲存檔分爲:
1)存儲點存檔,這法較爲簡單,由於能夠避免對大量世界數據的記憶
2)任何地方皆可存檔
【對象引用與世界查詢】
幾個實現對象引用的方式:
1)指針
2)智能指針
3)句柄。句柄會有引用過期對象的問題,解決此問題的方案之一是,在每一個句柄中加入惟一的對象標識符。
遊戲對象查詢能夠提供幾下以種能力:
1)以惟一標識符搜尋遊戲對象
2)對合乎某條件的全部對象進行迭代
3)搜尋射線路線以及範圍內物體
【實時更新遊戲對象】
「差一幀」問題引發的狀態不一致是bug的主要來源。相比遊戲對象模型,低階引擎子系統纔是性能關鍵。
【事件與消息泵】
一、爲每種事件定義一個虛函數,如OnExplosion()。這種方式的壞處在於,全部的對象都必須實現OnExplosion,即便是不響應此函數的對象也要實現。
二、把事件封裝成event,基類event提供類型,子類event提供具體內容,經過統一的OnEvent(Event *evt)來傳遞。
關於事件的類型,有2種方法:
1)enum枚舉,此法有如下幾個缺點,首先,全部的類型聚合在一塊兒,破壞封裝。其二,類型硬編碼,其三,硬編碼被改變後,對於存儲於磁盤上的內容沒法修改。
2)使用字符串,缺點是佔用內存點,消耗大。
關於事件的參數,有如下幾種方法:
1)統一的variant集合
2)鍵值對,此法能夠解決variant的次序問題。
事件的參數必須深拷貝出去,採用池分配能夠有效減小內存碎片。可是採用event模式,會加大調度困難,由於沒法追溯事件的發送者。
三、事件處理器,即OnEvent的實現能夠用switch來實現。另外,在設計上能夠採起職責鏈模式。
四、使用事件註冊機制能夠減小須要響應事件在範圍。
五、即時消息發送可能會致使棧開銷過大,層次過深。
六、事件響應的邏輯能夠經過世界編輯器開放給策劃,由策劃來完成。
七、事件機制能夠提供排隊的功能,以及延時響應功能。
【腳本】
遊戲腳本語言一般有2種:
1)數據定義語言(data-definition language)
2)運行時腳本語言(runtime scripting language)
對於大多數工做室而言,更合適的方未能是選擇一個知名且成熟的腳本語言。遊戲引擎必需要能執行腳本代碼,腳本代碼也須要發志引擎中的操做。運行時腳本語言的虛擬機一般是嵌入遊戲引擎中的。引擎啓動虛擬機,須要時執行腳本代碼,並管理腳本的執行狀況。
腳本須要和遊戲對象互動,其中一個方法是在腳本中以不透明的數值類型句柄(handle)來引用對象。