• entries
    437
  • comments
    1000
  • views
    335615

Game Coding Complete Message Handler Upgrade

Sign in to follow this  
evolutional

104 views

For those that read my last entry, here is the upgrade to the message handler I was talking about.

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.
Sign in to follow this  


4 Comments


Recommended Comments

I guess I *could* hook this up to boost::signals (or sigslot), but the idea of this was to augment the existing code that came with the Game Coding Complete book and point out that the author presented a useful solution, but fell slightly short of the mark in terms of how he handled the game Events.

Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now