Using a stack for the gamestate

Started by
33 comments, last by Seriema 18 years, 8 months ago
[This is more meant as a design discussion, and not really a question. I want some feedback on my design] I was thinking a little about the design of my next game(A simple Asteroids clone, in 3D) about how the manage the gamestates. Since in a game like tetris you can get away with a flag, in a bigger game, using flags will make things messy, very messy. So I remember a convo I once overheard about using a stack for this. All the gamestates are derived from an abstract base class called GameState. GameState has a few functions like Update(), Render() and a few callbacks. The main GameStateStack class, controls these states, and calls Update()/Render() on the top class in the stack, and allows the top object to pop itself off the stack, or push new states onto the stack(Such as when a user selects "New Game", a PlayGameState object is created and shoved onto the stack). This creates a very robust system, that's reusable over various games, and makes it easy to encapsulate various functionality. I'm using C#, so here is some code to illustrate the system: GameStack

	public class GameStack
	{
		System.Collections.Stack stack = new Stack();

		public GameStack(GameState initialState)
		{
			stack.Push(initialState);
		}

		public void Update(float timeDelta)
		{
			if (stack.Count > 0)
			{
				// Get our top state
				GameState state = (GameState) stack.Peek();

				// And update it
				state.Update(timeDelta);
			}
		}

		public void Render()
		{
			if (stack.Count > 0)
			{
				// Get our top state
				GameState state = (GameState) stack.Peek();

				// And render it
				state.Update(timeDelta);
			}
		}

		public void Push(GameState newState)
		{
			// Hook the dispose event
			newState.Disposing += new StateDisposingEvent(OnStateDisposing);

			// Push it onto the stack
			stack.Push(newState);
		}

		public void Pop()
		{
			// Pop the the object, and store it
			GameState state = (GameState)stack.Pop();

			// Make sure to release all resources
			state.Dispose();
		}

		private void OnStateDisposing(object sender)
		{
			// Is the object disposing while still on top? If so, remove it
			if (stack.Peek() == sender)
			{
				stack.Pop();
			}
		}
	}

The GameState

	public abstract class GameState : IDisposable
	{
		protected GameStack stack = null; // We need to know in which stack we are
		protected Device device;
		
		public event StateDisposingEvent Disposing; // In case we're disposing while on top of the stack

		public GameState(GameStack stack, Device device)
		{
			this.stack = stack;
			this.device = device;
		}

		public abstract void Update(float timeDelta);
		public abstract void Render();

		#region IDisposable Members

		// Child classes need to be able to trigger the disposing
		protected void TriggerDisposing()
		{
			if (Disposing != null)
				Disposing(this);
		}

		public void Dispose()
		{
			TriggerDisposing();
		}

		#endregion
        }

Now, would you guys consider this a robust system, and/or what could be improved to the system? I assumed the top state is always the state that will send the dispose event. I could change the system a bit so that if a lower state wants to be popped, all other states ABOVE it, will be popped aswell(Such as a state running multi-threaded and all the sudden decised to dispose itself). Toolmaker

Advertisement
I personally use a very similar system, however it's not stack-based and is slightly more complex in certain aspects.

I have an abstract base class for game states, from which specific states are derived (just like you do). However, I store these in a map (I use C++ BTW) which relates states to strings (which are the state's IDs or names).

Instead of updating the most recently pushed state, I store the string ID of the current state and execute it's corresponding value in the map. Your stack-based method is probably more efficient here since mine has to perform a look-up into the map.

Other than this, there aren't any other non-superficial differences between my system and yours. Mine actually is tied into a messaging system also, but that's irrelevant to this discussion.

This system has always worked fine for me. It's definately more clean than a big huge switch statement. I'm sure there's other methods which can be employed to make this even more elegant, but for a non-massive game project, this method should be perfectly sufficient.
Hello,

I guess the following link would help you about it.

http://tonyandpaige.com/tutorials/game1.html

Regards,
Oscar
The main drawback here is that it requires game states to be 'stackable'. This will be fine in a simple game (eg. your Asteroids clone), but when things start to get more complicated this may not be desirable.

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
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
I use a state machine for moving between states, as well as a stack for temporary states. So, there's a current state, and some possible overlays. You can almost get away with just one layer of overlay ("menu", say), but for some game designs, such as an RPG with close-up fight scenes, you need a two-deep stack: main game -> fight scene -> menu.

My state class has five functions: enter, exit, suspend (when something pushes on top), resume (when popped back to be topmost) and step.

The "state manager" is built in as static functions in the abstract base class, because it's so simple. When you setState() to a new state (rather than pushState()), all states in the current stack are torn town and exited before the new state is entered. Thus, if you're in main game -> combat scene -> menu, and choose "load game", that will setState() on a "main game" state, which will tear down the combat scene and menu, and you're left with just a main game state at the bottom of the stack.
enum Bool { True, False, FileNotFound };
I am using a "stack", but it is basically a linked list. All nodes are derived from my Screen class, and the base screen holds a child screen. If the screen has no child, it is the current state. Otherwise, all of the calls to the screen get passed through. The benifit of this is that any of the derived screens can override this behaviour, either to perform its own computations based on events, or provide a more complicated state structure.

In the load menu scenario they screens could simply pop down a few levels, since they already have to have the ability to return values to lower levels. It shouldn't be any different then a child form in normal windows programming.
Turring Machines are better than C++ any day ^_~
Quote:Original post by joanusdmentia
The main drawback here is that it requires game states to be 'stackable'. This will be fine in a simple game (eg. your Asteroids clone), but when things start to get more complicated this may not be desirable.

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


I don't completely agree with you there, because that's a matter of bad stack management. Perhaps my class needs a Count property where as loading a game would look like:

^ LoadMenu
| MainMenu

In LoadMenu, you could just do:
while (stack.Size > 1) // More than our initial gamestate    stack.Pop();stack.Push(playState);


This will place the gamestate on top of just the main menu, which is exactly the kind of behaviour you want.

Toolmaker

Maybe the Load state could pop itself from the stack?
That's exactly the idea

i have created a very similar design. except there is no stack. each game state has the standard render update etc methods. but there is also a GameState* changeState() method. which, when the game state is ready to change, this method will return the next game state to be used (whatever it may be, the manager doesnt care). if this method returns a non-null value, it calls the clean up method for the current state, deletes it, and sets the current state to the one that was returned. if you want the states to pause / run again without recreating, you can add a temp game state map and add the state to that before deleting.
---------Coming soon! Microcosm II.

This topic is closed to new replies.

Advertisement