As promised, here is my implementation of a game state manager. My last project was done in OGRE3D and as such, I was introduced to game state management through this wiki:
Managing Game States With OGRE
Which is inspired by:
-and-
State Pattern in C++ Applications
Which together inspired:
An Architecture For Game State Management Based On State Hierarchies
My code derives heavily from (see: almost exact replica of) the first 3 sources while the 4th is slightly different.
Without further ado:
GameEngine.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <vector> #include "SDL.h" class GameState; class GameEngine { public: void Init(int width, int height, int bpp, Uint32 flags,FILE *pFile); //Initialize SDL void Cleanup(); //Cleanup SDL //The following 3 functions loop through the respective //functions from the states contained in the states vector void HandleEvents(); void Update(); void Draw(); void ChangeState(GameState* state); //The following 2 functions are used seperately from ChangeState() //when one wishes to overlap states (ex. pop up menus) void PushState(GameState* state); void PopState(); bool Running() { return m_running; } void Quit() { m_running = false; } private: std::vector states; bool m_running; SDL_Surface* m_mainSurface; }; |
GameEngine.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | #include "GameEngine.h" #include "MainMenuState.h" #include "SDL.h" void GameEngine::Init(int width, int height, int bpp, Uint32 flags,FILE *pFile){ //SDL_GetError() seems like a logical thing to add to the failed if calls below (in the fprintf). //Maybe implement with a DEBUG flag if (SDL_Init(SDL_INIT_VIDEO)==-1) { fprintf(pFile,"Could not initialize SDL!\n"); exit(1); } else { fprintf(pFile,"SDL initialized properly!\n"); atexit(SDL_Quit); } m_mainSurface = SDL_SetVideoMode(width,height,bpp,flags); if(!m_mainSurface) { fprintf(pFile,"Could not create main surface!\n"); exit(1); } } //as of now, SDL_Quit cleans everything that I need it to and that's been set with atexit(). //But left this here anyway so it can be used for more than SDL. void GameEngine::Cleanup(){} void GameEngine::HandleEvents(){ states.back()->;HandleEvents(this); } void GameEngine::Update(){ states.back()->;Update(this); } void GameEngine::Draw(){ states.back()->;Draw(this); } void GameEngine::ChangeState(GameState* state){ if(!states.empty()){ //Cleanup is not in destro because the object is never actually destroyed (singleton), //but all of its resources are unloaded with Cleanup so its memory becomes negligible states.back()->;Cleanup(); states.pop_back(); } states.push_back(state); states.back()->;Init(); } void GameEngine::PushState(GameState* state){ if(!states.empty()) //no reason to use if states is empty, but accounts for it anyway states.back()->;Pause(); states.push_back(state); states.back()->;Init(); } //pause and push back void GameEngine::PopState(){ if(!states.empty()){ states.back()->;Cleanup(); states.pop_back(); states.back()->;Resume(); } } //remove back and unpause |
GameState.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | class GameEngine; class GameState { public: virtual void Init() = 0; virtual void Cleanup() = 0; virtual void Pause() = 0; virtual void Resume() = 0; virtual void HandleEvents(GameEngine* game) = 0; virtual void Update(GameEngine* game) = 0; virtual void Draw(GameEngine* game) = 0; void ChangeState(GameEngine* game,GameState* state) { game->ChangeState(state); } protected: GameState() { } }; |
Implementation of the states is very dependent on tech so I’ve left an example out. States should typically be implemented as Singletons, which will be done on a class by class basis to classes that inherit from GameState.
I’ll continue my work and keep you all updated as major engine features get added. In the mean time though, I think I’ll post about the creation of the new header
. Be on the lookout and make sure to tell your friends about this site! <3
4 Comments, Comment or Ping
Hi!
Its just a co-incidence or let me say, this phenomenon is very common! I just read through your first post and it made me chuckle since I am in the same boat
(I also haven’t completed any of my games, yet!)
On that note, I am trying to complete this very simple game I did sometime back. Its a simple pong game that I did but I want to implement a game menu system for that to make it look like a complete game product. I need some help with that..
Would it be possible for you to help me implement the game-menu system for that ?
In case you are wondering, this pong game serves as my guinea pig experiment test-bed. I try and implement everything there and then use that generic code in other games
December 31st, 2008
Sure, I can help you out. Shoot me an email and I’ll see what I can do.
“I try and implement everything there and then use that generic code in other games” , that’s the best way to get started! Just make sure your code is of high quality, if you’re reusing flawed code your problems will compound over time in every program that you make.
January 1st, 2009
Hi Tyler!
The article “Managing Game States in C++” is the one I’ve read before and after I’ve always used the game states like that!
Consider also the possibility to divide the phase of init with the phase of resource loading, maybe with a method (init) that initalize all the game-state classes BUT doesn’t allocate memory, and another (enter) that physically load all the resources (and vice-versa with leave and cleanup).
This ensure that you can have a longer lifecycle of a state (maybe it contains some useful informations for other states) but it has no resources loaded in memory.
Well, this is only my thought! Hope it helps!
January 11th, 2009
I’ve thought about it before, if we’ve got the state loading up resources on a per state basis, and we change states, but need resources that the last state loaded and subsequently unloaded upon it’s close…we’re wasting cycles reloading the same resources. This really comes seriously into play when one is changing between states frequently, for example using states to represent “levels” in a game individually rather than with an umbrella PlayState. Even if we’re not changing states that frequently, your suggestion can cut load times by a large margin. My states as they stand are too abstract too worry about the resource loading times, as the transitions between each are infrequent but I like your idea, thanks
.
January 11th, 2009
Reply to “Game State Management”