Managing game state
From GDWiki
GameStates or Scenes:
[edit] The Problem
During the lifetime of a game application it will run through very different stages, for example, the menu and the general game logic. Scince within an engine the term Scene has been assigned for the SceneGraph systems, we use game state for this purposes. The distinction between two different states of the game is that de OnUpdate logic differs radicly, to the point that if implemented within the same method, an IF or SWITCH would have to separate them.
To make things easier than a large switch choosing from all the different states we might have we use state machines.
The basic concept of the state machine is to link the pass between one state and another through an event, clicking on NewGame in the Menu state will send an event to the state machine that will tell it to change the state to the GameLogic state. In the purposes of design you should make a list of all your applications States and then which events may occur in each one that would take the application to another state, to get a clear idea you should have an oriented graph, or digraph as a result, with the nodes being each state and the edges being the events.
Note that the change between two states does not necesarily go both ways, for example, if you are in the game and loose, you would probably go to a GameOver state showing highscores or so, but from this state you cant go directly back to the game state, you would probably have to go through the menu state again first
[edit] Implementation
Next I will explain the basics of my implementation of this concepts, there might be better ways to face it or some optimizations to it scince I dont consider myself to be a senior expert software proggramer, this system was concieved under an object oriented c++ paradigm.
First the State class: While it may implement some general funcionality this is basicly an interface, the lifecycle runs through 4 basic stages: OnInit, OnFrame, OnDraw and OnShutdown. All these will be present in the basic State class at least as an abstract method.
Additionaly, I added some general variables to it: ID (to identyfy the state within the machine with an unsigned int), a Pause flag (used to skip all or part of the update in case of true), an IsLoaded flag which I will explain later and a _MyEvent unsigned int variable for the state events.
Each different state would then be a son to this State class and override this four basic methods with its specific functionality.
The Machine:
The state machine is the base class, in here we will arrange a matrix of pointers to each different state possible, remember I talked about the states having an unsigned int ID? this was its purpose, the ID will be asigned by this manager as the states get registered to the machine, starting from 0 and so on making sure it remains unique, then come the events, in the manager we will have a 2D matrix (two dimensions array) size of #states * #difEvents. To make the matrix a little tight we will assume that an event ID 0 in one state is not the same to an event ID 0 in a different state, therefore the machine will assume its second dimention by the gratest ammount of different events given by any one state. Lets say that there are 3 different states, and they have 2, 4 and 1 events respectively, our matrix will be a 3x4 array. To make this system flexible I create the matrix dinamicly after establishing how many states and how many events my app will have.
Each line of the machine belongs to one specific state, and each column belongs to an event ID, inside the matrix I store a pointer to the state that I should go to given a specific event from a specific state. For example, I'm in the InGame state wich has ID 1, and its update returns an event ID of 2, in my game this means that within gameplay the QuickLoad key was pressed, therefore in the machine: StateMachine[1][2] I should have a pointer to the Load state. This pointer will be assigned to the CurrentState pointer.
Without any integrity checks my update will be something like this:
CurrentState = StateMachine[CurrentState->ID][CurrentState->OnUpdate()];
This line does basicly all the work by itself, so the frame overhead of the system is minimal, there should be some additional considerations however, if I swithced to a state that has not been initiated yet (maybe to keep free resources) I should load it before updating, this consideration may be taken in the StateManager's update or within each State's update, this is a design desicion I'll leave to you.
Scince every possible outcome of the state update has to return an event ID I ussualy reserve the 0 ID to a Null event, this is an event that guarranties the state will remain the same, so this particular column of the array should have pointers to the same state of the current line.
To make this dynamic and reusable, I implemented the update, draw, and shutdown of the manager leavig the Init to be overrided by each application as it wishes, also implemented some methods to make the initialization easier, so each different game I make with this system inherits the StateManager class, overrides the OnInit with the arrays composition and then runs only on the fathers methods in most cases.
[edit] Author Notes
First of all, I'm not familiar with the editing language of wiki, so I made no code insertions or anything fancy, my article is free of format and that I'll leave to the generous contribution of any of you readers.
Second, I repeat, this explains in general lines the basic concept of a State Machine as it was explained to me by teachers and peers, and offers an example implementation that might (and most likly) not be the best possibility. If anyone comes up with a better solution he is welcome to edit this or append his idea to this, I wrote this cause I already faced this problem and there was no article on this here.
Third, English is not my native language, though I'm pretty fluid in it, I most likly made several syntax and spelling mistakes, I do that even in my own language, so, feel free to correct me if that annoys you or you just feel like it
Andres "NEXUS" Chamarra

