Using a stack for the gamestate

Started by
33 comments, last by Seriema 18 years, 8 months ago
I think Aldacron provided an even better solution to storing game states. By providing a TaskManager and Tasks that can run simultaniously you can both solve problems with the requirement of multiple tasks running at the same time and have an extensible system.

I personally consider it a better system(I'm not just here to defend my design :P), and I should implement it a bit to test some things around.

I consider a task/state management system one of the crucial parts of a game engine. Without a proper designed system for this, you quickly end up in shit. Which is the whole reason, I ditched my 2D asteroids clone, because I lacked a proper gamestate system.

Right now, it's time to implement a prototype system for TaskManagement and Tasks, and compare both systems. And then I can finally work on other problems.

Toolmaker

Advertisement
The point of a stack-based system is that any given state does not need to know what state came before it. For example, in one of my games I have a popup options menu, that is both accesible from the main menu and from within the game. When I want to let the user access the menu, I simply push its state onto the stack. When the user exits from the menu, it pops itself off the stack, returning to whatever state showed the menu in the first place. I would argue that this system is much easier to use and much more elegant than a FSM where you have to pass the previous state around all over the place.

In addition, you could impliment a system whereby the top state can call code from the state directly beneath it. In the case of my popup options menu, the menu still draws the state "beneath" it, so that behind the options menu you can see either the main menu or the game, depending on what showed the menu in the first place. In the case of a multiplayer game where you don't want the options menu to pause the game, it can call the update logic of the state beneath it in addition to the rendering code.
Please don't get me wrong - I'm not critizising anyones design... I'm trying to learn and improve my own :)


Quote:Original post by Holy Fuzz
The point of a stack-based system is that any given state does not need to know what state came before it.

Do a FSM need to?

Quote:For example, in one of my games I have a popup options menu, that is both accesible from the main menu and from within the game. When I want to let the user access the menu, I simply push its state onto the stack. When the user exits from the menu, it pops itself off the stack, returning to whatever state showed the menu in the first place.

In this case I would probably have done a state in a popup-stack that overrides the game-state. ie:
update: if popupstack is empty update game-state, if popup is nonempty - update popup.
rendering: render game-state, then render popups

Quote:I would argue that this system is much easier to use and much more elegant than a FSM where you have to pass the previous state around all over the place.

void GameState::update(float p_deltaTime) {  m_currentGame->update(p_deltaTime);  if( someCondition ) gameMashine->setState(InGameMenyState::instance());}
or
void GameState::update(float p_deltaTime) {  m_currentGame->update(p_deltaTime);  if( someCondition ) gameStack->pushState(InGameMenyState::instance());}

There isn't that much difference in code to me...

Quote:In addition, you could impliment a system whereby the top state can call code from the state directly beneath it.

I really can't argue with this, but is it needed? A pause state might want to update the view, but not the game logic(like max payne pause) and there goes IMHO the beauty of stack.

Quote:In the case of my popup options menu, the menu still draws the state "beneath" it, so that behind the options menu you can see either the main menu or the game, depending on what showed the menu in the first place. In the case of a multiplayer game where you don't want the options menu to pause the game, it can call the update logic of the state beneath it in addition to the rendering code.

So the options-state updates the one underneath? Doesn't this mean you can click around in the main-menu, or is there an option that comes w/ the option-menu? If so that is IMHO a bad design since it allows to add several option-menu's on the stack...
This is not really a suggestion for what to do, but a description of things I've done. Things that are a bit different from everyone else it seems, as usual :/

I don't use a stack, and I don't really have a seperate state machine for gamestates. In my current design, the actual game, or menus, or similar dialogs are just renderable classes. Renderables are stuffed into a tree, and where they exist in the rendering process determines which is 'active'. Usually this results in a stack-like behavior, but not always.

Opening a menu will simply occlude what's being displayed below. Deleting/closing the menu returns whatever is below to the forefront [or at least to the menu's position in rendering].

I've two different methods I've tried to use for dealing with... er, what's being discussed here as state transitions. The first is simple explicit side effects to creation. For example, creating a menu object might need to check if the game is running and pause it when opening. Similarly, the created menu would then include extra functors to re-start the game at close.

Kinda messy, kinda difficult to track, but good enough for really simple games where you can enumerate the various possible states in your head.

The other method is something I stole from my textinput class design. I made a class which groups things. It was meant to make sure that only one textinput was active at a time. It also works fairly well with major game states, as well as 'selected unit', and menu selections. It does a lot of the things the other method does, but with more code re-use.

It's not terribly flexible though, and the programmer doesn't have enough control [imo] of how some of the transitions occur.
I've been thinking on it for a while now, and both designs are actually quite good. Let's consider the stack idea:

A main stack is always updating it's top state. Allows menu's to be re-used along the way, and it doesn't require the top state to know what is below it.

Allowing each state have a set of sub-states(Such as Controls in C# *ALL* have a Controls member) allows things such as small Windows(Inventory in an RPG for instance) to be on top of the current state, but not block it. Without showing any code, calling Update() on the top state, would first have it update itself, and then call the Base.Update() function, which then updates all the sub-states. Same accounts for Render() function.

Thus, my MainGame state catches the keypress 'i', checks if the menu is already open and if not, creates a new menu and pushes it into the local stack. With some slight modifications you can set a specific stack to update only top or all states.

The pro of using a TaskManager however allows things to be more seperated out. I could write a NetworkTask which is responsible for sending/receiving player information over the network. Instead of stashing it into the MainGameState, I shove it directly into the TaskManager and give it a high priority.

The pro of using a TaskManager is that you can seperate out task, and give them a higher priority. However, the con is that for instance with menu's, it's much harder to see where each menu belongs at that moment. With a stack, you could print out the stack, and know exactly what's going on where.

I think both options are VERY useable, and whichever you use is probably very personal.

Toolmaker

First of all I would say that what everyone is describing is not a State Machine but is more of a Task Management system. The methods that everyone is using i.e. Render, Update, Push, Pop, Dispose. Is akin to Start, Stop, Pause, Run, Push Task, Pop Task onto a Task System or a Event Handler. A true state system does not have a State Manager but simple proceeds from one state to the next as each state knows what criteria is needed for moving another state and therefore decoupling that responsiblity and allowing for 'any' functionality within a state.
Quote:Original post by Holy Fuzz
The point of a stack-based system is that any given state does not need to know what state came before it. For example, in one of my games I have a popup options menu, that is both accesible from the main menu and from within the game. When I want to let the user access the menu, I simply push its state onto the stack. When the user exits from the menu, it pops itself off the stack, returning to whatever state showed the menu in the first place. I would argue that this system is much easier to use and much more elegant than a FSM where you have to pass the previous state around all over the place.

In addition, you could impliment a system whereby the top state can call code from the state directly beneath it. In the case of my popup options menu, the menu still draws the state "beneath" it, so that behind the options menu you can see either the main menu or the game, depending on what showed the menu in the first place. In the case of a multiplayer game where you don't want the options menu to pause the game, it can call the update logic of the state beneath it in addition to the rendering code.
To handle a popup menu state like that one would derived all the GUI states from a PopupState which would be derived from the main GameState or State class. This would allow for all the Derived object to have the funcitonality of the PopupState where the input say a right mouse click would then prompt run the code within the PopupStates input handler which would initialize the popupmenu and display it. So, that would be a simple solution to use with an actual state machine system.

Just a thought but how exactly are the states your describing and the state "stack" different from a Task Management system or System Kernel Architecture.

I'm not trying to belittle anyones design I think some of these are really quiet intriquing only I think that everyones use of gamestate is really more gametask or Itask rather than a state machine.
@ sirGustav:

Quote:Do a FSM need to [know what state came before it]?


A state in an FSM needs to know what state came before to do such tasks as returning to the previous state.

Quote:In this case I would probably have done a state in a popup-stack that overrides the game-state. ie:
update: if popupstack is empty update game-state, if popup is nonempty - update popup.
rendering: render game-state, then render popups


If I understand correctly, then you are proposing to implement a stack system for only those "base" states that really need a stack, which also turns it into a "bottom-up" system rather than a "top-down" system. Other than requiring a (probably insignificant) amount of work, I only see one problem with this method: By having a base state manually implement a stack system you are requiring every base state to know whether another state may or may not be pushed on top of it. In my opinion, this limits extensibility, though an argument could be made that it also keeps the state system from being abused with needless pushing of states ontop of other states.

Quote:void GameState::update(float p_deltaTime) {
m_currentGame->update(p_deltaTime);
if( someCondition ) gameMashine->setState(InGameMenyState::instance());
}

or

void GameState::update(float p_deltaTime) {
m_currentGame->update(p_deltaTime);
if( someCondition ) gameStack->pushState(InGameMenyState::instance());
}


Again, if a pure FSM was used, you would need to hardcode in or otherwise tell the new state which state it should return to after it is done executing. In the first chunk of code, InGameMenyState::instance() would need to be passed a handle to the previous state.

Quote:I really can't argue with this, but is it needed? A pause state might want to update the view, but not the game logic(like max payne pause) and there goes IMHO the beauty of stack.


Hm... maybe "stack" isn't the proper term... How about "runtime state inheritance"? What I'm describing is actually a lot like type inheritance and polymorphism, except with states instead of classes. For example, pushing state A onto a stack whose top state is state B really means that A is inheriting (and probably overriding some of) the functionality of B, which in turn may inherit and override the functionality of C, and so on... So yeah, it's like polymorphic states where inheritance happens a runtime.

Quote:So the options-state updates the one underneath? Doesn't this mean you can click around in the main-menu, or is there an option that comes w/ the option-menu? If so that is IMHO a bad design since it allows to add several option-menu's on the stack...


My system seperates the handling of user input from the handling of game logic. My "options menu" state calls the rendering and game-logic code of the state beneath it, but does NOT call the user-input code. So no, the user can't actually click on anything beneath since the state beneath can't respond to user input. (though in my system, a state could call the previous state's input code if it really wanted to)

@ Toolmaker:

Quote:Allowing each state have a set of sub-states(Such as Controls in C# *ALL* have a Controls member) allows things such as small Windows(Inventory in an RPG for instance) to be on top of the current state, but not block it. Without showing any code, calling Update() on the top state, would first have it update itself, and then call the Base.Update() function, which then updates all the sub-states. Same accounts for Render() function.


Yeah... there's no reason that an individual state in a stack-like state system couldn't also implement is own sub-states, such as gui controls and whatnot.

Quote:The pro of using a TaskManager however allows things to be more seperated out. I could write a NetworkTask which is responsible for sending/receiving player information over the network. Instead of stashing it into the MainGameState, I shove it directly into the TaskManager and give it a high priority.


This sounds alot like multithreading, though without all the hassle of synchronization. Each task is a thread, but instead of the OS interrupting threads and switching between them in seeming-random fashion, the task manager iterates through them in some sort of predictable, organized fashion. My own "task manager" is similar in that it executes a number of tasks in an organized manner, though these tasks are executed through hard-coded interfaces. I've found that whenever an additional task is needed that it almost always best fits as a sub-task within either one of the hard-coded tasks or within a state.

@ 5MinuteGaming:

Quote:A true state system does not have a State Manager but simple proceeds from one state to the next as each state knows what criteria is needed for moving another state and therefore decoupling that responsiblity and allowing for 'any' functionality within a state.


Right, and that's what's limiting about a pure FSM. Oftentimes you want a state to behave in an abstract manner based on some previous or related state.

Quote:To handle a popup menu state like that one would derived all the GUI states from a PopupState which would be derived from the main GameState or State class. This would allow for all the Derived object to have the funcitonality of the PopupState where the input say a right mouse click would then prompt run the code within the PopupStates input handler which would initialize the popupmenu and display it. So, that would be a simple solution to use with an actual state machine system.


Wait, I'm afraid I don't quite understand what you're saying. Could you explain in more detail?

Quote:Just a thought but how exactly are the states your describing and the state "stack" different from a Task Management system or System Kernel Architecture.


In a task manager or kernel architecture, a bunch of different tasks are all run in parallel, meaning that more than one state can be active at a time. In my stack-like system, *only* the top state is executed, and it may explicitly decide whether the state directly beneath it may also execute some portion of its code.

- Fuzz
First of all, let me start off by saying that I think the nature/genre of the game should be primarily considered when deciding to use a game stack, task manager, or whatever your design is. Some games would be more suited for a game stack than others, so I don't think there is any "one solution fits all" design here.


Having said that, my game is a (non-MMO) 2D RPG and we use a classic game stack engine. There is a base class that all the different mode classes inherit from, and the top of the stack is the active game state (and there can only ever be *one* active state). The (GPL) code for this can be seen in the following two files (look at the GameMode and GameModeManager classes):

engine.h
engine.cpp


It's been working great so far and its a really simple, convenient, and intuitive interface.

Quote:
The first example that comes to mind is when dealing with saved game. Say the user loads a previously saved game. At the moment the user enters the game the stack would look something like this:

^ PlayGameState
| LoadMenu
| MainMenu

Lets say the user now presses escape to go back to the load menu, what do you do? Do you pop the PlayGameState off the stack? That would make it impossible to resume the current game. So, you add another LoadMenu state onto the stack. The user then picks a different saved game, and after a couple of iterations of this you end up with something like:

^ PlayGameState
| LoadMenu
| PlayGameState
| LoadMenu
| PlayGameState
| LoadMenu
| MainMenu


You don't have to do it this way (ie, you don't need a state for every little piece of code in the game). We define our states as different "game modes" (modes of operation). There's map mode for exploration, boot mode for the boot menu, battle mode, menu mode, etc. It doesn't make since to write a seperate state for every different active GUI menu: it's just too many states. Instead what you can do is implement your Update function for a game state (like menu mode) to take different actions based on the value of different class members. So if I keep a pointer to the currently selected menu in Menu Mode, I call a different sub-Update function that processes code specific to that menu.




The only thing we've had trouble with so far is when a game mode wants to destroy itself. For example, when you select a new game in Boot mode you want to destroy Boot mode (and hence free up the resources it consumes) and push a Map mode. But having a class object destroy itself is a very risky/daring thing to do (its been working so far). Here's an e-mail excerpt I sent one of my new developers on the matter and my idea for circumventing the problem.

Quote:

I was concerned about this for a long time too. I know that it's bad coding practice, but it worked at the time. What I wanted to happen when switching modes was the following:

1) Construct the new mode
2) Push it to the top of the game stack
3) Wait for the current mode's subroutine to exit
4) Pop the old mode


The problem with this was that I couldn't think of a good way to do this. But now I think I do, so tell me how this sounds. Currently, there is this line in the main game loop:

ModeManager->GetTop()->Update(SettingsManager->UpdateTime());

Which calls the Update function for the game mode on the top of the stack. What if I modify this call to check a change in game state. So for example, first lets assume that there's a temporary "staging" pointer in the GameModeManager class that is NULL except when there's a new game mode to push. Then I can write the following function:


void GameModeManager::UpdateGameState(Uint32 update_time) {
if (next_state != NULL) {
Pop(); // Remove the old state
Push(next_state); // Put the new state on the stack
next_state = NULL;
}
game_stack.top()->Update(update_time); // Update the game state on the top of the stack
}


But there are problems with this too. 1) We check for a state change every iteration through the main loop and since 99.9999% of the time there is no change, it seems wasteful. 2) Just because we push a new state doesn't mean we want to pop the old state. To solve #2, I guess I could do something like write the Pop function to keep a vector of states that are expired and periodically the GameModeManager will check it and remove any old game modes (updating the game stack accordingly in the process). But I still have a feeling that there should be a better way to do this.



A modern processor's branch predictor should be able to guess the 99.99999% that that if statement is false, so I don't think there would be a big performance hit or anything. But I'm wondering if anyone else knows of a better solution to the problem?

Hero of Allacrost - A free, open-source 2D RPG in development.
Latest release June, 2015 - GameDev annoucement

Quote:Original post by Holy Fuzz

Quote:To handle a popup menu state like that one would derived all the GUI states from a PopupState which would be derived from the main GameState or State class. This would allow for all the Derived object to have the funcitonality of the PopupState where the input say a right mouse click would then prompt run the code within the PopupStates input handler which would initialize the popupmenu and display it. So, that would be a simple solution to use with an actual state machine system.


Wait, I'm afraid I don't quite understand what you're saying. Could you explain in more detail?
Yeah sorry about the cryptic post I don't think I reread that one and if I did thats pretty bad. What I failed to describe before was a Decorator Pattern where if you want a Popupmenu to be displayed you don't neccessarily have to have a separate state for it. Now that I think about it the PopupMenu would be a Decorator to a Window Component or a GameScreen component. Or however you have your Widget system setup your GameState for the Main Menu for instance would inherit from GameState as well as a Component or Window Component which is decorated with a PopupMenu or has that added as a separate component. But I don't think that making a PopupMenu a separate State would be the best implementation option.

Although a stack-like state system is certainly useful for more than just a popup window, here's my reasoning for using it in this one particular case: The popup window is entirely self-contained, meaning that it is not associated with any other gui control, and in addition it blocks EVERYTHING ELSE on the screen from responding to user input (not just what is visibly obscured by the window). My gui system itself supports popup windows very nicely, but not the ability to easily prevent controls outside the window's region from responding to user input. (the popup window actually dims everything else on the screen by drawing a screen-sized translucent grey rectangle behind the window). The popup window is, in effect, its very own self-encapsulated state, even though at appears translucently ontop of another state.

This topic is closed to new replies.

Advertisement