If you need to represent multiple states and transitions between them. For instance, your game has can be running, paused, over, and showing credits with a set of possible conditions which moves from one state to another. When your game approaches this level of complexity it behooves you to adopt this pattern.
This pattern breaks up your game code into a set of discrete parts. Once broken up it's easy to determine what each state does and how it transitions to other states.
There are two ways to implement this pattern. The simplest way is to create an enum representing each state in the game. After that you can sequester state specific code inside conditionals as follows:
private enum InGameState { RUNNING, GAME_OVER }; private InGameState state; switch (state) { case InGameState.RUNNING: // keep running if (lives == 0 || score > MAX_SCORE) { state = InGameState.GAME_OVER; } break; case InGameState.GAME_OVER: // display game over screen if (newGameButton.pressed()) { lives = 3; score = 0; state = InGameState.RUNNING; } break; }
The advantage to this approach is that the state specific code is obvious. However, as you can probably guess this gets really messy fast when dealing with many states and transitions.
That's why we have a second heavy-duty pattern which uses the State and StateManager. Please see Decoding State Machines for an in-depth walk-through of this approach with code examples.
In a nutshell, this approach separates the state specific behavior into separate private class which implement the State pattern. This cleans up all the conditionals found in the simple approach. It's now easy to tell what each state does and how it transitions to other states.
Adopting this pattern helps tease out complex state machines into discrete parts which can be more easily understood and maintained. This makes it easier for you or future developers to fix bugs or add new features to the system.
Depending on how far you take it, this pattern can force you to expose functionality or state that would otherwise remain private. It is also possible to go too far with this pattern and over design the solution. Make sure to balance the trade off between maintainability and encapsulation.