找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 1810|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

有限狀態(tài)機(jī)之泛型編程

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:107189 發(fā)表于 2016-3-6 00:22 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
Generic programming of finite state machine

關(guān)于有限狀態(tài)機(jī):
不想奢談高深的理論,理論太過高深有可能編程實(shí)現(xiàn)么?我覺得可以這么簡(jiǎn)單理解吧,一個(gè)對(duì)象有多個(gè)狀態(tài)(注意這里的“對(duì)象”與“狀態(tài)”都是廣義與抽象的),通過事件(event)的觸發(fā)使得狀態(tài)(state)之間相互躍遷(transition),可以定義在狀態(tài)切換時(shí)所附加的操作(op)。而我們要實(shí)現(xiàn)的有限狀態(tài)機(jī)(finite state machine,以下簡(jiǎn)稱FSM)便是維護(hù)與管理這一機(jī)制的代碼。

    因?yàn)樾阅苄室蟾叩膶?shí)時(shí)圖形程序(如三維網(wǎng)游)不可能用MFC這樣的商業(yè)程序框架,所以FSM便可以作為整個(gè)實(shí)時(shí)程序的核心部分,因?yàn)橛螒虺绦虻日f(shuō)到底無(wú)非是不同的一些狀態(tài)之間的切換,如開始的登錄界面,選擇角色界面,主游戲界面,單機(jī)版游戲還有專門的版權(quán)頁(yè)面等等.有些小游戲采用設(shè)計(jì)模式中的State模式來(lái)作為游戲的管理調(diào)度核心,但是作為大型的游戲,采用一種設(shè)計(jì)模式顯然是難以勝任應(yīng)用程序核心的復(fù)雜要求的,這樣就必須有一種成熟機(jī)制來(lái)完成這一任務(wù),今天我們來(lái)討論FSM.

關(guān)于泛型編程:
    泛型編程,模板,設(shè)計(jì)模式,其重要性與優(yōu)越性盡人皆知,在此不過多討論.我只是想說(shuō),從宏觀上來(lái), ,它們的目的與作用是用c++來(lái)表達(dá)一些思想,而且這些思想還是實(shí)際代碼!光這一點(diǎn)就可以帶來(lái)很多好處,如代碼高復(fù)用率,靈活性與可擴(kuò)展性,接口統(tǒng)一性等等.

    有關(guān)FSM比較流行的資料是Game Programming Gems第一卷第三章第二篇文章,網(wǎng)上也流傳有中譯版.作者在里面討論與實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的FSM實(shí)現(xiàn).他用采用State設(shè)計(jì)模式,用一個(gè)FSMclass類管理許多FSMstate類的實(shí)例,大家有興趣的可以去參考,而現(xiàn)在要討論的是一個(gè)更加接近實(shí)際產(chǎn)品代碼的FSM實(shí)現(xiàn),勿須過多理論介紹,直接看代碼.

Code:
//模板類,傳入狀態(tài)類型與事件類型
template<typename state_type, typename event_type>
class fsmachine//通用基本有限狀態(tài)機(jī)類
{
public:
    typedef fsmachine machine_type;

    fsmachine(){}//構(gòu)造函數(shù)
    virtual ~fsmachine(){}//虛析構(gòu)函數(shù)

    void addState(const state_type& state)//增加狀態(tài)
    {
       typename state_map::iterator it = m_stateMap.find( state );//STL迭代子
       if (it == m_stateMap.end())//如果狀態(tài)映射表中不存在此狀態(tài)
       {
           m_stateMap.insert(typename state_map::value_type(state,state_e()) );//插入
           return;
       }
    }

    void setState(const state_type& dest)//設(shè)置當(dāng)前狀態(tài)
    {
       const typename state_map::const_iterator it = m_stateMap.find( dest );
       if (it == m_stateMap.end())//如果找不到此狀態(tài)
       {
           //錯(cuò)誤處理
           return;
       }
       m_currState = dest;//設(shè)置為當(dāng)前狀態(tài)
    }

    const state_type& currentState() const
    {
       return m_currState;//返回當(dāng)前狀態(tài)
    }

    size_t numStates() const
    {
       return m_stateMap.size();//返回狀態(tài)映射表的數(shù)目
    }

    void clearStates()//清空狀態(tài)映射表
    {
       m_currState = state_type();//調(diào)用默認(rèn)構(gòu)造函數(shù)
       m_stateMap.clear();//清空
    }

    void addTransition(const state_type& src, const event_type& evt, const state_type& dest)//增加src狀態(tài)的事件狀態(tài)躍遷記錄
    {
       if (src == dest)//源狀態(tài)與目標(biāo)狀態(tài)相同,無(wú)意義
       {
           //錯(cuò)誤處理
           return;
       }
       typename state_map::iterator it = m_stateMap.find( src );
       if (it == m_stateMap.end())//找不到源狀態(tài)
       {
           //錯(cuò)誤處理
           return;
       }
       {
           const typename state_map::const_iterator itDest = m_stateMap.find( dest );
           if (itDest == m_stateMap.end())//目標(biāo)狀態(tài)不在狀態(tài)映射表中,不合法
           {
              //錯(cuò)誤處理
              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//返回某狀態(tài)的躍遷記錄數(shù)
    {
       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)//狀態(tài)躍遷函數(shù)
    {
       const typename state_map::const_iterator it = m_stateMap.find( m_currState );
       if (it == m_stateMap.end())//源狀態(tài)不存在
       {
           //錯(cuò)誤處理
           return;
       }
       const event_state_map& evt2state = it->second.transitions;
       const typename event_state_map::const_iterator itFindTransition = evt2state.find(evt);
       if (itFindTransition == evt2state.end())//觸發(fā)事件不存在
       {
           //錯(cuò)誤處理
           return;
       }
       exitOp(*this,m_currState);//退出舊狀態(tài)的函數(shù)調(diào)用
       m_currState = itFindTransition->second;//新狀態(tài)為當(dāng)前狀態(tài)
       enterOp(*this,m_currState);//進(jìn)入新狀態(tài)的函數(shù)調(diào)用
    }

private:
    //對(duì)每一種狀態(tài)而言,都對(duì)應(yīng)這樣的一個(gè)事件狀態(tài)躍遷映射表
    typedef std::map<event_type,state_type> event_state_map;
    //此結(jié)構(gòu)體,用于保存每一種狀態(tài)的事件狀態(tài)躍遷映射表,以及用戶自定義數(shù)據(jù)
    struct state_e
    {
       event_state_map transitions;
       void* userData;
    };
    //定義fsm的狀態(tài)映射表
    typedef std::map<state_type,state_e> state_map;
    //fsmachine類的狀態(tài)映射表成員變量
    state_map m_stateMap;
    //當(dāng)前狀態(tài)
    state_type m_currState;


分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表