Event Queue Design Issues

Started by
6 comments, last by Arvsgamer 8 years, 2 months ago

I'm having an issue designing a good event based system in my Java game. How it currently works is, there are subsystems: Graphics, Physics, Input, and Entity. Each one has a class that implements EventListener, an interface with a method: void act(EventMessage message). They also add themselves to the event queue's listener list. Each of the subsystems holds a reference to the EventQueue, so they can push messages into it if needed. When the EventQueue polls messages each frame, it pops the message off and invokes all listener's act method, and a listener can use the message if needed. EventMessage is simply the base class to all messages, and it holds a String name, to distinguish itself from other events passed into a listener's act method.

The problem I'm having is that I want it completely decoupled so that the Entity sub system doesn't have to know what the Graphics or Physics systems are. The way it works now, an event CreateSpriteMessage can be pushed onto the queue, and it holds a String for the texture path that the graphics will load the texture from, but the problem is that there is no way for the class that sent that message to know what the id is for that image, in this case an int index in an ArrayList. Another problem is collision detection in the Physics system, the way I have it designed, when a collision occurs, it'll push a message for the collision, but I'm perplexed on how I'll tell the Entity system what hitboxes were collided, and how the entities will know if that's their hitbox or not.

I'm just wondering if i'm implementing an event queue correctly, and if there's any practical ways to combat these issues.

Advertisement

Maybe make derived class for different kinds of events?

You could add additional information to the derived classes, eg a hitbox number, or an id numbers.

Look eg at how a GUI system passes events from the mouse and keyboard to the application.

PS I would also drop the string name, and use an enumeration instead. The number of different event types is fixed anyway, and string compare might be slow, at least an order of magnitude slower than an enumeration value check. If you use derived classes you could also use "instanceof" for testing event types, and you wouldn't need an identification of the event any more at all.

Good idea for using instanceof, I'll do that instead of names. Every event actually is derived of a base event class, and the problem is getting the index of the newly created sprite back to the entity. Your response gave me an idea of setting a member of an event to the index, and because the sender also has a reference to the message, it will also know the index of the sprite.

I'll try this and see if this works well. I'm trying to keep the design as clean as possible.

Every event actually is derived of a base event class, and the problem is getting the index of the newly created sprite back to the entity. Your response gave me an idea of setting a member of an event to the index, and because the sender also has a reference to the message, it will also know the index of the sprite.
Hmm, right. The problem may be that the sender doesn't get a signal when the value is written.

Perhaps make the event smart enough to update the data of the sender? It does feel a bit smelly though, imho, sneakily changing data.

Perhaps your message is wrong? A cleaner way could be to send back a message "new sprite BLA created with ID XYZ". The sender then gets the message, and can update its information by itself.

May I ask why you want to talk through messages instead of a simple method call? (That is bi-directional by nature.) You can define an interface for it if you like to keep things clean. If you want two systems to talk to each other at all, they need to know some stuff about each other. It's impossible not to share something. In your case they are sharing known events and their meaning. It's not much different from knowing a few method names, but more complicated, as all talk goes through an intermediate system.

I'd like to see some code first. I'm not terribly sure of your setup by reading your description.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

The problem I'm having is that I want it completely decoupled so that the Entity sub system doesn't have to know what the Graphics or Physics systems are. The way it works now, an event CreateSpriteMessage can be pushed onto the queue, and it holds a String for the texture path that the graphics will load the texture from, but the problem is that there is no way for the class that sent that message to know what the id is for that image, in this case an int index in an ArrayList. Another problem is collision detection in the Physics system, the way I have it designed, when a collision occurs, it'll push a message for the collision, but I'm perplexed on how I'll tell the Entity system what hitboxes were collided, and how the entities will know if that's their hitbox or not.

I'm just wondering if i'm implementing an event queue correctly, and if there's any practical ways to combat these issues.

You're on a good start. You mention several systems, so I recommend you think about how you've seen others do it.

Every game I've worked on has implemented a message bus or event bus as described, usually more than one.

Consider how many systems like Swing or AWT will pass around an object they'll call "FooEvent" derived from EventObject, which can be extended with whatever data is appropriate for that event.

You can do something similar. I also recommend an integer or enum value for message types since this is a much faster check, faster than either string or instanceof. If you have many message types or event types you can create a constant-time lookup table like a hash map or simple array to save time finding the event listeners. Then instead of a search it boils down to: messagebox[event.eventType].broadcast(event);

Alternatively and in various languages, you can have templates or generics to indicate what will be passed. Then it becomes something like:

Messenger<int,int,GameObject>.Broadcast(eventType, x, y, theThing);


For your physics collision event, you and then add parameters to the Event object or to the message type to expect two collision objects. Then document their order, perhaps the first is the object being applied and the second is the object being tested, or perhaps the reverse. Or for your CreateSprite message, and event type or message signature that takes a string for the image path.

The problem I'm having is that I want it completely decoupled so that the Entity sub system doesn't have to know what the Graphics or Physics systems are. The way it works now, an event CreateSpriteMessage can be pushed onto the queue, and it holds a String for the texture path that the graphics will load the texture from, but the problem is that there is no way for the class that sent that message to know what the id is for that image, in this case an int index in an ArrayList. Another problem is collision detection in the Physics system, the way I have it designed, when a collision occurs, it'll push a message for the collision, but I'm perplexed on how I'll tell the Entity system what hitboxes were collided, and how the entities will know if that's their hitbox or not.

I'm just wondering if i'm implementing an event queue correctly, and if there's any practical ways to combat these issues.

You're on a good start. You mention several systems, so I recommend you think about how you've seen others do it.

Every game I've worked on has implemented a message bus or event bus as described, usually more than one.

Consider how many systems like Swing or AWT will pass around an object they'll call "FooEvent" derived from EventObject, which can be extended with whatever data is appropriate for that event.

You can do something similar. I also recommend an integer or enum value for message types since this is a much faster check, faster than either string or instanceof. If you have many message types or event types you can create a constant-time lookup table like a hash map or simple array to save time finding the event listeners. Then instead of a search it boils down to: messagebox[event.eventType].broadcast(event);

Alternatively and in various languages, you can have templates or generics to indicate what will be passed. Then it becomes something like:

Messenger<int,int,GameObject>.Broadcast(eventType, x, y, theThing);


For your physics collision event, you and then add parameters to the Event object or to the message type to expect two collision objects. Then document their order, perhaps the first is the object being applied and the second is the object being tested, or perhaps the reverse. Or for your CreateSprite message, and event type or message signature that takes a string for the image path.

Good to know, I'll keep that in mind for my game :)

I think I got it figured out. I did what Alberth suggested and sent a message back to the sender. It works :)

This topic is closed to new replies.

Advertisement