This a singleton Class for managing GameStates. (I know it's game programming, but it is also all C++ as well)
This is the class. Notice: it is all inline so it may be hard to follow, and I apologize ahead of time.
Code:
#include "gHge.h"
#include <map>
//This has to be the Base class for every gamestate class
class GameState
{
public:
virtual bool Initiate() = 0;
virtual bool Shutdown() = 0;
virtual bool Update(float delta) = 0;
virtual bool Render() = 0;
};
class gsMgr
{
public:
gsMgr():curState(0){};
~gsMgr()
{
//Free all states
std::map<size_t, GameState*>::iterator iter;
for ( iter = GameStates.begin(); iter != GameStates.end(); ++iter )
FreeState((*iter).first);
};
//Add a state to the stateMgr
void CreateState(size_t index, GameState* StatePtr)
{
if ( GameStates.find(index) != GameStates.end() )
{
if ( GameStates[index] != 0 )
{
hge::Ref()->System_Log("Error: GameStates[%d] already exists.\n",index);
//Free memory from pointer if it is not needed.
if ( StatePtr != 0 )
{
delete StatePtr;
StatePtr = 0;
};
return;
}
}
GameStates[index] = StatePtr;
hge::Ref()->System_Log("Passed: GameStates[%d] added.\n",index);
};
bool InitiateState(size_t index)
{
if ( GameStates.find(index) != GameStates.end() )
{
if ( GameStates[index] != 0 )
{
if ( GameStates[index]->Initiate() )
{
hge::Ref()->System_Log("Passed: Initiate GameStates[%d].\n",index);
return true;
}
else
{
hge::Ref()->System_Log("Error: Initiate GameStates[%d] failed.\n",index);
return false;
}
}
else
{
hge::Ref()->System_Log("Error: Attempted to initiate <null> GameStates[%d].\n",index);
return false;
}
}
hge::Ref()->System_Log("Error: Attempted to initiate non-existant GameStates[%d].\n",index);
return false;
};
//Call shutdown method in GameStates[index]. Does NOT delete state.
bool ShutdownState(size_t index)
{
if ( GameStates.find(index) != GameStates.end() )
{
if ( GameStates[index] != 0 )
{
if ( GameStates[index]->Shutdown() )
{
hge::Ref()->System_Log("Passed: Shutdown GameStates[%d].\n",index);
return true;
}
else
{
hge::Ref()->System_Log("Error: Shutdown GameStates[%d] failed.\n",index);
return false;
}
}
else
{
hge::Ref()->System_Log("Error: Attempted to shutdown <null> GameStates[%d].\n", index);
return false;
}
}
hge::Ref()->System_Log("Error: Attempted to shutdown non-existant GameStates[%d].\n",index);
return false;
};
//Shutdown the state. Delete the state, and set value to 0
void FreeState(size_t index)
{
if ( GameStates.find(index) != GameStates.end() )
{
if ( GameStates[index] != 0 )
{
//Run shutdown function
ShutdownState(index);
//Free pointer memory
delete GameStates[index];
//Set pointer value to 0
GameStates[index] = 0;
hge::Ref()->System_Log("Passed: Freed GameStates[%d].\n", index);
return;
}
else
{
hge::Ref()->System_Log("Error: Attempted to free <null> GameStates[%d].\n",index);
return;
}
}
hge::Ref()->System_Log("Error: Attempted to free non-existant GameStates[%d].\n",index);
};
int SetState(size_t index)
{
if ( GameStates.find(index) != GameStates.end() )
{
if ( GameStates[index] != 0 )
{
if ( curState != index )
{
ShutdownState(curState);
hge::Ref()->System_Log("Passed: Switched GameState from [%d] to [%d].\n",curState,index);
curState = index;
InitiateState(curState);
return 0;
}
else
{
InitiateState(curState);
return 0;
}
}
else
{
hge::Ref()->System_Log("Failed: Requested index is <null>. Finding a valid Index.\n");
}
}
//Try to find a valid index
long t_ = FindValidState_();
if ( t_ != -1 )
{
hge::Ref()->System_Log("Passed: Found index[%d].\n",t_);
ShutdownState(curState);
curState = t_;
InitiateState(curState);
return 1;
}
else
{
hge::Ref()->System_Log("Failed: No valid States. Fatal Error.\n");
return -1;
}
};
//Update the current gamestate
bool UpdateState(float delta)
{
if (GameStates[curState] != 0)
{
//Update
if ( GameStates[curState]->Update(delta) )
{
//Nothing bad happened
return true;
}
else
{
//Error in update
return false;
}
}
//Error invalid state. Lots of bad things can happen if this does.
return false;
};
bool RenderState()
{
if (GameStates[curState] != 0 )
{
//Render
if ( GameStates[curState]->Render() )
{
//Nothing bad happened
return true;
}
else
{
//Error in rendering
return false;
}
}
//Error invalid state. Lots of bad things can happen if this does.
return false;
};
//Singleton functions
static gsMgr& Ref()
{
if (!singleton)
{
hge::Ref()->System_Log("Initiated Singleton gsMgr class.\n");
singleton = new gsMgr();
}
return *singleton;
};
static gsMgr*& Ptr()
{
if (!singleton)
{
hge::Ref()->System_Log("Initiated Singleton gsMgr class.\n");
singleton = new gsMgr();
}
return singleton;
};
private:
//The single StateMgr
static gsMgr* singleton;
//The index for the current GameState
size_t curState;
//The container of all GameStates
std::map<size_t, GameState*> GameStates;
//This function is used to find a valid state if the specified is not valid.
//This is called by the SetState() function if it fails.
//Return index to first found valid state. Else returns -1
long FindValidState_()
{
std::map<size_t, GameState*>::iterator iter;
for ( iter = GameStates.begin(); iter != GameStates.end(); ++iter )
{
if ((*iter).second != NULL )
return (*iter).first;
};
return -1;
};
};
gsMgr* gsMgr::singleton = 0;
Well let me know what you think. Thank you again. I just want to make sure it is safe to use before I use it large scale.