Friday, June 6, 2008

High-Level Game State Management

By 'state management' I mean high-level game state. For example, when a game starts up, it might display a sequence of loading screens, including company logos, a game title screen, and intro cinematics. Then the main menu; then the game proper. Within the game itself, the game might have different screens that it displays and moves among, from character info to world view to options, etc.

I've seen some weird state management systems in my time. Almost all of the "systems" I've seen other people use aren't really systems; they were just hand-coded transitions, often involving a lot of global variables, a bunch of free functions, large switch statements, etc. Or maybe just a bunch of nested function calls, meaning that, when you quit the game, it backs out all the way through the main menu, past the title screen, the company logo, and the intro loading screen...

A programmer that's used to doing something one way, and satisfied that the approach is efficient, is unlikely to do something different. So here's something new.

I use a class-based state management system, cuz I'm a C++/C# programmer. State is managed through a 2-level inheritance hierarchy -- no complex class relationships, just one base class and one subclass for each different state. The main loop calls a static singleton to do whatever needs to be done in the current state; that singleton calls the current state subclass (of course, through a virtual function) to do its thing.

Each call through the system renders one frame. Usually; the current state can spend a bunch of time if it wants, which really only happens when loading new content. Even then, I sometimes leave the loading work to a different thread and continue rendering frames. This is one instance where the specifics aren't important; how you handle loading is independent of the idea of using a State parent class and its children to switch between different high-level states.

When a State has figured out that the game needs to move to a different state, it tells the state manager. I stick an enum for the different states in a header file. (Note that this means a bunch of recompilation "every time" I add a new State subclass. The thing is, that doesn't happen that often. There'll be maybe eight or ten states in the entire game, and over the lifetime of the project, ten extra recompiles is no big deal.) Since each run through the state manager generates one frame, the state manager can do cleanup and transition to the new state cleanly on a frame boundary.

I typically use an event model for controller/keyboard/mouse input. The events are grabbed at a high level and fed through the state manager. Abstracting input is a handy thing, and this structure solves that problem.

I've sometimes built complex stuff like preloading and caching into the state system. Separating out each game screen makes a bunch of stuff easier. Since the state objects aren't unloaded when state changes, a "level" can keep itself in memory, cached provided there's enough memory for it, meaning no lengthy load when the user (say) backs out to the main menu then reloads from a save point.

The State parent class has, over time, morphed into a Screen class. The different 'states' that this system models are often the major screens in a game: the loading screen, the company logo, the game title, the main menu, submenus, and the game proper. If save/load is handled through a fullscreen interface, that's a chance to move that code into its own class.

It doesn't matter to me if you use this structure, of course. I hope it's given you some ideas for structuring the high-level bits of your game differently.

Note: I've made a followup post on state management in game menus.

1 comment:

Anonymous said...

I'm gathering ideas for a state manager of my own. My game is in flash using as3, so a lot of this article was over my head. But it still gave me some useful ideas. Thanks!