2013-07-30 26 views
2

我策劃一個事件驅動的遊戲引擎。其基本思想是,不是讓所有事情都與一切事情交流,而是與事件系統進行交流,而不是將接收者與通知者或其他方式耦合起來。C++:事件系統實施一個遊戲引擎

  • 對象登記自己的事件系統。通知ID和指向回調函數的指針作爲每個註冊命令的參數傳遞。
  • 對象將通知添加到事件系統。通知的ID作爲每個通知的參數傳遞。通知被添加到保存所有待處理通知的隊列中。
  • 此外,事件系統支持預定的通知。通知ID和將來的執行時間作爲每個通知的參數傳遞。然後按照未來的執行時間將預定通知存儲在保存預定通知的數據結構(「時間表」)中。
  • 一個調用對象命令事件系統來處理所有排隊的通知。事件系統按順序提取通知,並調用每個已註冊自己的對象的回調函數,並使用與當前通知相同的ID。
  • 調用者對象命令事件系統處理一個預定的通知。最早的通知是從計劃中提取的,並且調用了使用相同通知ID註冊的所有對象的回調。

class Registration 
{ 
public: 
    void callback(void){ callback_(); } 
    void setCallback((*callback)(void)); 
    void addToEventSystem(int ID, EventSystem &eventSystem); 
private: 
    void (*callback_)(void); 
}; 

class EventSystem 
{ 
public: 
    void register(int ID, Registration* registration); 
    void unRegister(int ID, Registration* registration); 
    void addNotificationToQueue(int ID); 
    void addNotificationToSchedule(int ID, int notificationTime); 
    void processQueuedNotifications(void); 
    void processNextScheduled(void); 
    int getCurrentTime(void); 
private: 
    //placeholder types 
    <list> notificationQueue; 
    <binaryheap> notificationSchedule; 
}; 

//------------Use:------------------ 
class ReceiverObject 
{ 
public: 
    void doStuff(void); 
    void initialize(void){ 
     keyPressRegistration.setCallback(doStuff); 
     //multiple registrations with different ID:s to same eventsystem possible 
     keyPressRegistration.addToEventSystem(1234,eventSystem); 
     keyPressRegistration.addToEventSystem(42,eventSystem);}; 
private: 
    Registration keyPressRegistration; 
}; 

int main() 
{ 
    ReceiverObject receiverObject; 
    EventSystem eventSystem; 
    receiverObject.initialize(); 
    eventSystem.addNotificationToQueue(1234); 
    eventSystem.processQueuedNotifications(); 
} 

但是我並不完全滿意這種解決方案,主要是因爲系統不允許容易傳遞參數給收件人,我懷疑回調成員函數,它是設計好做法?那麼我提出的方法/類/變量名稱呢?歡迎對這個問題提出建設性的批評,指導和替代方法。

+2

如何爲您的回調傳遞'std :: function'而不是普通函數指針? –

+0

確實那些看起來很有前途。我只是沒有經驗,也沒有關於C++ 11的知識,但是我會給新標準一個看看 – jms

回答

4

它不嚴格相關的問題,但談到設計,我會避免使用全局通知系統「一切」,因爲我已經在過去看到不好的後果。在一個對象只是調用另一個對象的某些方法的地方,你只會傾向於使用沉重的事件系統。

專業templatatised系統更好地工作,即,允許你控制對象的壽命和系統設計用於處理特定類型的事件和已知參數在其中。

任何情況下,你會發現它難以解決的問題,如未決事件瓦亭交付給已經殺死了收件人。

1

我個人會有一個接口類EventHandler,你可以註冊,它將有一個虛擬的action函數(也許事件系統告訴它的類未被註冊)。這完全避免了回調,並且EventHandler的實際實現將有可能保存其他數據(或對其他數據的引用)。

+0

那麼這比我目前的回調想法更有意義,但參數/數據傳輸如何呢? EventHandler的具體實現默認必須知道接收者類,但是如果要傳輸數據,它還必須知道數據的來源(可能是將事件添加到「EventSystem」中的類)首先),這將他們結合在一起。 – jms

+0

不確定你的意思 - 在我的想法中,接收者類是「EventHandler」的一個實例。 –

+0

我原以爲你的意思是你的原始答案是'Registration'已經被做成了一個名爲'EventHandler'的抽象基類,'Registration' /'EventHandler'中的回調系統已經被派生類所用的虛函數替換了實現所需的響應,如調用ReceiverObject-> doStuff()。我最初的意圖是接收方對象擁有處理接收方和事件系統之間交互的註冊,所以我從你的回答中想到,接收方對象同樣擁有一個「EventHandler」實例。 – jms

1

有關參數問題 - 您可以定義基類ParamList其衍生物的模板:

class ParamList 
{ 
    const ID_Type& GetParamsType(); 
    ... 
}; 
template <typename T> 
class Params: public ParamList 
{ 
    ... 
} 

現在回調將是類型: 無效(*回調)(ParamList &); 安全使用情況,您可以添加到類註冊 常量ID_TYPE & GetExpectedParamsType(); 並調用回調

薩姆斯之前用它去通知: 無效addNotificationToQueue(INT ID,ParamList & PARAM); void addNotificationToSchedule(int ID,ParamList & param,int notificationTime);