I use game state manager (intro, main menu, gameplay etc) from here. However there is one problem. A very minimalistic example:
class cApp //manages the states and gives them access to window
{
public:
cApp (RenderWindow & ref) : window(ref) {}
void changeState(cState *); //these function realy doesn't matter
void update();
void draw();
RenderWindow & window; //the same as in the article, this class not only manages state but gives them access to window etc
private:
std::vector <cState *> states;
}
The state:
class cState
{
public:
cState(cApp * ptr) : app(ptr) {}
virtual void update() = 0;
virtual void draw() = 0;
protected:
cApp * app;
}
So far everything is good. The problem is this is the part of basic framework. So the cApp is only very basic and gives access only to window. However there may be the case where the user wants to use networking in his game. Network engine isn’t a part of single state so it must be at the more global (that means, cApp) level.
So the user does:
class cNetworkedApp : public cApp
{
public:
cNetworkedApp(RenderWindow & ref1, NetworkEngine & ref2)
: networking(ref2), cApp(ref1)
NetworkEngine & networking; //initialized in cNetworkedApp constructor
}
class CharacterCreationState : public cState
{
CharacterCreationState(cApp * ptr) : cState(ptr) {}
//implement pure virtual functions
void draw()
{}
void update()
{
//THE PROBLEM
//the state needs to access the network engine so casting is required
cNetworkedApp * ptr = static_cast<cNetworkedApp*>(app))
ptr->networking.sendSomething();
}
}
The only obvious solution is to include everything what may be possible in cApp, however as I said this is a framework. Of course some engines like physics engine or sound engine are things which you put into a state so that’s not problem, but things like networking system must be the one object available for all states. And not every app uses it.
Do I need to redesign this code or is it okay?
Your
cAppmay keep with it a named list of a polymorphic typeEngine, iemap<string,Engine*>, then, your user may ask thecAppif it has a given engine.NetworkEnginewould be a subclass of the pure abstractEngine.Update
When dealing with a pointer that I you are sure that it is of the given specialized type, you should use
static_cast, when you wanna query if the pointer can be casted to a type you should usedynamic_cast.I, myself, have a safer approach for the first case, I use an assertion to guarantee that the type can be casted and use the
static_castin normal code:Only a object of type
NetworkEngineshould be putted on the “network” name, but maybe someone mistakenly put something else, theassertwill make us safer without needing to worry about the overhead.