[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