Sign in to follow this  
Silgen

Game States

Recommended Posts

Silgen    178
Going back to basics and writing really simple games (tic-tac-toe, currently) but trying to use a good, clean OO structure. All states are derived from a base class cState:

[source lang="cpp"]class cState {
public:
virtual void enter() = 0;
virtual void update() = 0;
virtual void leave() = 0;
};[/source]
The code below is for the state manager
[source lang="cpp"]void cGame::changeState(cState* targetState) {
currentState->leave();
currentState = targetState;
currentState->enter();
}[/source]

I was thinking of putting each state in its own file, but this means I will need to pass a pointer to the state manager (so that the state manager knows when to switch states) and also an inclusion for all of the header files for the states that it can transition to. This sounds messy. Is there a better way of doing it?

Share this post


Link to post
Share on other sites
SiCrane    11839
I usually use state classes that use the run and return successor pattern. Basically every function called on a state object returns a smart pointer to the state that the system should be in now. This can be a pointer to the original state. This avoids needing states to know anything about what holds the states. There may not even be an explicit state manager class. Example source for this kind of system is in [url=http://www.gamedev.net/topic/630301-managing-game-statescreens-without-managers-and-singletons/] this thread[/url].

Share this post


Link to post
Share on other sites
[quote name='Silgen' timestamp='1353605774' post='5003275']
Going back to basics and writing really simple games (tic-tac-toe, currently) but trying to use a good, clean OO structure. All states are derived from a base class cState:

[source lang="cpp"]class cState {
public:
virtual void enter() = 0;
virtual void update() = 0;
virtual void leave() = 0;
};[/source]
The code below is for the state manager
[source lang="cpp"]void cGame::changeState(cState* targetState) {
currentState->leave();
currentState = targetState;
currentState->enter();
}[/source]

I was thinking of putting each state in its own file, but this means I will need to pass a pointer to the state manager (so that the state manager knows when to switch states) and also an inclusion for all of the header files for the states that it can transition to. This sounds messy. Is there a better way of doing it?
[/quote]

I've haven't programmed stateful behaviour yet, but it was my understanding that the states themself manage the transition. (stateA->leave() returns stateB, alternatively leave() sets the next state itself). A state will include the states that it can transition to. Because of polymorphism you can then just store a pointer to the base class.

Share this post


Link to post
Share on other sites
1) What do these states actually represent?
2) Who calls changeState? Can't the states' own logic trigger a switch to other states?
3) If the concrete states form an intimately related system, unique to your particular game, I'd put them in the same .cpp file. Is there any real reason to spread them around? If they grew so huge compilation started being a problem, which file they reside in would be the least of your problems.

Share this post


Link to post
Share on other sites
[quote name='Stroppy Katamari' timestamp='1353608666' post='5003290']
1) What do these states actually represent?
2) Who calls changeState? Can't the states' own logic trigger a switch to other states?
3) If the concrete states form an intimately related system, unique to your particular game, I'd put them in the same .cpp file. Is there any real reason to spread them around? If they grew so huge compilation started being a problem, which file they reside in would be the least of your problems.
[/quote]

This is the right mindset, in my opinion.

Know your needs, and keep it simple.

Share this post


Link to post
Share on other sites
Silgen    178
Thankyou for all of your replies.

I've tried to take into consideration the points raised in the responses, and I've written a simple program to test this out. I was hoping you guys could give me some feedback - or some general pointers etc.

[u]Extract from cState.h[/u]
[source lang="cpp"]class cState {
private:
static cState* currentState;
static bool isRunning;
public:
virtual void enter() = 0;
virtual void update() = 0;
virtual void leave() = 0;

void setCurrentState(cState*);
void updateCurrentState();
void exit();
};

class cStateA : public cState {
public:
cStateA(cState*);
~cStateA();

void enter();
void update();
void leave();
};[/source]
[u]Extract from cState.cpp[/u]

[source lang="cpp"]#include "cState.h"

//---

cState* cState::currentState;
bool cState::isRunning = true;

void cState::setCurrentState(cState* target) {
currentState = target;
}

void cState::updateCurrentState() {
while(isRunning) {
currentState->update();
}
}

void cState::exit() {
isRunning = false;
}

//---

cStateA::cStateA(cState* caller) {
//Clean up after the caller state and initialise the current one
if(caller)
caller->leave();

setCurrentState(this);
enter();
}

cStateA::~cStateA() {
std::cout << ">> Destructor called for A" << std::endl;
}

void cStateA::enter() {
std::cout << ">> Entering State A" << std::endl;
}

void cStateA::update() {
std::cout << "Enter desired state: ";
if(getch() == 'b') {
setCurrentState(new cStateB(this));
}
}

void cStateA::leave() {
std::cout << std::endl << ">> Leaving State A" << std::endl;
delete this;
}[/source] Edited by Silgen

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