我基本上在多个系统中正交使用了这个精确系统。例如,前端和游戏内菜单(也称为“暂停”)状态具有其自己的状态堆栈。游戏中的UI也使用了类似的方法,尽管它具有状态切换可能会变色但在各州之间以通用方式更新的“全局”方面(例如健康栏和地图/雷达)。
游戏中的菜单可能由DAG表示为“更好”,但使用隐式状态机(转到另一个屏幕的每个菜单选项都知道如何去那里,并且按返回按钮始终会弹出顶部状态),效果是一模一样。
这些其他系统中的一些还具有“替换顶部状态”功能,但是通常先执行,StatePop()
然后再执行StatePush(x);
。
存储卡的处理方法类似,因为实际上我确实将大量“操作”推入了操作队列(在功能上与堆栈做相同的事情,只是作为FIFO而不是LIFO);一旦开始使用这种结构(“现在发生了一件事情,当它完成后它就会弹出”),它将开始感染代码的每个区域。甚至AI也开始使用这种东西。当玩家发出声音但未被看见时,AI变得“笨拙”,然后切换为“疲倦”,然后当他们看到玩家时,AI最终提升为“活动”(并且与当时的小游戏不同,您无法隐藏在一个纸板箱中,让敌人忘记你!不是我很苦...)。
GameState.h:
enum GameState
{
k_frontend,
k_gameplay,
k_inGameMenu,
k_moviePlayback,
k_numStates
};
void GameStatePush(GameState);
void GameStatePop();
void GameStateUpdate();
GameState.cpp:
// k_maxNumStates could be bigger, but we don't need more than
// one of each state on the stack.
static const int k_maxNumStates = k_numStates;
static GameState s_states[k_maxNumStates] = { k_frontEnd };
static int s_numStates = 1;
static void (*s_startupFunctions)()[] =
{ FrontEndStart, GameplayStart, InGameMenuStart, MovieStart };
static void (*s_shutdownFunctions)()[] =
{ FrontEndStop, GameplayStop, InGameMenuStop, MovieStop };
static void (*s_updateFunctions)()[] =
{ FrontEndUpdate, GameplayUpdate, InGameMenuUpdate, MovieUpdate };
static void GameStateStart(GameState);
static void GameStateStop(GameState);
void GameStatePush(GameState gs)
{
Assert(s_numStates < k_maxNumStates);
GameStateStop(s_states[s_numStates - 1])
s_states[s_numStates] = gs;
s_numStates++;
GameStateStart(gs);
}
void GameStatePop()
{
Assert(s_numStates > 1); // can't pop last state
s_numStates--;
GameStateStop(s_states[s_numStates]);
GameStateStart(s_states[s_numStates - 1]);
}
void GameStateUpdate()
{
GameState current = s_states[s_numStates - 1];
s_updateFunctions[current]();
}
void GameStateStart(GameState gs)
{
s_startupFunctions[gs]();
}
void GameStateStop(GameState gs)
{
s_shutdownFunctions[gs]();
}