简体   繁体   中英

C++: event system implementation for a game engine

I am planning an event driven game engine. The basic idea is that instead of having everything talking to everything, everything would talk to the event system, which would relay the messages to their recipients, without coupling the recipients to the notifiers or the other way around.

  • Objects register themselves to the event system. A notification ID and a pointer to a callback function are passed as parameters of each registration command.
  • Objects add notifications to the event system. The ID of the notification is passed as a parameter of each notification. The notifications are added to a queue holding all pending notifications.
  • Additionally, the event system supports scheduled notifications. The notification ID and the future time of execution are passed as parameters of each notification. The scheduled notifications are then stored in a data structure ("schedule") holding the scheduled notifications in order of the future time of execution.
  • An invoker object commands the event system to process all queued notifications. The event system fetches the notifications in order, and calls the callback function of each object that has registered itself with the same ID as the current notification.
  • An invoker object commands the event system to process one scheduled notification. The oldest notification is fetched from the schedule, and the callbacks of all objects registered with the same notification ID are called.

.

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();
}

However I am not entirely satisfied with this solution, mostly because the system does not allow easy passing of parameters to recipients, and I am skeptical about callbacks to member functions, is it good design practice? What about the method/class/variable names I have come up with? Constructive criticism, guidance and alternative approaches to the problem are welcome.

It is not strictly related to your question, but speaking about design, I'd avoid using a global notification system 'for everything' as I've seen bad consequences in the past. You'll just tend to use a heavy event system in places where one object would just call some method on another object.

Specialised templatatised systems work better, ie the systems that allow you to control objects' lifespan and that are designed to handle events of particular types and known parameters in them.

Any case, you'll find it hard to solve problems such as pending events wating for delivery to already-killed recipients.

I personally would have a interface class of EventHandler , that you can register, which will have a virtual action function (and perhaps a function for the event system to tell the class that it's being unregistered). This completely avoids callbacks, and the actual implementation of the EventHandler will have the possibility of holding other data (or references to other data).

For the parameters issue - You can define base class ParamList whose derivates are templated:

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

now callbacks will be of type: void (*Callback)(ParamList&); for safety usage you can add to class Registration const ID_Type& GetExpectedParamsType(); and use it before calling the call back

sames go for notifications: void addNotificationToQueue(int ID, ParamList& param); void addNotificationToSchedule(int ID, ParamList& param,int notificationTime);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM