Even with my extensive background in programming and web development, even with some nice APIs at my disposal, and even with my earlier experience doing QBasic game development, I still didn’t really know the first thing about how to structure a large-scale game project. Luckily I could admit this to myself and decided to research some of the approaches other people have taken. The first thing I came upon was the idea of game states.
Game States are basically the different screens you would see in a game. You start out with the introduction screen, then the title/menu screen, then probably the actual gameplay screen. From there, you could go to the pause screen, the ending screen, the gameover screen, or back to the title/menu screen. All of these translate into the different states the game can be in, and each one functions differently than the other.
Now, without thinking about it, you could easily just start coding your game without really separating out the game states. All you have to do is fill your main game loop with lots of “if” statements or a big “switch” block, trying desperately to keep everything organized. However, as you might have guessed, this will quickly get out of hand and before you know it, enemies will keep moving while the game is paused, the menu screen will show up but won’t accept input, or any other number of oddities that will just get increasingly harder to debug as the codebase grows. If you want to have any chance of being able to navigate through your code, you’ll need to find a better way to structure things.
The solution is to create an abstract GameState class with virtual methods like Update(), HandleInput(), and Draw(). You can then derive “subclasses” from the GameState class such as IntroState(), GamePlayState(), PauseState(), etc., and all you have to do for each state is fill out those few virtual methods.
You’ll also need a class that manages your game states—like GameStateManager. The GameStateManager typically holds a stack of GameStates and has its own methods for Update(), HandleInput(), and Draw(). The only thing these methods do, though, is call Update(), HandleInput(), and Draw() on the topmost GameState. It also needs methods for adding and removing GameStates from the stack.
So, to start out with you’ll just add the IntroState to the top of the GameStateManager stack. After the intro is over, the IntroState tells the GameStateManager to pop itself off the stack and add the GamePlayState. If the game is paused, the GamePlayState adds the PauseState to the top of the stack, so HandleInput(), Draw(), and Update() get called on the PauseState instead of the GamePlayState (because PauseState is at the top of the stack now). When the game is unpaused, the PauseState tells the GameStateManager to pop itself off the stack, which leaves the GamePlayState to resume where it left off.
This is a simple and effective design that will keep your different game states organized in a logical and cohesive manner. However, I’ve fleshed out the design a lot more to allow for more functionality. Things like state transitions, passing input, allowing lower states to draw “underneath” higher ones, and more will be supported in my engine very easily. As of now, it’s about 95% done.
“Only 95% done!?", you say? Well, the next thing I came across was the game object concept. The idea is that every object in your game (the player’s character, trees, rocks, sounds, lights, cameras, etc.) are all represented by an abstract GameObject class. Each GameState contains a list of GameObjects, and each GameObject has methods that are called by the GameState’s Update(), HandleInput() and Draw() methods. So until I figure out how exactly I’m going to implement GameObjects, the GameState stuff needs to be put on hold. It’s all done except for the areas that deal with GameObjects, so that’s why I say it’s 95% done.
I’ll share some code once things are more finalized, but for now if you’re interested in game states and want to know more, check out these articles that helped me get going:
Cornflower Blue: Basic Game Structure
Managing Game States with OGRE
Managing Game States in C++
Tune in next time when I’ll tie up these where-I’m-at-so-far posts with everything I’ve learned about GameObjects!
Recent Comments
No comment yet...