This tutorial has been a long time coming and for anyone who has been following the other tutorials I apologize.

In this tutorial I will cover one of the most useful topics in game programming, Game States. Game States are extremely useful, lets say you have a game with a menu screen, pause screen, play screen and game over screen.

You could go ahead and do something horribly convoluted and hard to maintain such as this-

if(menuState)
{
// do this
}
if(playstate)
{
// do this
}
etc....

As you can see eventually this is gonna be extremely hard to maintain and use, so the solution is to create a way to easily switch between states, remember our Game class, everything is nicely encapsulated and set out. We can use this class with our Game State class to make Game States that are essentially like separate games, these games can be easily switched between.

So first we will create a GameState.h modelled partially on our Game.h file, so create GameState.h and start coding...

Notice the pure virtual functions (functions denoted = 0;) we use these so that we can have all our game states inherit from this GameState base class, inheritance is a topic that you should research if this concept seems strange to you.

Also notice we are passing in a pointer to a Game object, this is because GameStates may need to access some game functions as they are essentially Games themselves.

Once more thing to look at is the protected constructor, this is used so we can implement the class as a singleton, singletons are used to ensure there is only ever one instance of an object at any time, we use a protected constructor, then use a function that returns a pointer to a static instance of the class.

OK thats it for our GameState.h, since this is a pure virtual base class we will not write a .cpp file as each individual game state will overload these functions.

OK, we removed these function bodies as we now want our individual states to handle their own drawing,updating and event handling.

Now make sure this compiles, it will just be a blank window at the moment and you will have to force it to quit.

Now we need to implement our GameStates into the Game class and also create the new functions that we wrote.

So again in the Game.cpp file

#include "Game.h"
#include "GameState.h"
// constructor
Game::Game()
{
}
void Game::Init(const char* title, int width, int height,
int bpp, bool fullscreen)
{
int flags = 0;
// initialize SDL
SDL_Init(SDL_INIT_EVERYTHING);
// set the title bar text
SDL_WM_SetCaption(title, title);
if ( fullscreen ) {
flags = SDL_FULLSCREEN;
}
// create the screen surface
m_pScreen = SDL_SetVideoMode(width, height, bpp, flags);
m_bFullscreen = fullscreen;
m_bRunning = true;
printf("Game Initialised Succesfully\n");
}
/*
Our new functions, ChangeState() takes a pointer to a GameState as a parameter and then pushes that state onto the vector of pointers to GameStates, before that it uses the clean function to remove the old state from the stack.
*/
void Game::ChangeState(GameState* state)
{
// cleanup the current state
if ( !states.empty() ) {
states.back()->Clean();
states.pop_back();
}
// store and init the new state
states.push_back(state);
states.back()->Init();
}
/*
Whereas ChangeState() pushes a state onto the stack and removes the previous state, PushState() pauses the previous state before pushing a new state onto the stack, this state can then be removed and the previous state resumed. Extrememly useful for pausing.
*/
void Game::PushState(GameState* state)
{
// pause current state
if ( !states.empty() ) {
states.back()->Pause();
}
// store and init the new state
states.push_back(state);
states.back()->Init();
}
/*
Remove and resume previous state.
*/
void Game::PopState()
{
// cleanup the current state
if ( !states.empty() ) {
states.back()->Clean();
states.pop_back();
}
// resume previous state
if ( !states.empty() ) {
states.back()->Resume();
}
}
/*
These functions have now been changed so that they simply allow the current state to handle things, states.back() refers to the last element on the stack (the current state)
*/
void Game::HandleEvents()
{
// let the state handle events
states.back()->HandleEvents(this);
}
void Game::Update()
{
// let the state update the game
states.back()->Update(this);
}
void Game::Draw()
{
// let the state draw the screen
states.back()->Draw(this);
//SDL_Flip(m_pScreen);
}
void Game::Clean()
{
while ( !states.empty() ) {
states.back()->Clean();
states.pop_back();
}
// shutdown SDL
SDL_Quit();
}

Right then our state manager is now set up, now onto creating a few states for our game.
I hope it hasn't been too hard going so far and everyone is still with me.

So check that this compiles, again you will have to force quit the program.

Now lets create a state, we will create a few states but each will simply be a different image as that is the scope of the tutorial so far, and it gives us an excuse to use our Sprite class from the previous tutorial.

While writing the tutorial I realised I would have to write a function to return the screen as it is private, it is bad practice to just bluff it and make it public so try not to do it. Here is the GetScreen() function and it couldn't be simpler />/>

SDL_Surface* GetScreen() {return m_pScreen;}

Just put this function in the public: part of the Game.h file.

Ok so we have now written pretty much all we need to test our first state, so lets update our main.cpp and check it out.

You should start with a menu state and then pressing space will take you to the playstate and then pressing space will pause and unpause the playstate. I know this is quite a simple demonstration but the code written here can be used in all of your 2d games, you can create states as individual levels or anything you want. Try making a menu in the menu state and then possibly a moving sprite in the playstate.

Wow that was a long tutorial, now you know why it took so long to appear. Next tutorial will focus on creating a game object base class and deriving some objects from it.

Happy Coding, as usual any questions welcome.

Here are the files I used in the project, sorry they're big />/>paused.bmp(900.05K)Number of downloads: 800menustate.bmp(900.05K)Number of downloads: 787playstate.bmp(900.05K)Number of downloads: 694

Kakashi is cool />/>

This post has been edited by stayscrisp: 06 December 2012 - 03:46 AM
Reason for edit:: Small typo fixed

It seems to me tht you are using the ChangeState function rather than the PushState function when going into the pause state. PushState pushes a state onto the top of the stack of game states but doesn't remove the previous state, when you use ChangeState it removes the current state and pushes on a new state which means if you pop the current state off the stack there are no longer any states on the stack. Which isn't what you want.