Friday, October 3, 2014

Getting the Message

Hello long-neglected blog viewers!

I won't get into a lengthy discussion about why I haven't posted for ages, but it sounds a lot like, "I can't post that because it's spoilers, I can't post that because it's boring, I can't post that because I'm busy working, I can't post that because I'm not at my computer, and I can't post THAT because... well, that raid's not going to heal itself now, is it?"

The short version: Game is still in progress. Engine is kind of nice. Music is coming along. Level design is not there yet, but making definite progress. I want to show stuff, but greyblock art is maybe not a good first impression, so I'm working on some prettying up.

Short-ish term goal:  Get a single level together for design and engine testing.

So, let's talk code.


typedef void (*Fn)(const string &);
typedef VSTACK<Fn> FnList;
typedef MAP<string, FnList> StringFnMap;

class cMessageHandler
{
 FnMap mFnMap;

public:
 void Register(const string &name, Fn fn)
 {
  mFnMap[name].push_back_resize(fn);
 }

 void Unregister(const string &name, Fn fn)
 {
  mFnMap[name].find_erase(fn);
 }

 void Call(const string &name, const string &s)
 {
  FnList &f = mFnMap[name];
  for(FnList::ITER it = f.begin(), end = f.end(); it != end; ++it)
  {
   (*it)(s);
  }
 }
};


Basically, it's just a list of functions listening to a particular message ID (string), and a function to broadcast a message (string) to each of them.  It's using my own containers, but you could use std::vector and std::map easily enough instead.

I also have a version that handles member functions - you just need to store the "this" pointer and a redirect function for each class, similar to a delegate.

This makes it pretty easy to send messages or triggers between components from data - there's no need to create a message ID or bind to specific functions in each class.  Instead of writing a bunch of custom code for each class to bind it to other components, they just need to send or listen to the same message name.

My project has a "game" library, which has many generic game components in it.  It is not supposed to have any game-specific code or logic in it to make it easier to re-use in a new project.  This was causing some problems connecting generic components to game-specific components, but this system lets me hook them up in data without the game library knowing anything about the game-specific stuff.

Initially I found this system kind of worrying, mostly because it involves so many strings.  It's the old-school hacker mentality, where individual bytes and cycles were of vital importance.  Well, you still probably need to be a little gentle with it - it's for events that happen only occasionally. Overall, I think it's worth being able to easily bind events from data.

So, yes, still working on things.  :)  I will try to update more often, not sure of the frequency yet!

No comments:

Post a Comment