Quote:Original post by masterbubu
This way the AI engine does not communicate with physics engine directly. This allows the components be undependable, so you can replace subsystem without effacing the others.
The idea behind interfaces is the same: if a subsystem provides a decent interface (classes, functions, expected behavior), then it's underlying implementation can safely be changed without breaking code that uses it, as long as the interface itself is not changed.
If I call renderer.DrawRectangle(x, y, width, height, color), then I don't care what renderer does under the hood. Perhaps it uses OpenGL, perhaps DirectX, perhaps software rendering? As long as it does what it's expected to do you can swap the underlying code without affecting the calling code.
In the end, you're going to have some sort of interface. Whether that's a direct code interface, or a more abstracted form of messaging, if you need to work with a subsystem you will need to know something. You'll just want to limit that to what's necessary.
Quote:My question was: how can I build such a message queue?
As an example, every time a collision occurs, the collision system could send a message to the collision message queue. This could be an object that describes what objects collided, their contact points, the forces involved, and so on. Another subsystem could check the queue and notice that a collision message was posted. It can then react to it based on the stored information. So yeah, as the name implies, it's a queue of messages.
Another approach would be to bind callback functions to certain events. Some code that needs to know about key presses from the input subsystem would tell the input subsystem: when this event type occurs, call this function. The calling code no longer has to poll for messages - instead, it will be informed whenever that event occurs.
In both cases, events or messages can be represented with classes. For example, a CollisionEvent could look like this:
class CollisionEvent{ CollisionObject* objectA; CollisionObject* objectB; Point collisionPoint;}
With the queue, you'd store them in a queue and you'll let other subsystems read from that queue. With a callback system, you send them directly to all subsystems that registered themselves (of course, they'll need to provide a function that accepts such an event object as an argument). With both approaches, other subsystems still need to know what sorts of events to expect, otherwise they can not meaningfully work with them.
As you can see, there are multiple approaches possible. Which one to choose depends on your requirements - so it really helps to be specific.