Transitioning game states when using a stack of states

Started by
9 comments, last by L. Spiro 7 years, 7 months ago

I am trying to implement a game state system in my engine. I have read around a bit and think I am able to tackle a stack of gamestates. In order to prototype I am aiming to have first a splash screen, then a main menu, and then the "playing" state.

I am wondering the best way to transition from one state to another?

Right now, I have a GameState class,


class GameState
{
public:
    GameState();
    ~GameState();
    virtual void update(const float deltaTime) = 0;
};

and my Game class (of which my actual game inherits from), with a vector of states


std::vector<std::shared_ptr<GameState>> m_states;

So right now, I can add the first state (the SplashScreenState, Inherited from GameState) using


game.pushState(std::make_shared<SplashScreenState>());

and in my game update loop I call


	for (std::vector<std::shared_ptr<GameState>>::reverse_iterator i = m_states.rbegin(); i != m_states.rend(); ++i)
	{
		(*i)->update(frameTime);
	}

to update each State. So right now my SplashScreenState is getting updated, and a timer transitions it. Once the timer runs out I want the MainMenuState to activate.

The question is, given my current design, how do I best go about this?

Should I have something inside SplashScreenState::update() that lets me push on the next state directly?

Should My GameState class handle all transitions internally?

Where do I go about actually explicitly stating which state I want to go from where and to (Splash Screen to Main Menu, Main Menu to Playing, Playing to Paused...).

Thanks for any insight.

Advertisement

The simplest way is to have a StateMachine object that holds your vector of states, pass that in to each GameState when it is created, and then each GameState can tell the StateMachine which new state to replace it with when it's done. StateMachine would take on your pushState function, and a replaceState, and whatever other state management functionality you want.

(You could put all that functionality inside the Game, but it's best not to have one object trying to manage too many different responsibilities.)

Hi Kylotan, thanks for your reply. Simple is good for me! I like the idea of each state being able to push and replace states directly...

I am a bit confused when you say pass that in to each GameState when it is created,

So my StateMachine class currently looks as:


class StateMachine
{
private:

public:
	std::vector<std::shared_ptr<GameState>> m_states;

	void pushState(const std::shared_ptr<GameState> &state);
};

Do I have this StateMachine in my Game class?

Thanks for your help!

A stack of states only makes sense when you have what you consider the “current state” and then have the ability to push another sub-state on top of it to temporarily block that state, such as to tell the player his or her WiiMote batteries are dead (the current state is temporarily interrupted, a screen appears indicating that batteries need to be replaced, and it goes away and your game is resumed normally once batteries are replaced).

In almost all situations you only need a current state.
View these posts on how to set it up.
General Game/Engine Structure
Passing Data Between Game States


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Do I have this StateMachine in my Game class?

Sure. If the Game has the concept of being in different states, it makes sense for it to own the StateMachine.

Not sure how to answer the 'pass that in to each GameState' query because it didn't seem like a complete sentence.

And as L. Spiro noted above, it's rare you actually need a stack of states. Alongside that pushState function you will also want a replaceState function which is basically a pop followed by a push, and that's the method you'll use more frequently.

A stack of states only makes sense when you have what you consider the “current state” and then have the ability to push another sub-state on top of it to temporarily block that state

Hi L. Spiro. Thanks, this makes sense. My reasoning for the stack of states was to allow other 'states' or 'screens' ontop of each other during the game. An example of this is diablo 2, when you select what skills you want as right click, you bring up the 'skill' bar, the game keeps running behind.

300px-Skills-right-click.jpg

I want this sort of functionality. Thanks, I will check out your article, I have gone down the track of my implementation for now so want to try and finish that.

Do I have this StateMachine in my Game class?

Sure. If the Game has the concept of being in different states, it makes sense for it to own the StateMachine.

Not sure how to answer the 'pass that in to each GameState' query because it didn't seem like a complete sentence.

And as L. Spiro noted above, it's rare you actually need a stack of states. Alongside that pushState function you will also want a replaceState function which is basically a pop followed by a push, and that's the method you'll use more frequently.

Agreed I will be mainly with one state, but it is the in game 'upgrades' or 'skill select' screens that I have this in mind for...

Regarding my question, in your original post you say "The simplest way is to have a StateMachine object that holds your vector of states, pass that in to each GameState when it is created"

I pass the state machine object into the GameState?

Right now I have got


void GameImplementation::init(HWND hw)
{
	auto splashScreenState = std::make_shared<SplashScreenState>();
	m_stateMachine.pushState(splashScreenState);
}

I don't quite understand what you mean. Sorry I am quite a beginner at this.

Thanks

Usually you don't want to handle different UI aspects as different game states. Instead, they are UI elements that you add or remove to the game as necessary. Use states for when there are different modes you can be in, and you are only ever in one mode at any one time. Common game states might be Intro Menu, Playing Game, Pause Menu, etc. Now, I appreciate there's a fuzzy line here because sometimes you want to display a new window and it is an entirely new mode of operation (eg. level up screens, pause menus) and sometimes it is not a new mode and just something else you can click on (eg. skill bar). You have to decide what is right for you.

As for the rest, here's what I mean:


// In your Init function (and similar code exists elsewhere)
auto splashScreenState = std::make_shared<SplashScreenState>(m_stateMachine); // pass the state machine into the SplashScreenState
m_stateMachine.pushState(splashScreenState);

// And in your SplashScreenState definition...
class SplashScreenState
{
public:
    SplashScreenState(StateMachine& owner) {
        // Remember which state machine we're a part of
        m_owner = owner;
    }
private:
    StateMachine& m_owner;
// etc...
};

// And when the SplashScreen needs to move to the next stage...
if (key_pressed || intro_finished)
{
    // Destroy this state and start the main menu state
    m_owner.replaceState(std::make_shared<MainMenuState>(m_owner));
}


Does that help?

A stack of states only makes sense when you have what you consider the “current state” and then have the ability to push another sub-state on top of it to temporarily block that state

Hi L. Spiro. Thanks, this makes sense. My reasoning for the stack of states was to allow other 'states' or 'screens' ontop of each other during the game. An example of this is diablo 2, when you select what skills you want as right click, you bring up the 'skill' bar, the game keeps running behind.

300px-Skills-right-click.jpg

I want this sort of functionality. Thanks, I will check out your article, I have gone down the track of my implementation for now so want to try and finish that.

You might be over complicating things. That wouldn't be a product of overall states. That'd be two seperate systems in the game. They don't block each other from running, but one stops user interaction by priority.

Hi L. Spiro. Thanks, this makes sense. My reasoning for the stack of states was to allow other 'states' or 'screens' ontop of each other during the game. An example of this is diablo 2, when you select what skills you want as right click, you bring up the 'skill' bar, the game keeps running behind.
So perhaps you should have a stack of Screens?

State has a specific meaning, and I am not sure your intended meaning is represented well by what you want. Screen seems closer to your idea.

As for the rest, here's what I mean:


Does that help?

Yes! Thanks! That's amazing. I couldn't quite figure out how to apply the demos of this sort of stuff I have read to my game. Much appreciated!

You might be over complicating things....

State has a specific meaning, ...

Yeah.. I see what you mean guys, Thanks. I think I need to separate the idea of GameState and "Screen or UI State". Since In my game I will be wanting these 'overlays. As Kylotan says though It is a fine line and I am having trouble deciding what constitutes as a "GameState" and "ScreenState".

This topic is closed to new replies.

Advertisement