Event System in C++
|
As a part of getting input into the game I’m working on for the programming course we’re taking right now, I wanted to implement some kind of event system. I come from a background in web development, working a lot with javascript and actionscript and I tend to draw inspiration from there. I always liked the flexibility and ease of use of the event handling in javascript and actionscript, and I wanted to try and do something similar with my system. Registering an event listener in javascript looks like this: document.body.addEventListener('click', clickedHandler);
Here, A common problem when dealing with javascript events in an object oriented environment is the value of document.body.addEventListener('click', Delegate(avatar, avatar.jump));
In C++, callbacks can be done easily using function pointers, if you only need to work in the global scope that is. The equivalent of function pointers in an object oriented environment are method pointers, but they are a bit more restrictive as the type of a method pointer does not only include the return type and parameters of the method, but also the type of the containing class. A pointer to a method in a class named void (Foo::*method_ptr)(const Event&); The method can then be called with the object (foo.*method_ptr)(e); This means that in order to store such a method pointer for use as a callback, the type of the class that the callback belongs to must be known to the register function. But I need an event system that is flexible enough to register callbacks for several different types. I also need to associate the method with a context object to be able to call it at all (compare this to the js delegate mentioned above). The latter can be achieved by grouping a pointer to a context object and a method pointer in a class: class EventHandler {
public:
EventHandler(Foo* context, void (Foo::*handler)(const Event&)) {
m_xContext = context;
m_xHandler = handler;
}
void handle(const Event& e) {
(m_xContext->*m_xHandler)(e);
}
private:
Foo* m_xContext;
void (Foo::*m_xHandler)(const Event&);
};
A bunch of these handlers can then be registered by an event dispatcher and stored in a vector to be called when a certain object occurs, for example: Foo foo, bar; Game::instance()->registerEventHandler(Event::START, foo, &Foo::onStart); Game::instance()->registerEventHandler(Event::START, bar, &Foo::onStart); Here, class AbstractEventHandler {
public:
virtual void handle(const Event& e) = 0;
};
template ;
class EventHandler {
public:
EventHandler(T* context, void (T::*handler)(const Event&)) {
m_xContext = context;
m_xHandler = handler;
}
void handle(const Event& e) {
(m_xContext->*m_xHandler)(e);
}
private:
T* m_xContext;
void (T::*m_xHandler)(const Event&);
};
This enables me to store //Code from my PlayerController constructor
Game::instance()->registerEventHandler(
Event::KEY_DOWN,
this,
&PlayerController::keyDownHandler
);
Game::instance()->registerEventHandler(
Event::KEY_UP,
this,
&PlayerController::keyUpHandler
);
While not quite as easy to use as the event listeners in javascript, I feel it’s simple enough, and it’s certainly a flexible approach, allowing me to bind a callback to a specific event for a specific object of any type. If anyone is reading this who isn’t a spambot, please let me know in the comments if you know of another approach to a flexible event system in C++! |