Finite-State Machine in the game StoneDrop
I use a state machine approach (see more examples at gamedevelopment.tu...) in my
Referee class to be able to control all the game (I mean gameplay) events and at the same time to encapsulate all the logic behind them in one class. So the
Referee holds a field that stores the current state of the game and there are some methods in
Referee which allow somebody outside (in my case it's a GameController) to change the current state. Any such method can be executed only if the game is in a particular state now and demand as a parameters all the data that is required to proceed from this state to another one. The body of those methods contains core game logic (
Referee operates with objects that hold information about field, turn queue, score, game record, etc.) and all kind of game events calls. So the workflow is the following: the GameController creates a
Referee and then use it's methods as a transition from one game state to another until the game ends; during the View initialization all view classes get a link to the
referee with the current game and subscribe to events they depict on the screen; GameController in some cases may look at some of the View or Input classes and make decisions on what
Referee's method to call based on input or view information (for example wait for the end of an animation or the user input).
The the following game states were used (look at the picture attached, but keep in mind that there is an ambiguous terminology here: the orange "state changed" blocks refer to inner game-recording system, not the
Referee state machine):
Not Ready - initial state,
Referee automatically proceed from this state to
Ready and only stays here if it encountered any critical bug (incorrect level information, corrupted game record, etc.),
Ready - means
Referee initialized successfully, all objects required for the game were created and prepared. If method StartGame will be called then
Referee will fire the event GameBegan and will switch to the state
Active - one of the main game-cycle states. It means that game is going on, but no one is able to make a turn right now. This state is used as an intermediate between two turns and generally automatically switched (by the GameController) to the next one right after all the animations are finished. The transition method is
StartNextTurn which checks some game rules and prepares player and timer to the next turn. It's also possible to end the game from this state.
ActiveTurn - the second and the last of the main game-cycle states. It means one of the players has an ability to make a turn now. Right after the player approve his decision or when turn time is over - the method
FinishTurn starts and modifies field and player score if necessary. The
Referee may end up in two different states after the
FinishTurn was called:
Scored - means one (or more) player(s) get a score point(s) after the previous turn. The transition (
ContinueGame) from this state depends on the game rules and current game situation. If any of the players reached a win-score or if any of the players ran out of global time (like in chess competitions with limited overall time) or if the field is full and the field reset is not allowed by the rules then
Referee will end up in the
Ended state. Otherwise - it will be in the
Ended - timers stopped, all game ending events fired, game results and game record created. Now it's possible to return to the main menu, or to restart a level (or to start the next one).
Because the whole game logic is encapsulated in
Referee and it's not dependent on any View events (but only controlled by the GameController) it's possible to use the same
Referee class in other cases. For example - automated AI players tournaments without any visualization. In such a case it's necessary to write another GameController which will create any of the View objects and just run hundreds of AI games to determine the most intelligent algorithm. But even if another GameController is needed we don't have to re-implement any of the game logic in it, just a sequence of
Referee method calls.
PS: In my case the finite state machine implementation differs from the traditional State Machine programming pattern. You can read very good explanation of such a pattern with examples and details related to game programming in the book "Game Programming Patterns" by Robert Nystrom.