Я использую фабричный шаблон в сочетании с шаблоном состояний в моей будущей игре.
Код может быть немного грязным, но я постараюсь его почистить.
Это класс, из которого вы получаете все состояния, такие как меню, игра или что-то еще.
class GameState {
public:
virtual ~GameState() { }
virtual void Logic() = 0;
virtual void Render() = 0;
};
Этот класс будет вашим интерфейсом для обработки различных состояний. Вы можете динамически добавлять и идентифицировать динамически.
class State {
public:
State();
virtual ~State();
void Init();
void Shutdown();
void SetNext( std::string next_state );
void Exit();
bool Logic();
void Render();
protected:
bool Change();
std::string state_id;
std::string next_state;
GameState *current_state;
std::vector<std::string> state_ids;
StateFactory *state_factory;
bool is_init;
};
Я использую функтор для создания различных производных GameState.
class BasicStateFunctor {
public:
virtual GameState *operator ()() = 0;
};
template<class T>
class StateFunctor : public BasicStateFunctor {
public:
StateFunctor() { }
GameState *operator ()() {
return new T;
}
typedef T type;
};
Наконец, фабрика, которая будет хранить и управлять различными состояниями.
class StateFactory {
public:
StateFactory();
virtual ~StateFactory();
bool CheckState( std::string id );
GameState *GetState( std::string id );
template<class T> void AddState( std::string id );
private:
typedef std::map<std::string, BasicStateFunctor*>::iterator StateIt;
std::map<std::string, BasicStateFunctor*> state_map;
};
В вашем файле определения:
Здесь я упустил много вещей, но, надеюсь, вы поймете идею.
bool StateFactory::CheckState( std::string id )
{
StateIt it = state_map.find( id );
if( it != state_map.end() )
return true;
else
return false;
}
GameState *StateFactory::GetState( std::string id )
{
StateIt it = state_map.find( id );
if( it != state_map.end() )
{
return (*(*it).second)();
} else {
//handle error here
}
template<class T> void StateFactory::AddState( std::string id )
{
StateFunctor<T> *f = new StateFunctor<T>();
state_map.insert( state_map.end(), std::make_pair( id, f ) );
}
void State::Init()
{
state_factory = new StateFactory();
state_factory->AddState<Game>( "game" );
current_state = state_factory->GetState( "game" );
is_init = true;
}
void State::SetNext( std::string new_state )
{
//if the user doesn't want to exit
if( next_state != "exit" ) {
next_state = new_state;
}
}
bool State::Change()
{
//if the state needs to be changed
if( next_state != "" && next_state != "exit" )
{
//if we're not about to exit( destructor will call delete on current_state ),
//call destructor if it's a valid new state
if( next_state != "exit" && state_factory->CheckState( next_state ) )
{
delete current_state;
current_state = state_factory->GetState( next_state );
}
else if( next_state == "exit" )
{
return true;
}
state_id = next_state;
//set NULL so state doesn't have to be changed
next_state = "";
}
return false;
}
bool State::Logic()
{
current_state->Logic();
return Change();
}
А вот как вы это используете:
Инициализируйте и добавьте различные состояния, я делаю это в Init ().
State.Init();
//remember, here's the Init() code:
state_factory = new StateFactory();
state_factory->AddState<Game>( "game" );
current_state = state_factory->GetState( "game" );
is_init = true;
Для функции кадра
State.Logic(); //Here I'm returning true when I want to quit
и для функции рендеринга
State.Render();
Это может быть не идеально, но у меня это хорошо работает.
Для дальнейшего продвижения дизайна вы хотели бы добавить Singleton для State и, возможно, сделать StateFactory скрытым классом внутри State.