Jump to content
  • Advertisement
Sign in to follow this  
JimmyDeemo

Switching gamestates.

This topic is 3871 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Right now i'm sorting out my gameflow and how my game changes from state to state. What i've got is a GameState base class that other states have to derive from and override functions. I'm going to create a State Manager that will have a stack (implemented as a boost::ptr_vector) that will simply run the Execute function of the GameState at the top of the stack (Note: the Execute function hadles moving that state from Init to Updating to Cleanup) I'm having trouble getting my head around moving between states though. I am fine with once a state has finished, i can just have my Execute function return true. Test for this in the state manager, like this;
if( topOfStack->Execute() )
{
   m_stateStack.pop_back();
}

This will pop the state off when done and the previous one will resume where it left off. But what if say a Menu state wants to move to a Play state. I had the idea of passing a pointer to the state manager to the Execute function, then letting the state do something like this;
Execute( CStateMan* manager )
{
  /*code removed*/
  if( /*something*/ )
  {
      manager.PushState( new CPlayState );
  }
}

But this would mean i'd have to include all header files for states that it could move to. So could i have a header file that has an enum or defines for all my states and include that. Then pass the appropriate ID to the PushState function. Then the state manager can do some kind of lookup and push the right state on the top of the stack. Like this;
Execute( CStateMan* manager )
{
  /*code removed*/
  if( /*something*/ )
  {
      manager.PushState( ePlayState );
  }
}

CStateMan::PushState( int StateID )
{
   switch(StateID)
   {
      case ePlayState:
      m_stateStack.push_back(new CPlayState);
      break;
   }
}

I'd appreciate some oppinions as to if the above is an ok idea or maybe some alternative ideas. Thanks.

Share this post


Link to post
Share on other sites
Advertisement
I have the State class taking a reference to the state stack in its contructor. This is stored in a private variable. The state has a protected function "setState", which takes a boost::shared_ptr<State> and pushes that onto the state stack. This way the inherited states do not need to include the state stack header.

Alternatively, you could have Execute return a (smart) pointer to a state. This is probably easier and better.

Share this post


Link to post
Share on other sites
I think that's a little over-engineered. I like to keep things simple: instead of an explicit state stack, I use function scope. Whenever a state's function is called, a new state is essentially "pushed" onto the stack and the function takes over program flow. When the function returns, the state is automatically "popped" off the implicit stack:

#include <iostream>

void newgame();
void highscores();
void credits();

int main(){
bool running = true;
char choice;

while(running){
cout << "Main Menu" << endl;
cout << "1 - new game" << endl;
cout << "2 - high scores" << endl;
cout << "3 - credits" << endl;
cout << "4 - quit" << endl;

cin >> choice;

switch(choice){
case 1:
newgame();
break;
case 2:
highscores();
break;
case 3:
credits();
break;
case 4:
running = false;
break;
}

}
}


Share this post


Link to post
Share on other sites
I guess i'm not making to much sense. I'd like to keep a state stack like this rather than using a switch statement.

I know that i can reference the state manager or even just take a pointer to the stack like rip-off suggested. But lets say inside my MenuState class i want to move to the play state, if i had a pointer to the state manager i would call;

pStateMan->PushState( new CPlaystate );


But lets say my app gets more complicated and i have a possible of 5 states to move to from my MenuState class, i would have to include all the header files so i can use the new keyword followed by the class. I'd like to avoid that if possible.

But if my plan is totally out there then please suggest something else. Maybe i could implement my State base class better.

Share this post


Link to post
Share on other sites
Quote:
But lets say my app gets more complicated and i have a possible of 5 states to move to from my MenuState class, i would have to include all the header files so i can use the new keyword followed by the class. I'd like to avoid that if possible.


You asked for alternative ideas, so here is my take. Are you trying to make a game or are you just experimenting with system design for fun? If you are trying to make a game and get something done, then it sounds like you are falling in to the YAGNI trap. Generally, you should write code to satisfy your current requirements and not spend an exorbitant amount of energy trying to capture future "what if" requirements. If you are just designing for fun and are not concerned with actually getting anything done, then there is no correct answer. You can fiddle with your game state system until the end of time.

Share this post


Link to post
Share on other sites
Another way is to have each particular GameState determine which GameState to switch to. This method doesn't involve a stack, but depending on how you choose to implement it may have StateManagers.

Perhaps something like this:


public GameState {
private:
Game* game;
public:
public GameState(Game* g){ game = g; }
virtual void Enter(Game* game) = 0;
virtual void Execute(Game* game) = 0;
virtual void Exit(Game* game) = 0;
};




public Game {
private:
// If each Game didn't store its own states then you'd need a way for all states
// to get a handle on other states so they can change the state of the Game
// to that (either a StateManager or each GameState as a Singleton)
GameState* previousState;
GameState* currentState;
...
// OR if you have each Game store its own states then you'd have to provide
// getter methods for the states to use to change the state of the Game
GameState* MainMenuState;
GameState* PlayState;
GameState* PausedState;
GameState* ExitState;

public:

GameState* GetMenuState(){ return MainMenuState; }
GameState* GetPlayState(){ return PlayState; }
GameState* GetPausedState(){ return PausedState; }
GameState* GetExitState(){ return ExitState; }

...
void ChangeState(GameState* state){
currentState->Exit(this);
previousState = currentState;
currentState = state;
currentState->Enter(this);
}
...
};

// Game constructor
void Game::Game(){
MainMenuState = new MainMenuState(this);
PlayState = new PlayState(this);
PausedState = new PausedState(this);
ExitState = new ExitState(this);
...
}




void MainMenuState::Enter(Game* game){
// Do something
game->DoSomething();
}

void MainMenuState::Execute(Game* game){
// Show the menu
if(user clicks Start) game->ChangeState(game->GetPlayState());
if(user clicks Exit) game->ChangeState(game->GetExitState());
}

void MainMenuState::Exit(Game* game){
// Do nothing...or play a sound
}



This should give you an idea of another way of handling States.

[Edited by - Shakedown on March 17, 2008 2:10:43 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!