Hi everyone,
There's an issue that's been bugging me for a while now and I'd like to resolve it before I move on with other things. I've been working on my own little C++/SDL/OpenGL/ECS game framework/engine for a year or so now and it's coming along nicely (and thanks to anyone here who's helped me in the past).
BUT I'm struggling to realise the best way to implement event messaging system correctly with ECS. The way I originally implemented it
- The messaging system sends all messages at the beginning of the step
- Each system only receives the event types it has subscribed to
- Each system will read its mailbox immediately and then do everything (e.g. find collisions, render, etc..) its designed to do
- Finally, each system sends messages to the messaging system at the end of the step.
So I realised that there might be some cases where an event only gets processed a frame or two later, but was happy to accept this at the beginning. Except now I'm getting quite complicated event-chains. Take the following example
- User presses key (or touch pad or other input). Key press event sent to command system (e.g. KEY_EVENT, 'UP_ARROW')
- Command system finds matching command to input and generates command (e.g. MOVE_EVENT, 'PLAYER_MOVE_UP')
- Physics system, or player script, processes command and sends command to actually move entity (e.g. MOVE_ENTITY, 'UP')
- Rendering system updates position of entity and renders entity at new position
So, in this case there are 4 frames before the player will actually see the entity move. This obviously means a noticeable delay depending on the framerate (e.g. about ~0.07 sec for 60fps, ~0.13sec for 30 fps). Now I know about the whole 'fix-your-timestep' stuff, but that's not the issue really. Unless I use a crazy high game timestep, this can give issues with responsiveness no matter what
So there are several ideas that come to mind :
- Have an immediate event dispatch mode, where systems can send events and even receive replies in the same timestep. This would help but would surely cause problems with concurrency of the (otherwise independent) systems. Plus I'm not sure how I would implement this anyway.
- Allow systems to ask a limited set of queries of other systems directly. For example, a touch event (on a mobile) might enquire to the collision system if there is a selectable object at the touch coordinates and return either a valid entity id or nothing. The main problem is this causes a little inter-system dependency, something the ECS with event system tries to avoid. Second, each system might be updating that data when the query is made; this can be solved by double-buffering the data but might be expensive (memorywise) for each system. But then this would allow safe queries to be made of other systems provided it doesn't change any data (which it shouldn't).
Anyway, I don't want to overthink it too much but I surely need some solution since my original 'one send-one receive-per step' approach is surely not good enough. If anyone has encountered similar problems, or has experience with ECS systems and realises I am doing things completely wrong, then I would love some advice :-) . Thanks!