Global messaging system

Started by
11 comments, last by simhau 19 years, 8 months ago
Hi. I'm designing some of the core of my game, and is having a little problem knowing if I'm picking the best solution for the job. The game will be a roguelike, so there will be many traps, monsters etc. on the map at any time. My first thought would be to use events (I'm using .Net), but thinking about it, I realised that everything had to listen to every object, so I started designing a messaging system. Every object tells the messaging system what kind of messages it wishes to listen to (attacking, door opening, player moving, monster dieing etc.). Once a player makes a move it sends a moving message to the messaging system. Everything that does something sends a message to the messaging system, and at the end of the turn, the messaging system loops thru the queue and dispatches the messages to all the objects that is interested in a messagetype like this. I've allready programmed a test, and it seems to be working ok. But this will be a very central element in the core of the game, and I do not wish to screw up being required to refactor 6 months after I start the development. Can anyone see a better sollution for a system like this? (I posted this first in software architecture, but I guess that's not the right forum)
-Simen
Advertisement
It sounds like you are looking for possible conflicts but with out a little bit more information about what you are going to try to do with your game (ai, scripting, ect) conflicts will be hard to spot.

So far it seems good though, an interesting take on the trigger mechanism.
One thing to think about, is that some of those messages might trigger other messages that should be handled during that end turn phase.
The message system idea is widely used but one of the known problems is that it could be really hard to debug.

You need to know exactly which system responds to a message at a certain time so if an error occurs you have an idea which systems you should debug.

Another thing.. when you post messages and respond to them at the end of each frame how are you going to handle your collision detection? Maybe you should create a priority system to make sure that the 'animation system' runs after the 'check collision system'...

But I think it's a great idea to keep your system as modular as possible. Modules don't know from eachother that they exist.. they just respond(or don't respond) to a certain event.

I wrote a simple message system for an 'simple game'.. It worked great but I was wondering what the speed penalty would be if all your units and other things send messages that need to be processed..

Does anyone have data on that?
What I was thinking in a game loop is that it loops thru all the messages in the system until there are no messages left (since some messages could trigger other messages) and then go on to "rendering" (it will be 2d ascii). So.. First it loops thru all the messages until the queue is empty, then render, then takes player input, and continue this loop.

I was thinking about the speed hit though. Going thru all these messages that could arise will take quite some time. As Scheermesje pointed out, there will be a lot of messages sent to the messaging system that noone cares about. And for these messages the messaging system must check all the listeners to see if they wants messages like this. Another way would be for the message system to keep track of how many are listening to each messagetype, and reject all messages that noone is interested in.

I havent done anything like this before, so I want to be aware of the pitfalls before I begin designing around this system. Thanks for the great feedback 'til now.
-Simen
The speed hit should be next to nothing, especially if you arn't rendering anything. Keep it simple and brute force, you shouldn't need to optimize messaging in a text game. But just to know, potentialy how many objects will be sending messages every frame?
If anyone's interested, there was a message thread on FlipCode about a generic messaging system that was used within a company.

I've based my mxEvolution kernel upon a similar architecture and so far, the only problem I've had is the the one mentioned before, that of debugging the message queue.

In mxE, a task or system registers itself as a handler for the message (either exclusively, or shared) so that systems can pump messages into the queue and whoever's interested picks them up. Messages can also be directed towards systems or tasks, as each one has a message queue built in. This system works as I've created an interface system allowing me to wrap messages up to be passed seamlessly along a network as well as internally. Prioritsing is done per system, so certain system tasks are given more priority to the messages, it works well - allowing me to boost the priority of the GUI task (for example, when visible) and get the messages it needs in the right oreder.

The problem I've not yet tackled is that of how to handle messages between units, such as collisions or commands. For this though, I imagine me using maybe some form of internal queue system. Again, I can imagine that a 1000 units sending a message in one frame will incur a speed hit - so you have to think about how you're sending the messages and who to. Obviously if the units don't 'know' about each other you'll need some form of central unit manager which is smart enough to grab the current frame's data and dispatch as little as it needs to get by. Maybe instead of sending 1000 "I'm dead" messages to your unit manager, you'd send one message with parameters of the dead units. I guess it's all about volumes, if you know you'll be handling a lot of messages of a given type, then why not restructure the way the message is sent (in my system a message can have 2 parameters, which can be cast).

Just a thought. I'd be interested on how others handle this problem too, because I'm in a similar state ;)
Nuget5555 :
I would guess that it will be sent around 300 messages each turn, and of wich some may respond back making it perhaps 350 messages (this is all assumtion!). It depends on what is dispatching messages. If there are 100 units on the map, and everything dispatches a message on moving, changing equipment etc. etc. There will be many messages... Another flaw I see is that if a unit/system wants to be listening to all movement it might receive 100 messages each turn where there are perhaps 0-2 messages that matters..

I was thinking about adding a range for each message, so that every listener out of range would be thrown away, but I guess that range check would result in a bigger speed hit than just dispatching all the messages...

I dont want the message system to be completly bloated with managers for each messagetype and you name it.
Anyone else has any experience designing such systems?
-Simen
I wonder if a signals and slots system would suit you well?

A search on google should point you in the right direction.

www.clanlib.org has this built directly into their game SDK. You could read their API docs/overview on signals and slots.


I'm approaching the stage where I will need to set up some kind of messaging system as you are. I've read documents from some hotshot game developers who say "everything should be an entity, and entities should inform everything via messages."

One guy presented a messaging system in C using enums for the message types. In this way you could add messages easily and quickly (just make a new member of the enum).

I'm considering signals and slots myself.
"Creativity requires you to murder your children." - Chris Crawford
I heard a lot of people mention the signal and slot thingy and I'm defenitely going to study it..

Currently I'm using the boost library to bind events to member functions.

I've got a 'base event' class which defines a function list and a pointer to the next event.

An event would inherit from the base class. Override the 'execute function' and if a function wants to respond to the event it will be added to the function list that the class holds.

I've also got a boolean option 'popped' to let me know if the event is dead(so all functions are removed from the list and the event can no longer be triggered) and a list of function names so I can remove or execute a function by name.

catch mentioned an enum to declare messages.. In my case you would just inherit a new event and register the listening functions.

Because of the boost library and the 'execute' option I've also got the ability to use different parameter lists on the different events that can be triggered(maybe it sounds trivial but it toke me some time to get it working :d)

This topic is closed to new replies.

Advertisement