And why can't you run more than one gamestate at once?
don't quite follow you there.... you mean an overall state which is a combo of two or more sub states?
If you have children states, then both the parent and the child are active at the same time. It's no longer StateA and StateB and StateC, but you have states of your game where StateA is running at the same time StateA1 and StateA2, but not StateA3 are running.
Example: In some games, when you stand still, your health and mana slide into view on the HUD.
So, you're walking around in the game world [State: Exploring]
Then conditionally, based on the data of the 'Exploring' state about whether the player is moving or not, it activates or deactivates one of its children: HealthHUD.
What if the game and the options screen both listen for the same keyboard input? If they are concurrent states, you would have behavior such as moving the cursor on the options screen and having the player character move in the background. You would have to make the game state be aware that there's an options screen state active, and so it should 'pause' or 'ignore' its input listener.
What happens when you want to overlay your options menu on the game, but keep the game itself visible and running in the background?
Here's how I do it:
whatever_parent.Push(InWorld) //Game world is displayed in this state (and animated).
InWorld.Push(Exploring) //Push to InWorld's private stack of children. Only the topmost child is active.
//Player can walk around, as well as the walking-around GUI gamestates can be children of this,
//like health bars and world mini-maps. Since this is drawn after 'InWorld', the world itself is drawn under whatever game elements.
//Player can navigate the menu. Since this is drawn as a child of 'InWorld', the world itself is drawn under the menu.
I use a stack together with parent-children. Each state can have it's own stack of children. Only the topmost child is active.
Each state can also have a collection of non-stacked children that are always active as long as the state itself is active. I'm not yet sure whether this is a good idea or not. I call these 'free children', as opposed to the 'stack children'.
The example at the beginning of this post, with the player's health and mana sliding into view, would be an example where I'd consider using a free-floating child rather than a stack child. Because the health and mana GUI widget doesn't have to have exclusive focus, and so doesn't have to take control away from, say, a mini-map widget.
With events, you want pass to the children first, so the most descended state gets priority to respond over ancestors.
With drawing, you draw first, so the most descended state gets to draw over the ancestors. ([Edit:] If using a 2D API with no depth buffer. With 3D, you want to draw in reverse order)
Actually, I have [DrawBefore, DrawAfter, UpdateBefore, UpdateAfter, ReactBefore, ReactAfter] overridable functions because sometimes you want finer control over it, if you actually do want a parent state to draw over the descendant state.
Here's my code:
void GameState::DoDrawing(sf::RenderTarget &renderTarget)
//Activate, only if not yet activated already.
//This makes sure that GameState::activated() gets called (but only once, until deactivated() gets called).
//Draw before the children.
this->DrawBefore(renderTarget); //Virtual func, for derived classes
//Draw all the free children, which are always active as long as this GameState is active.
for(auto &object : this->pImpl->freeChildren)
//Draw the topmost stack child.
if(this->pImpl->childStack.empty() == false)
//Draw after the children.
this->DrawAfter(renderTarget); //Virtual func, for derived classes
DoUpdating() and DoReacting() are pretty much identical. I also have DoThinking(), because I'm seeing if separating my events (DoReacting) from my time-based updating (DoUpdating) and from my logic decisions (DoThinking()) works out well on my current project. As with free non-stack children, the votes still out on that.
This layout seems to be working for me so far - but since I haven't actually released my game yet, and it's still in semi-early development, you'll definitely want more experienced opinions before basing your solutions off of my experimentations.
Edited by Servant of the Lord, 28 August 2013 - 11:55 PM.