It *should* be compatible with the code supplied with the book, I'm not 100% sure because I made a few mods to my working copy ;)
First we need the functors. These allow you to make the callbacks to your class member functions. The functor has the same prototype as the IEventListener
bool function_name( Event const &a_event );
class IEventHandlerFunctor{public: explicit IEventHandlerFunctor() { } virtual bool execute( Event const &a_event ) = 0; virtual EventListenerPtr getListener() = 0;};typedef boost::shared_ptr IEventHandlerFunctorPtr;template <class T>class EventHandlerFunctor : public IEventHandlerFunctor{public: typedef bool (T::*handlerProc)( Event const &a_event ); explicit EventHandlerFunctor( T *a_inst, handlerProc a_proc ) : m_inst(a_inst), m_proc(a_proc) { } bool execute( Event const &a_event ) { return (*m_inst.*m_proc)( a_event ); } EventListenerPtr getListener() { return reinterpret_cast( m_inst ); }private: T *m_inst; handlerProc m_proc;};
You will notice that I typedef IEventHandlerFunctorPtr as a shared_ptr, which should allow us to throw the functors around and have them cleaned up after us.
From here, we have an implementation of the IEventListener interface, called EventListener. This class is what we'll be deriving all of our classes which are supposed to be handling messages.
class EventListener : public IEventListener{public: virtual ~EventListener(); // Interface for IEventListener bool handleEvent( Event const & a_event ); IEventHandlerFunctorPtr registerEventHandler( EventType const &a_type, IEventHandlerFunctorPtr a_handler ); bool removeEventHandler( EventType const &a_type ); bool isEventRegistered( EventType const &a_type );private: typedef std::map< EventType, IEventHandlerFunctorPtr > EventMap; typedef EventMap::iterator EventMapIterator; typedef std::pair< EventType, IEventHandlerFunctorPtr > EventMapPair; EventMap m_eventHandlers;};
You'll notice that it implements the IEventListener interface as it should, but it is no longer virtual, meaning the messages stop here ;) Whenever a class needs to handle a message it must now register the message type and the functor with itself. This, in turn, will register the class with the global EventManager and will forward the messages on to the functor specified at registration. The rest of the implementation follows:
EventListener::~EventListener(){ EventMapIterator it = m_eventHandlers.begin(); while ( it != m_eventHandlers.end() ) { IEventHandlerFunctorPtr h( it->second ); removeGlobalEventListener( h->getListener(), it->first ); ++it; }}bool EventListener::handleEvent( Event const & a_event ){ // Find the handler based on type IEventHandlerFunctorPtr h; EventMapIterator it = m_eventHandlers.find( a_event.getType() ); if ( it != m_eventHandlers.end() ) { h = it->second; return h->execute( a_event ); } return false;}IEventHandlerFunctorPtr EventListener::registerEventHandler( EventType const &a_type, IEventHandlerFunctorPtr a_handler ){ IEventHandlerFunctorPtr h; EventMapIterator it = m_eventHandlers.find( a_type ); if ( it != m_eventHandlers.end() ) { h = it->second; } m_eventHandlers.insert( EventMapPair(a_type, a_handler) ); safeAddListener( a_handler->getListener(), a_type ); return h;}bool EventListener::isEventRegistered( EventType const &a_type ){ EventMapIterator it = m_eventHandlers.find( a_type ); if ( it != m_eventHandlers.end() ) { return true; } return false;}bool EventListener::removeEventHandler( EventType const &a_type ){ EventMapIterator it = m_eventHandlers.find( a_type ); if ( it != m_eventHandlers.end() ) { IEventHandlerFunctorPtr h = it->second; safeDelListener( h->getListener(), a_type ); m_eventHandlers.erase( a_type ); return true; } return false;}
USAGE
Usage is pretty simple and can be used with the existing Game Coding Complete system. You create your own events with their datapackets first. I created a simple event BeeSeven_Event which I want my class to handle. The class itself is very simple:-
class TestListener : public EventListener{public: TestListener() { registerEventHandler( BeeSeven_Event::gkName, IEventHandlerFunctorPtr( new EventHandlerFunctor ( this, &TestListener::handle_b7 ) ) ); } virtual ~TestListener() { } bool handle_b7( Event const & a_event ) { std::cout << "bee seven"; return true; }};
You will notice that we *must* register the handler functions for each class instance. For this I do it in the ctor, but you may want an Init() method or something.
And that's it... Your TestListener class will register itself to listen to 'b7' events (plus any others you want) and will unregister the handlers when it destructs.
TestListener t;BeeSeven_Event b7;safeTrigger( b7 );
And there you have it. Any improvements are welcome.