Message System, C++

065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 Sep 30, 2004 at 16:03

I’ve been working away at a simple game framework, and came into a problem/design requirement that I’m sure most of you have faced plenty of times, needing a robust messageing system between objects.

For Keyboard event notification, settings update propagation and so on

I’ve thought lots. but havn’t really came up with a nice OOP way to work it. Please hit some ideas at me with a cluebat :)

14 Replies

Please log in or register to post a reply.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Sep 30, 2004 at 16:34

Setup one object that controls the messages. The most generic way is like the windows message queue. You can probably find a more specific way of doing this that works better when you restrict the domain to your game framework.

When objects want to find out if the keyboard has been pressed they ask that object. When objects want to simulate a keyboard event they tell that object.

065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 Sep 30, 2004 at 18:11

@NomadRock

The most generic way is like the windows message queue. [snapback]12184[/snapback]

Any more info? I’ve never programmed on Win32.

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Sep 30, 2004 at 20:24

Basically a queue<Message> ;)

Look for PostMessage, GetMessage, PeekMessage, MSG in the online MSDN.

065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 Oct 01, 2004 at 04:40

Okay, thanks. I’m going to look at more event based models however.

Thanks :)

F7a4a748ecf664f189bb704a660b3573
0
anubis 101 Oct 01, 2004 at 11:32

When objects want to find out if the keyboard has been pressed they ask that object. When objects want to simulate a keyboard event they tell that object.

i find event polling unelegant somehow. objects shouldn’t have to know where the events come from. they should just have to specify which events they want to capture (keyboard or mouse for example) by deriving from some receiver class or provide a delegate for that (depending on the language you use) and receive the events once they happen

D5a77f73a82eeeafd6fb30177f2b5cc5
0
Decibit 101 Oct 01, 2004 at 12:06

That is the messaging system from my project. It is not necessary good for everything, I just wanted to make my input platform-independent. The idea is to use Context-Receiver scheme.

struct Message
{
...
};

class Receiver
{
    virtual void onKeyDown(unsigned short key, unsigned rep)=0;
    virtual void onKeyUp(unsigned short key, unsigned rep)=0;
    virtual void onMouseDown(int x, int y, unsigned button)=0;
...
};

class Context
{
protected:
    Receiver*   m_pTargetReceiver;
public:
    virtual ~Context()=0;
    virtual void update()=0;
    virtual Receiver* setTargetReceiver(Receiver* tr)=0;
    virtual void sendMessage(Message mes)=0;
...
};

The system proved to be good for aboth ssinchronous and synchronous events handling.

The framework installs Context.
User adds custom Receiver to Context.
The system scans hardware when updates and sends corresponding messages to the Receiver.
User can send own messages through sendMessage function.
Context-Receiver pairs can be written for most subsystems. The code above is just the example of doing it for input.

Maybe that helps.

22b3033832c5c699c856814b0cf80cb1
0
bladder 101 Oct 01, 2004 at 13:19

here’s something really quick and dirty:

class Event
{
 union
 {
  struct
  {
   char ScanCode;
  };

  struct
  {
   int MouseButton;
  };
 };
};

class Receiver
{
 virtual HandleIOEvent( Event* pe ) = 0;
};

class MouseReceiver : public Receiver
{
 virtual OnWheelRotate( int amount ) = 0;
 virtual OnLeftButtonDown() = 0;
 virtual OnRightButtonDown() = 0;
};

class KeyboardReceiver : public Receiver
{
 virtual OnKeyUp( char k ) = 0;
 virtual OnKeyDown( char k ) = 0;
};

class EventManager
{
 static vector<KeyboardReceivers> m_KRs;
 static vector<MouseReceivers> m_MRs;
 static RegisterKeyboardReceiver( KeyboardReceiver* pkr );
 static RegisterMouseReceiver( MouseReceiver* pkr );
 static HandleIO()
 {
  // get keyboard and mouse info, iterate through all keyboard
  // receivers and mouse receivers and handle events
  for( each keyboard/mouse receiver handle IO depending on type )
  {
   switch( IOType )
   {
   case KeyUp:
    // Go through keyboards and call the OnKeyUp function
   case KeyDown:
    // Go through keyboards and call the OnKeyDown function
   // etc...
  }
 }
};

You basically have your IO module right. And your IO manager checks if any input has taken place, then tell the objects that can handle any type of input to handle it. This way, objects dont have to constantly scan for input. When input happens, they’ll be told it happened and can do what they want. Any object that wants to handle the keyboard/mouse will have to register itself with the manager. ie:

class Player : public KeyboardReceiver
{
 Player()
 {
  EventManager::RegisterKeyboardReceiver( this );
 }
 OnKeyUp( char k )
 {
  // do whatever
 }
};
065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 Oct 01, 2004 at 14:54

Wow! Thank you very much.

Boost is interesting, however I don’t like having so much abstracted from me, when I can write more specific code to do the same task.

Decibit, your approach was interesting too, and I think I’ll go for an approach similar to Bladder’s subscribe/manager pattern.

Thank you, I’m all sorted now :)

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Oct 01, 2004 at 17:58

Good, glad you found your way.

6e0b32504d31ae07efc17f3322cdb147
0
SnprBoB86 101 Oct 01, 2004 at 18:03

never underestimate the awesomeness of boost…

899ea4117c35b7d0ed9f6fed9673e667
0
grusifix 101 Nov 20, 2004 at 11:32

@bladder: Looks lot a like Observer-pattern (?)

Bb7748a48312cc943e856f42b2263ca3
0
Madgibs 101 Mar 03, 2005 at 15:42

You might also consider the Windows GetAsyncKeyState() function to test for whether or not a key is down.

065f0635a4c94d685583c20132a4559d
0
Ed_Mack 101 Mar 03, 2005 at 16:14

It’s Linux ATM, so I wanted to write it OS agnostic. I went for the Publisher & Subcriber / Observer pattern, and it’s worked very nicely so far. Thanks Bladder and rest :)