遊戲框架設計 遊戲中的事件機制

2021-06-20 17:58:45 字數 3831 閱讀 8392

事件機制在很多高階程式語言中都有支援。譬如vb、c#(delegate)、c++builder(並不屬於c++的範疇。c++builder中的事件處理器必須用關鍵字closure《閉包》修飾)等等,甚至在html中也可以見到它的身影。事件機制的引入使軟體系統變得更加易於理解——它使一種語言(平台)更加接近於這個世界的真相。事情的發展變得像現實世界中那樣順理成章。某一事件的產生引發了一系列其他事件的產生,這些事件要麼是結果要麼又會引發一系列事件的產生……如此這般,資訊才得以在事件的新陳代謝中延續,世界才得以向前發展。在某些遊戲設計過程中的一項重要任務就是模擬現實世界的某些特徵,以期實現機器與使用者的更加親密的溝通。事件機制就是很好的一例。我們需要事件來使我們的系統更加人性化。

我想,在我繼續進行下面對討論之前,先簡單介紹一下「事件」這個東東。

1. 遊戲中的事件機制

聯絡是普遍存在的。事事有聯絡、時時有聯絡,整個世界是乙個相互聯絡的統一整體。乙個人的行為、物的狀態的改變或事的進展過程的某一階段可以引發乙個事件。乙個事件的發生或許會引發另外的事件——通過人的感知、大腦的反映,然後作出決策,付諸行動——也或許,就這麼蒸發掉,無人知曉。但無論如何,在這一過程中,我們總能抽象出一些實質性的東西來。就像下面的圖示:

在遊戲中:

事件源——表示任何可以引發事件的物件。譬如,乙個「人」、「坦克」、「建築物」、「地面」。

事件——表示任何可以處理的事件。譬如,「感冒」、「射擊」、「倒塌」、「有物件經過」。

響應者——表示任何對某事件感興趣的物件。

響應器——表示對某事件感興趣的物件對某一確定事件作出的反應。

特別的,對於過程:

通知——發生在事件與響應者之間。我們把它分為兩種方式:有限聽眾式、廣播式。對事件感興趣的物件(響應者)只有確定的有限個(只有乙個的情況下,可以叫做點對點式)的情況就是有限聽眾式。而對於廣播式,事件並不知道會有哪些(個)物件對自己感興趣。它向所有可以接收事件通知的物件廣播事件。

觸發——響應者發現自己對特定事件需要做出相應的行動時就會觸發事件處理器,並同時傳遞需要的事件資訊給它。對於響應者,它也可以選擇沉默——自己了解事件但並不作出行動。因此這個過程的決定權在響應者手上。

2. 萬事之鼻祖 event

我們需要乙個類來表示所有事件的普遍性質。

public class

event

// 獲取或設定事件的名稱

public string message

// 獲取或設定事件的簡單描述

eventtypes eventtype

// 獲取或設定事件型別(列舉eventtypes)

listenercollection listeners

// 獲取響應者的集合

public bool 

poolevent

// 獲取或設定事件的簡單描述

// 方法

void 

raiseevent(); 

// 通知響應者事件的發生

void 

abandonlistener( int index ); 

// 拋棄乙個事件響應者,並把它從 listeners 中移除。

void 

abandonlistener(); 

// 拋棄所有的事件響應者}

3. 列舉型別 eventtypes

這個列舉型別指示事件通知過程的型別:有限聽眾式、廣播式。

public enum 

eventtypes

4. 響應者介面 ilistener

該介面只有唯一的方法 eventarrived() 。事件發生時會呼叫這個方法並傳遞相關引數。這個引數必須是 eventargs 或由它派生而來。

public inte***ce 

ilistener

5. eventpool

乙個事件池。當且僅當需要事件廣播時我們才需要它。需要注意的是 addevent 方法。它把乙個事件新增到池中,第二個引數指定是否將該事件已經指定的響應者亦新增到廣播的響應者中。事件新增後,其 event::eventtype 屬性會被設定為 eventtypes.broadcast。

public class

eventpool

// 獲取池中所有的事件的集合

public listnercollection listners

// 獲取池中所有的響應者的集合

// 方法

void 

addevent( event obj ,bool copylistners ); 

// 新增乙個事件並把它作為廣播式事件

void 

removeeventat( int index ); 

// 將乙個事件從列表中移除

void 

removeevent( event listener ); 

// 將乙個事件從列表中移除

void 

broadcast( event event ); 

// 向列表中的所有響應者廣播指定事件(可以是非池中的事件)

void 

broadcastitemat( int index ); 

// 向列表中的所有響應者廣播池中的指定事件}

6. eventargs

public class

eventargs  

// 獲取傳遞這個引數的事件

public 

object sender  

// 獲取事件源}

8. 響應者行為

響應者實現 ilistener 介面後就可以響應事件了。在 eventarrived() 方法中,你可以直接處理事件,抑或是呼叫其它的事件處理器(響應器)。c#中有很好的解決方案——委託——替代函式指標的最有效的方法。在c++中也可以用虛函式表來模擬委託機制。總之,在響應器上的解決方案是很靈活的。在實際開發中,可以根據不同的環境做出不同的選擇。

9. 擴充套件機制

在乙個遊戲中,除了已經定義好的事件外,其劇情或功能可能會要求玩家自行定義一些事件。這就需要一種可擴充套件的方案。我們引入了 customevent 類——繼承自 event,以及 condition 類。

public class

customevent : event

public condition testcondition }

condition _condition = null; }

public abstract class

condition

bool abstract test(); }

初始化乙個 customevent 類時必須同時傳入乙個 condition 類。condition 類必須被繼承。test()方法在適當的時候被呼叫以檢測是否可以引發這個事件。

10. 後記

以上談到的只是乙個簡單的模型,是否實用還要等待實踐的檢驗。歡迎讀者的批評與建議。

遊戲中PVP戰場框架的設計

mmorpg類的遊戲中,pvp戰場是很常見的乙個遊戲功能,這裡分享一種專案中使用的設計方式。在設計前,先理清下戰場我們需要維護的東西 戰鬥的階段 如登入 準備 戰鬥 結算等階段 戰鬥的積分 擊殺玩家得分 占領得分 助攻得分 對於戰鬥的階段劃分,每一類具體的戰場,需要的戰鬥階段可能都是不同的,比如某些...

Laya 小遊戲通用框架設計理念

當前在用laya做小遊戲開發,做了幾個專案,總結了一下遊戲中所需要的一些模組,大概理了一下,然後寫成一套自己習慣使用的框架 總結了一下其中的模組 大概要分為一下模組 1.base 模組 存放一些基類,以供後續繼承開發使用 如 單例的基類 2.asset 資源載入模組 用於laya 載入資源 3.da...

遊戲中幾種概率設計

遊戲中常見的4種概率設計 1 常規做法,直接配置概率,程式直接判定 2 在1的基礎上,加個保底次數,當連續不發生的次數高於保底時,強制發生 3 設定基礎概率,事件不發生概率翻倍 4 設定陣列,將事件發生概率變成陣列元素 設定預計平均發生概率為1 20 20次發生1次 模擬10w次方案1 3後得結果 ...