Generic programming of finite state machine
關于有限狀態機:
不想奢談高深的理論,理論太過高深有可能編程實現么?我覺得可以這么簡單理解吧,一個對象有多個狀態(注意這里的“對象”與“狀態”都是廣義與抽象的),通過事件(event)的觸發使得狀態(state)之間相互躍遷(transition),可以定義在狀態切換時所附加的操作(op)。而我們要實現的有限狀態機(finite state machine,以下簡稱FSM)便是維護與管理這一機制的代碼。
因為性能效率要求高的實時圖形程序(如三維網游)不可能用MFC這樣的商業程序框架,所以FSM便可以作為整個實時程序的核心部分,因為游戲程序等說到底無非是不同的一些狀態之間的切換,如開始的登錄界面,選擇角色界面,主游戲界面,單機版游戲還有專門的版權頁面等等.有些小游戲采用設計模式中的State模式來作為游戲的管理調度核心,但是作為大型的游戲,采用一種設計模式顯然是難以勝任應用程序核心的復雜要求的,這樣就必須有一種成熟機制來完成這一任務,今天我們來討論FSM.
關于泛型編程:
泛型編程,模板,設計模式,其重要性與優越性盡人皆知,在此不過多討論.我只是想說,從宏觀上來, ,它們的目的與作用是用c++來表達一些思想,而且這些思想還是實際代碼!光這一點就可以帶來很多好處,如代碼高復用率,靈活性與可擴展性,接口統一性等等.
有關FSM比較流行的資料是Game Programming Gems第一卷第三章第二篇文章,網上也流傳有中譯版.作者在里面討論與實現了一個簡單的FSM實現.他用采用State設計模式,用一個FSMclass類管理許多FSMstate類的實例,大家有興趣的可以去參考,而現在要討論的是一個更加接近實際產品代碼的FSM實現,勿須過多理論介紹,直接看代碼.
Code:
//模板類,傳入狀態類型與事件類型
template<typename state_type, typename event_type>
class fsmachine//通用基本有限狀態機類
{
public:
typedef fsmachine machine_type;
fsmachine(){}//構造函數
virtual ~fsmachine(){}//虛析構函數
void addState(const state_type& state)//增加狀態
{
typename state_map::iterator it = m_stateMap.find( state );//STL迭代子
if (it == m_stateMap.end())//如果狀態映射表中不存在此狀態
{
m_stateMap.insert(typename state_map::value_type(state,state_e()) );//插入
return;
}
}
void setState(const state_type& dest)//設置當前狀態
{
const typename state_map::const_iterator it = m_stateMap.find( dest );
if (it == m_stateMap.end())//如果找不到此狀態
{
//錯誤處理
return;
}
m_currState = dest;//設置為當前狀態
}
const state_type& currentState() const
{
return m_currState;//返回當前狀態
}
size_t numStates() const
{
return m_stateMap.size();//返回狀態映射表的數目
}
void clearStates()//清空狀態映射表
{
m_currState = state_type();//調用默認構造函數
m_stateMap.clear();//清空
}
void addTransition(const state_type& src, const event_type& evt, const state_type& dest)//增加src狀態的事件狀態躍遷記錄
{
if (src == dest)//源狀態與目標狀態相同,無意義
{
//錯誤處理
return;
}
typename state_map::iterator it = m_stateMap.find( src );
if (it == m_stateMap.end())//找不到源狀態
{
//錯誤處理
return;
}
{
const typename state_map::const_iterator itDest = m_stateMap.find( dest );
if (itDest == m_stateMap.end())//目標狀態不在狀態映射表中,不合法
{
//錯誤處理
return;
}
}
event_state_map& evt2state = it->second.transitions;
evt2state.insert( typename event_state_map::value_type( evt, dest) );//增加躍遷記錄
}
size_t numTransitions(const state_type& src) const//返回某狀態的躍遷記錄數
{
const typename state_map::const_iterator it = m_stateMap.find( src );
return ( (it == m_stateMap.end()) ? 0 : it->second.transitions.size() );
}
template<typename enter_state_op_t, typename exit_state_op_t>
void processEvent(const event_type& evt, enter_state_op_t& enterOp, exit_state_op_t& exitOp)//狀態躍遷函數
{
const typename state_map::const_iterator it = m_stateMap.find( m_currState );
if (it == m_stateMap.end())//源狀態不存在
{
//錯誤處理
return;
}
const event_state_map& evt2state = it->second.transitions;
const typename event_state_map::const_iterator itFindTransition = evt2state.find(evt);
if (itFindTransition == evt2state.end())//觸發事件不存在
{
//錯誤處理
return;
}
exitOp(*this,m_currState);//退出舊狀態的函數調用
m_currState = itFindTransition->second;//新狀態為當前狀態
enterOp(*this,m_currState);//進入新狀態的函數調用
}
private:
//對每一種狀態而言,都對應這樣的一個事件狀態躍遷映射表
typedef std::map<event_type,state_type> event_state_map;
//此結構體,用于保存每一種狀態的事件狀態躍遷映射表,以及用戶自定義數據
struct state_e
{
event_state_map transitions;
void* userData;
};
//定義fsm的狀態映射表
typedef std::map<state_type,state_e> state_map;
//fsmachine類的狀態映射表成員變量
state_map m_stateMap;
//當前狀態
state_type m_currState;
|