a game state management system can sometimes take modules that are at different levels and place them at the same level, which can lead to complications.
init_program, run_program, and shutdown_program are all top level modules.
game startup menus are a module called by run_program. they in turn call run_game. so the startup menus or "shell" is the second level of modules.
init_game, run_game , end_game is the next level of modules.
the in_game menu is a module called by run_game. its at the next level down.
by making the in_game menu or game startup menu just another state along with init_game, run_game, end_game, you "force" them to be at the same level, which may require extra communication which is normally handled implicitly by the call hierarchy.
note that its very common to have a game loop that looks like this:
while (! gameover)
process_input
if (gameover) return
update_all
if (gameover) return
render all
the sad fact is that there are a number of places you must break out of a game loop for a number of reasons. such as the player pressing the hotkey for the ingame menu, or the game ending due to any of a variety of reasons (mission goals achieved, mission goals failed, all bad guys dead, player dead, etc).
so there will be a number of places where something will occur and you'll want to break out of the game loop and call a sub-module such as an ingame menu, or return control to the calling module (the shell / wrapper / game startup menus).
about all you can do is set a flag when such things occur, and either finish the current module's processing (such as updating all) or return immediately. then after each call to a module where the flag can be set, you check to see if you should break out of the game loop.
one thing i note in this particular case is that your loop is of the form:
while ! quitgame
update
render
and you get input inside update...
update_each:
if (is_player) get_human_input else get_AI_input
or some such thing.
with a loop of the form:
while (! quitgame)
render_alll
process_input
update_all
you only need to check for gameover after getinput:
while (! quitgame)
renderalll
process_input
if (! gameover) update_all
you can also change the order to eliminate the check completely:
while (! quitgame)
update_all
render_all
process_input
but you would still need a check for gameover due to updates (such as player getting killed):
while (! quitgame)
{
update_all
if (! gameover)
{
render_all
process_input
}
}
i usually go with:
while (! gameover)
{
render_all
process_input
if (! gameover) update_all
}
note that by having an explicit process_input module in your loop, the in-game menu simply becomes a sub module called by process_input, instead of a state to be dealt with.
now, here's an example of when its a good idea to use "game states":
the game has 4 different types of environments / types of locations / points of view to draw: outside, in_cave, in_cavern, and up_a_tree.
each uses its own unique method of rendering the required scene, essentially 4 separate types of graphics engines.
as the player moves about the world, their "location" can change from outside to in_cave, etc. location is the "state" variable, with the 4 pre-defined state values of: outside, incave, incavern, and upatree.
when render_all is called, it checks the current state (the location) and calls the appropriate rendering engine.
each of the 4 rendering engines is a module at the same level, just below the render_all module. the render_all module NEEDS to be able to operate in one of 4 states. so its a good candidate for a "game state" approach. the key is that all the states are at the same level, so they are truly ONE thing (the renderer) operating in different states, as opposed to different things at different levels (the game loop and wrapper or in-game menus) being force to operate at the same level via state transitions.
what you're doing is replacing the flow control implicit in call hierarchy with explicit state transition flow control. but your problem is that in a game, you're not really dealing with a single state machine with multiple states like init, shutdown, startup_menu, ingame_menu, and rungame.
you're dealing with a hierarchy of state machines.
your highest level state machine has the states init_program, run_program, end program.
your next highest level state machine is run_program, with the states init_game, run_game and end_game.
your next highest level state machine is run_game with states render_all, process_input, and update_all.
your next highest level state machine is the one controlling the in-game menu, which is called from the process_input state as needed. think of the entire in-game menu as a "sub-state" of process_input that the game switches to as needed (IE when the player pulls up the in-game menus).
but as you can see, just from the previous sentence, trying to think of call hierarchies in terms of states at the same level can be confusing. that's because call hierarchies are tree type structures of modules, and state machines are more like peer to peer networks of modules.
peer to peer networks don't seem to me to lends themselves especially well to representing tree structures.
note that in a peerless network all the nodes (modules) are at the same "level". no client server hierarchy.
i think this may be a good test for when to use and not to use game states. are the modules that execute the states all inherently at the same level? if so, they may be a good candidate, if not, they may not be such a good idea.