16
\$\begingroup\$

My question is:

How can I handle game states in my entity system, without resorting to keeping a stack of game state objects around?

So the design of my entity system means that when an entity needs to register for input events for instance, the input component calls the input system and says "register this entity for this input". This is all fine and well, however if you add into this the concept of game states (say a pause screen), it becomes a problem to work out if an entity is in the current state and should receive the input.

I could augment the input component/system so that it says, "register this entity for this input while in these game states", but this requires that every entity know which states it's going to be used in, and that may not be obvious. Also, keeping a list of game states around per registered input (and other systems that use callbacks) doesn't sound too efficient.

Another idea I had is since there will be an entity that represents the game state, mark that as being disabled, then when generating the input event check that the entity is not a descendant of a disabled game state entity. Seems expensive to work out the parent for every callback.

Another idea is to have all the systems store their data keyed against the current state, that way when generating the input, the target entity won't even be a candidate. However this really hurts the ability to allow communication between entities in different states (not so much a problem for pause screens, but think lock picking in Oblivion/Skyrim).

The only other idea I've had is to have all components handle a state change events and communicate with their relevant system to disable anything they have registered, and re-enable it when switching back to this state.

The second (mark an object as disabled) and forth (have each component deal with state changes) seem like the best of my ideas, but none of them jump out at me as being particularly great.

Does anyone else have any other ideas on how to do this?

edit While I talk about input specifically in this question, it can mean any system capable of sending messages/events to entities, such as collisions, timer events, etc...

\$\endgroup\$
8
  • 6
    \$\begingroup\$ I do it like this: I have Screens, MenuScreen PauseScreen GameScreen, each screen can create its own World (container for Entities) and systems (like RenderingSystem) and then in GameScreen i create World, Entity with CameraComponent, and set CameraComponent.RenderTarget to screens background. This way i can add InventoryScreen that will have own entities and systems (like simplified renderer). Input can be passed from screen to world, so your userinterface will decide if it will pass input to screen (if its focused, visible etc) and that will pass input to world and entities \$\endgroup\$
    – Kikaimaru
    Commented Jan 29, 2013 at 11:42
  • 1
    \$\begingroup\$ Do these answer your question? gamedev.stackexchange.com/questions/31153/… gamedev.stackexchange.com/questions/40672/… gamedev.stackexchange.com/questions/40608/… \$\endgroup\$
    – House
    Commented Jan 29, 2013 at 15:01
  • 2
    \$\begingroup\$ @Byte56 Not really, only the first one has to do with gamestates (the other 2 are states within entities), and that doesn't really tackle the same problem that I'm having. When the game is in the paused state, something has to happen to the input system to stop it sending a movement messages to the player entity (for example), I just can't figure out a good way to do this. \$\endgroup\$
    – elFarto
    Commented Jan 29, 2013 at 16:18
  • 1
    \$\begingroup\$ OK, consider them related then. Good question. \$\endgroup\$
    – House
    Commented Jan 29, 2013 at 16:27
  • 1
    \$\begingroup\$ Something else to take into account that have been an annoyance to my component-based systems in the past: multi-layer UI. Dialog poping on top of world or multi-level screens. It has come up so far in every game I've made so I'd say to make sure to consider an approoach that can solve that problem. \$\endgroup\$
    – ADB
    Commented Feb 4, 2013 at 20:05

2 Answers 2

15
\$\begingroup\$

What is often used is an intermediate Intent System which abstracts the input and keeps track of the context and relevant gamestates.

The Intent system will stop transmitting inputs when the simulation is paused for example. It also handles the mapping between controller events and intents (move in direction, run, shoot, reload...).

This way your other conponents are not dependent on specific gamepads/inputs (BUTTON_A, BUTTON_B vs BUTTON_X, BUTTON_O...) but they all react to the same intents (IntentRun, IntentReload...).

Another advantage is that the intent system can be aware of available controllers being added/removed, as it can send intents to any subscriber even outside the simulation you can handle intents like AddPlayer(controllerID).

How much information about the game state you provide to the system either through events/message or directly is up to you. But the time invested in the Intent system is usually worth it.

You can manage Intent Contexts which will generate intents when they are attached to the system.

The context can be prioritized, i.e.:

  • SimulationAvailableContext sends intents to the simulation while it is available (but not running) for example move the camera, zoom in zoom out, add/remove player...
  • SimulationRunningContext sends intents to the simulation while it is not paused move player, send unit to position, shoot...

This way you can add and remove the contexts which are currently relevant.

And one thing about the whole intent systems is that it should run while the simulation is paused.

One way which is often used to play/pause the game simulation without breaking non simulation related updates is to use a different sets of times. i.e. GenericSystem::onTime(Long time, Long deltaTime, Long simTime, Long simDeltaTime).

With this approach your engine can simply block the increments on the games's simTime which in turn will block updates on the relevant animation & physics engines which use simTime and simDeltaTime while allowing continuous updates of your camera spring effect if it has to move even during pause, the animation of the loading effect on a virtual in-game billboard while data is being downloaded...

\$\endgroup\$
10
  • \$\begingroup\$ I like the fact that this doesn't have to call a bunch of "State Changed" functions on all the entities. You have to worry about the wrong intents being sent at the wrong time, but I think that is better than the alternative. \$\endgroup\$ Commented Jan 30, 2013 at 22:20
  • \$\begingroup\$ your entities can ignore intents like Jump while their state doesn't allow them to jump (i.e. not touching the ground). but they don't have to worry about receiving such intents while the game is paused. \$\endgroup\$
    – Coyote
    Commented Jan 31, 2013 at 7:18
  • \$\begingroup\$ I had already thought of letting the entity tell the input system what states to deliver messages in, but I hadn't thought of putting the states on the input itself, which is a good idea. Also splitting the time and simTime apart is nice too. \$\endgroup\$
    – elFarto
    Commented Jan 31, 2013 at 7:54
  • \$\begingroup\$ You should avoid bloating your simulation related state with non simulation related things. Move all UI, and player related code as far as possible from the simulation itself and in the simulation concentrate only on the intents. \$\endgroup\$
    – Coyote
    Commented Jan 31, 2013 at 12:40
  • \$\begingroup\$ Hey @Coyote, this system sounds very interesting. Could you maybe provide some more information by answering this question? Thanks! \$\endgroup\$
    – pek
    Commented May 10, 2013 at 2:53
2
\$\begingroup\$

How about creating a global event system and then have an event listener component for your each entity? After an event "Game State Change" you could fiddle with components individually for each particular entity.

Let's say you have an input component. After the event listener component receives the game state change event, it changes very specific values for that particular input component, so it wouldn't receive any input calls or wouldn't make any movement or response calls to the system or it's owner.

This works for me as most of my components are scripted (via Lua). I.e. I have an input component, which is triggered once when a key is pressed and it fires of a movement + direction and then it is triggered when the key is released and it fires of a stop + direction. There is also an event listener component which contacts the input component (if the game is paused) to stop doing any function firing and halt if necessary. I could easily then add another entity with a different reaction to the same events and keypresses using another script. This way you would save the interaction between different entities in different states and even make it much more customizable. What is more, some entities might not even have the event listener component in them. There is one drawback though - since it requires the engine core to call in scripts every time something happens, it might affect performance, but I personally haven't got any problems with this particular solution.

What I just explained is basically a practical example of your fourth solution.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .