Game Engine :: Entity Component Design - Handling Input

Started by
11 comments, last by L. Spiro 9 years, 7 months ago

I prefer to leverage game states as a means to orchestrate chunks of behavior that must coordinate with a broad range of engine subsystems.

For example, you may have a cutscene/movie subsystem that knows how to play avi files and a game state is responsible for checking whether the player has watched the intro movie and if not, instructs the movie subsystem to play it; otherwise transition to the login screen. The login state is responsible for preparing the login UI with the UI subsystem, perhaps loading the game's theme music and waiting for the user to enter their credentials. Our entire game menu/settings system which can be invoked from the login screen, character select screen, and while in game is all driven inside the game state system by pushing that state onto the active state list.

Another simple example of the game state system at work is when a user transitions from one map to another. You simply signal that you need to transition to a loading state, when you enter the loading state you know which map you need to load and so you can display an appropriate loading screen. During the update loop of this state, perhaps various things are being performed, specific tasks completion statuses being checked and when loading has finished, you pop the state which removes the loading screen and returns the player back to the game play state. Such a transition disables input to the controllers and perhaps other aspects.

As for event detection/dispatch, the observer pattern is simple and yet powerful. Most of my subsystems expose some type of listener interface that I just implement where needed. It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now. Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic. :)

Good luck!

Advertisement


As for event detection/dispatch, the observer pattern is simple and yet powerful. Most of my subsystems expose some type of listener interface that I just implement where needed. It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now. Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic.

I second this, but with an emphasize on "where needed".

Simultaneously I'm used to mention that a game usually runs continuously in a well ordered game loop, opposed to desktop applications. As a result, asynchronous input processing (asynchronous is meant here w.r.t. to the update() of a listening sub-system) means to memorize any relevant input changes locally, because a meaningful reaction can be made only when the own update() is called the next time. However, what "meaningful reaction" that is can also be determined inside update() only, because it is required to consider not only input but the entire state of the world, and that is valid only when the game loop calls the said update() method.

So question is, whether input listening is actually needed in a given use case, or whether it is even perhaps counter-productive. Patterns are fine in general, but as every tool, they have their use cases. Just "where needed"...

I prefer to leverage game states as a means to orchestrate chunks of behavior that must coordinate with a broad range of engine subsystems.

For example, you may have a cutscene/movie subsystem that knows how to play avi files and a game state is responsible for checking whether the player has watched the intro movie and if not, instructs the movie subsystem to play it; otherwise transition to the login screen. The login state is responsible for preparing the login UI with the UI subsystem, perhaps loading the game's theme music and waiting for the user to enter their credentials. Our entire game menu/settings system which can be invoked from the login screen, character select screen, and while in game is all driven inside the game state system by pushing that state onto the active state list.

Another simple example of the game state system at work is when a user transitions from one map to another. You simply signal that you need to transition to a loading state, when you enter the loading state you know which map you need to load and so you can display an appropriate loading screen. During the update loop of this state, perhaps various things are being performed, specific tasks completion statuses being checked and when loading has finished, you pop the state which removes the loading screen and returns the player back to the game play state. Such a transition disables input to the controllers and perhaps other aspects.

Basically this, although the reason I support stacks of states is to allow the lower states in the stack to maintain their current “state” while the top state interjects something on top, such as when your controller battery is about to die on a Nintendo Wii U.
Rather than going from a CGamePlayState to CLoading on top, then back to the original CGamePlayState, it’s better to go to an entirely new instance of a CGamePlayState so that you can easily release memory between stages etc. The loading screen would still be pushed on top of the CGamePlayState, but it would be at the start of a new instance rather than a singular massive multi-stage–encompassing instance.



As for event detection/dispatch, the observer pattern is simple and yet powerful. Most of my subsystems expose some type of listener interface that I just implement where needed. It's a very simple solution to implement, has minimal overhead and allows you to focus your energy in other places rather than loosing momentum designing something that is likely overkill for where you are at right now. Then when an event is fired, the class holding the listeners simply iterates the listeners, calls some virtual method and the listener implementation fires it's logic.

As mentioned by haegarr, there is a place for the observer pattern, but input has to be handled at a specific time within the game loop, not just immediately as the inputs are received. Inputs are not events.
I’ve discussed this exhaustively and posted links above.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement