Sign in to follow this  
Teenage Death Boy

Another game state question

Recommended Posts

After the recent threads about managing game states I have been trying to get my new game off to a good start with a solid state system. Following the threads on the forum and this page my system is as such. CGameEngine class declared in gameengine.h. It has member m_stateStack which is an STL stack of pointers to class CGameState. CGameState is contained in gamestate.h surprisingly enough and contains virtual functions draw and handleinput at the moment. I will be deriving my other states from this. At the moment I just have CTitle in title.h for the title screen, which is derived from CGameState. So in my main file, before starting int main i create engine object "CGameEngine engine;" and before entering my main loop I do CGameState *title = new CTitle; engine.pushState(title); which pushes the pointer to my CTitle state onto the stack. In my main loop I am using engine.m_stateStack.top()->draw(); engine.m_stateStack.top()->handleInput(); to run the appropriate function from whichever state is top of the stack. Now the problem I have is when I want to pop a state from the stack, I will need to run the popstate member function in CGameEngine (at the moment the function basically just runs the pop function of the STL stack). Being its late at night my only idea has been to give the CGameState class a pointer back to the engine, so it can say "engine.popstate();". To create a pointer to the CGameEngine class, I obviously need to add #include "gameengine.h" to the top of the gamestate.h header. This generates a lot of errors unless I also add in gameengine.h the like "class CGameState;". Even then I have the problem that even though I included the header that has the class definition of CGameEngine, I can't create a pointer (or use as a parameter) to the CGameEngine object, the compiler gives: gamestate.h(19) : error C2061: syntax error : identifier 'CGameEngine' However, in one of the derived classes, say title.h that includes gamestate.h, i CAN use pointers to CGameEngine object. Now I am really confused. Maybe I am handling this all in the wrong way, or a very inefficient way. What would be the better way of making the engine pop the state stack? Why am I having these problems creating a pointer to the engine object? And even if I had a pointer to CGameEngine, I'm guessing I would have to use the constructor for CGameState to assign the pointer to point to my engine object. Any help is greatly appreciated, but if I could avoid answers with complex solutions that would be nice :).

Share this post


Link to post
Share on other sites
Quote:
Original post by Teenage Death Boy

Being its late at night my only idea has been to give the CGameState class a pointer back to the engine, so it can say "engine.popstate();"



That is a really awkward way to handle things from the OO perspective. I've seen people try to use a similar strategy in large projects with results that were nothing short of disastrous. The problem is that when you do that, your CGameState class becomes coupled with your CGameEngine class.

The way I would handle this would be to make handleInput() modify some flag that is accessible to your CGameState object and to your main game loop whenever the state needs to be changed. That way, after you call handleInput(), you can do:


if (someFlag == true)
engine.popstate();


It exchanges coupling for side effects, but I think that side effects are the lesser of two evils. Maybe some of the more experienced OO masterminds here can twoCents->give(world_);

Share this post


Link to post
Share on other sites
Quote:
Original post by Teenage Death Boy
What would be the better way of making the engine pop the state stack?


Let the engine handle the state-processing logic, and have states communicate their need to be popped, rather than having them try to pop themselves:


void CGameEngine::runCurrentState() {
CGameState* current = m_stateStack.top();
current->draw();
// Handle input, and remove the state if the input indicates that it is done.
if (current->handleInput()) { m_stateStack.pop(); }
}



However, you may also want to consider other ways of managing the state, i.e. with patterns like Run and Return Successor (which I personally find to be about the most intuitive thing ever, whereas I never ever would have thought of this stack-based stuff except that it gets mentioned on GameDev.net every now and then). In the general case with RARS, you may require states to include a "State* previous" or something:


class State {
State* previous;
State(State* previous) : previous(previous) {}
// etc.
}

State FooState::Run() {
// do stuff...
return BarState(this);
}

State BarState::Run() {
// This is a submenu or something
return *previous;
}
// You're on your own WRT getting the memory management right in C++ with this
// kind of scheme, though. Much nicer in GC languages.



Quote:
Why am I having these problems creating a pointer to the engine object?


Did you read the GD.net bible of C/C++ source organization?

Share this post


Link to post
Share on other sites
Hmm, I havnt had time to look into RARS but will soon. I knew pretty much all of the source organisation article (been using inclusion guards etc, and project seems to be structured fine according to that) but hadnt come across the forward declaration part which was what was relevant to me.

A new day now and I can't believe I didnt think to just have the input function return a value which could let the engine pop the stack. Thanks for the help guys

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this