Ever since I started building games, back at the start of 2012, I’ve been using a fairly cumbersome Finite State Machine to switch states. This involved the use of a StateManager class to keep track of the current state I’m in, combined with a switch statement of varying size (depending on the number of states in the game) to switch between the different states. This was a fairly good design in my eyes, but I always knew there was a better way to do it through usage of the State Pattern. This would ideally mean that to change states all I’d need was to call a changeState function that took a pointer to the new state and deleted the old state.
After plenty of searching through Google, gamedev, stackoverflow, GameDevNet et al, I finally stumbled across a tutorial that explained the idea and provided enough concrete examples for me to build my own system off the back of it. Given the new found freedom of a programming a new engine in SDL 2.0, I took this idea and ran with it.
So now my State class now has these 5 pure virtual functions:
virtual void enter(Engine* engine) = 0; virtual void handleEvents(SDL_Event& e, Engine* engine) = 0; virtual void update(const double dTime, Engine* engine) = 0; virtual void render() = 0; virtual void exit(Engine* engine) = 0;
These obviously all have to be overridden in any derived classes, such as Title, Level and GameOver. The Engine*’s are used for calling the changeState function that is inside the Engine class (actually the StateMachine class, but it is called from the Engine class). Enter and exit are called at the start and end of the class’ lifetime to perform any special functions that are needed.
Keeping track of the currentState that the game is in is no longer controlled by the Engine class itself, but is now operated by a StateMachine class, which is much like the StateManager class I used to operate (in some ways). The StateMachine class is very simple:
void setCurrentState(State* s) ; State* currentState() const; void changeState(State* newState);
One to set the currentState, one to return it and one to change it. ChangeState isn’t even a difficult function:
if(typeid(*mCurrentState) == typeid(*newState)) { delete newState; return; } mCurrentState->exit(mOwner); delete mCurrentState; mCurrentState = newState; mCurrentState->enter(mOwner);
The first if statement stops us from changing from the state we’re in to the state we’re already in, using a wonderful feature I’d never encountered before in C++, RTTI (run time type information). This can work out what type a variable is whilst the program is running. For our pointers to State, we have to dereference them to find out what they’re actually pointing to. This little bit of code is put in because in the Engine class when we press the Esc key it changes state to the Title state, but if we’re already there there is no point in creating a new instance of it. We then exit the currentState, delete it, assign the newState to it and finally enter the state.
The Engine class then contains a StateMachine* within it, which is initialized in the body of the constructor (as we’re passing the “this” pointer into the constructor we can’t assign it in the initializer list) and the currentState is set. To change state from, say, the Title to the Level we can call one line of code, which is in the mouseClicked() function for Title:
engine->changeState(new Level(mediaCache));
No calls to any external classes are needed, there is no need for a big switch statement to take place, the Engine which seamlessly switch from the Title to the Level and all will be good with the world. Any other states that are introduced won’t mean having to rewrite the StateManage enum and extending the switch statement in the FSM, we can just create a different State* instead, i.e.
engine->changeState(new HighScore(mediaCache)); //or maybe... engine->changeState(new GameOver(mediaCache));
Leave a comment