5
\$\begingroup\$

I just started working on my game, mostly the game management. I plan and using game-states to make the menu's and other stuff easier.

My main idea for implementing the game-states is creating a game object and passing it as a reference to classes which control the current state, then storing the game-state classes via references inside a vector.
My main concern is that is this the better way to do it? Or should I implement it differently? Also, when you do use game states, where does the game loop go? Does it go inside a state such as gamePlaying or is it put somewhere else?

Hopefully someone can clear this up for me, thank you!

\$\endgroup\$
4
  • \$\begingroup\$ What is a "game-state"? \$\endgroup\$ May 11, 2012 at 0:07
  • \$\begingroup\$ also called gamestate; it's a system that allows you to easily switch between sections of the game like menus, credits, and gameplay. \$\endgroup\$
    – Rivasa
    May 11, 2012 at 1:46
  • \$\begingroup\$ MikeC seems to think it's something different. He seems to think it's the difference between in-game states like playing, paused, etc. As opposed to higher-level things like main-menu, in-game, etc. So which is it? \$\endgroup\$ May 11, 2012 at 1:56
  • \$\begingroup\$ this is the latter; higher level things such as main-menu, in-game and so on. \$\endgroup\$
    – Rivasa
    May 11, 2012 at 1:58

4 Answers 4

9
\$\begingroup\$

I usually implement a state-machine similar to this:

StateMachine
   + changeState(State)
   + getCurrentState()
   + update()

State
   + enter(StateMachine)
   + update(StateMachine)
   + exit()

When a state becomes the active state, the StateMachine calls the enter method. The StateMachine continiously calls update on the active state. When the state changes, exit will be called on the currently active state. The StateMachine passes itself as parameter to the enter and update methods, so that the State can initiate a state-change by itself.

Here's a pseudo-code example.

StateMachine:

// example for the StateMachine
Game implements StateMachine
{
    void changeState(State newState){
        if(currentState){
            currentState.exit();
        }

        currentState = newState;

        if(currentState){
            currentState.enter(this);
        }
    }

    State getCurrentState(){
        return currentState;
    }

    void update(){
        if(currentState){
            currentState.update(this);
        }
    }
}

Example State:

// example for a state implementation
IntroState implements State
{
    void enter(StateMachine sm){
        // start the intro
    }

    void update(StateMachine sm){
        if(introComplete){
            // change the state!
            sm.changeState(new GameState());
        } else {
            // play the intro
        }
    }

    void exit(){
        // nothing to do.. maybe free some stuff?
    }
}

Main:

// the main method that starts everything up..
main(){
    Game game = new Game();
    game.changeState(new IntroState());
    while(runGame){
        game.update();
    }
}

This architecture doesn't need switch or lengthy if statements. It's also really easy to change the flow of the states or add in new states. Imagine you wanted to start the MainMenuState after the IntroState? Change one line to: sm.changeState(new MainMenuState());. Then in the MenuState you could branch into whatever State you want, depending on which buttons have been pressed etc.

\$\endgroup\$
2
  • \$\begingroup\$ also, are the State and statemachine just simple base classes? \$\endgroup\$
    – Rivasa
    May 11, 2012 at 14:30
  • \$\begingroup\$ I'd implement the State as an Interface or Protocol, because it's implementation is probably different for every state and therefore a base-class isn't very useful. But since this doesn't exist in C++, it would probably be a pure virtual class, as explained in this stackoverflow question. The state-machine implementation won't change much, so implementing this as a base-class and then inherit from it seems fine. \$\endgroup\$
    – bummzack
    May 11, 2012 at 14:42
3
\$\begingroup\$

The most important thing you can do right now is actually just to make your own implementation without much regard to whether it's the "right" solution. Just write some code. You'll quickly find where the pain points are.

Having said that, one solution that works well for me is to have a Screen base class and a ScreenManager class. The ScreenManager class manages a list of Screen instances in a vector, calling Update and Draw on each one every game loop. One instance of the ScreenManager class is created at initialisation time in the main class (note I didn't say singleton. Generally you don't need singletons) and its Update and Draw methods are called from there at the right times. ScreenManager has methods AddScreen and RemoveScreen. Each inherited Screen class has access to the ScreenManager through a member of the base class (this value is set in ScreenManager.AddScreen) so each screen can remove itself and add new screens.

In this way, your game states are actually just screens, so you'll typically have a main menu screen, an options screen, and a game play screen etc, each with their own Update and Draw methods.

\$\endgroup\$
0
\$\begingroup\$

You could have a pure virtual class called game state. Then inherit from this class whenever you make a different game state, such as main menu or in game. You would have an enum that would be for your game states. You would also need one that was for not making a change. If you need to change the game state the current state will request the change. Then in your main game loop you would have a place to check if you need to change.

You can then utilize new and delete to facilitate the change in states. For instance, when you first start the game, you would have something like this pseudo code:

currentgamestate = NO_CHANGE;

gamestate = new IntroState;

while(shouldplay)
{
     gamestate->HandleEvents();
     gamestate->HandleLogic();
     gamestate->HandleRendering();

     if(currentgamestate != NO_CHANGE)
     {
           delete gamestate;
           switch(currentgamestate)
           {
                case INTRO: 
                { 
                      gamestate = new IntroState;
                      currentgamestate = NO_CHANGE;
                      break;
                }
                case MAIN_MENU:
                {
                      gamestate = new MainMenuState;
                      currentgamestate = NO_CHANGE;
                      break;
                }
           //and continue for each state and make this portion a separate function

This way you only have to deal with one switch statement for your states and your main game loop only deals with the one game state instance. You just have to insure that your constructors will create the bits they need to create and the deconstructors do their job right. Content loading and what not will happen automatically when you create the new state if you put it in the constructors. You can also have engine tools such as a renderer or a collision detection tool pass a reference or pointer of themselves into the different functions so you game states can utilize that code in their functions if they need to.

You could even have just gamestate-Run(); and run the three portions of events, logic, and rendering, inside the different gamestate classes. Up to you really.

\$\endgroup\$
-3
\$\begingroup\$

I'd suggest making your main game class a singleton and using public functions to change the state.

I'd implement the game loop within the singleton game class and have a switch() statement with cases for your various game states that call functions for whatever actions you want to do within each state.

\$\endgroup\$
8
  • \$\begingroup\$ Beat me to it :) This makes the most sense when you're dealing with over-arching game states (playing, paused, etc.) \$\endgroup\$
    – Mike Cluck
    May 11, 2012 at 0:39
  • \$\begingroup\$ thanks, seems like a good idea, I'll look into it. But is there another way rather than switch and case statments. \$\endgroup\$
    – Rivasa
    May 11, 2012 at 0:54
  • \$\begingroup\$ In programming, there's always another way. For this kind of behavior, I find a switch() to be most readable. You can get the same effect with stacked if else blocks. You could use an actual FSM. And, I'm sure the list could go on. \$\endgroup\$ May 11, 2012 at 3:05
  • 2
    \$\begingroup\$ -1. There's no excuse for singleton with public functions in a language where you have free functions, like C++. Just write free functions. \$\endgroup\$
    – user744
    May 11, 2012 at 8:55
  • \$\begingroup\$ @JoeWreschnig Are you saying that because I can write a globally accessible function in C++, I should never write a singleton class? I'd honestly like to hear your reasoning for that. \$\endgroup\$ May 11, 2012 at 15:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .