饭后温柔

汉堡与老干妈同嚼 有可乐味
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

boost statechart 模板化的state类

Posted on 2013-02-01 00:16  饭后温柔  阅读(2610)  评论(0编辑  收藏  举报

备忘:

    项目中大量使用了boost的statecahrt状态机.这玩意麻烦,但有时确实挺好用的.排查时让人头痛.尤其是项目整个状态机庞大且混乱,穿插了大量不规则的不属于statechart框架的全局状态变量(bool变量啥的).但工作需要,我需要实现除去人物逻辑动作等状态之外,各个状态都能有一个子状态,这样状态切换时都能进行全屏特效或别的工作.目前的办法是给state加上模板参数.事实上,项目中的确实缺乏通用子状态概念,导致实现不同职业的状态机时,类似一些特效开关,加载配置等,全部都需要在每个职业实现一个状态机,状态机里全部重写这些步骤一遍.一旦这些通用的设置有修改,就要全部去找到各个职业的状态机,然后再找到各个状态,一个一个改之.

 

#ifndef __fsm_h__
#define __fsm_h__

#include <boost/statechart/event.hpp>
#include <boost/statechart/state_machine.hpp>
#include <boost/statechart/simple_state.hpp>
#include <boost/statechart/state.hpp>
#include <boost/statechart/custom_reaction.hpp>
#include <boost/statechart/transition.hpp>
#include <boost/statechart/result.hpp>

#include <boost/config.hpp>

#ifdef BOOST_INTEL
#  pragma warning( disable: 304 ) // access control not specified
#endif

namespace Alpha
{
    namespace fsm
    {
        namespace sc = boost::statechart;
        namespace mpl = boost::mpl;

        template< class MostDerived,
        class InitialState,
        class Allocator = std::allocator< void >,
        class ExceptionTranslator = sc::null_exception_translator >
        struct fsm_machine : public sc::state_machine<MostDerived, InitialState, Allocator, ExceptionTranslator>
        {

        };

        struct nulltype {};

        template<class Host> 
        struct fsm_state_init_converter
        {
            typedef mpl::list<Host>     type;
            typedef Host                origin_type;
        };

        template<> 
        struct fsm_state_init_converter< mpl::list<> >
        {
            typedef mpl::list<>  type;
            typedef nulltype     origin_type;
        };

        template<
            class MostDerived, 
            class Context, 
            class InnerInitial = boost::mpl::list<>, 
                sc::history_mode historyMode = sc::has_no_history
        >
        struct fsm_state : public sc::state<MostDerived, Context, typename fsm_state_init_converter<InnerInitial>::type, historyMode>
        {
            typedef sc::state<MostDerived, Context, typename fsm_state_init_converter<InnerInitial>::type, historyMode> my_state_base;
            typedef typename fsm_state_init_converter<InnerInitial>::origin_type initial_type;

            fsm_state(my_state_base::my_context ctx):my_state_base(ctx) {}
        };

        template<class Context> 
        struct fsm_common_init_state : public fsm::fsm_state<fsm_common_init_state<Context>, Context>
        {
            typedef fsm::fsm_state<fsm_common_init_state<Context>, Context> my_state_base;

            fsm_common_init_state(my_state_base::my_context ctx):my_state_base(ctx) 
            { std::cout << "enter fsm_common_init_state\n"; }
            ~fsm_common_init_state() { std::cout << "exit fsm_common_init_state\n"; }
        };

        template<class Context, 
            template<class _Context> class common_init_state_type = fsm_common_init_state>
        struct fsm_common_state : public fsm::fsm_state<fsm_common_state<Context, common_init_state_type>, 
            Context, 
            common_init_state_type<fsm_common_state<Context, common_init_state_type>> >
        {
            typedef fsm_common_state<Context, common_init_state_type> this_type;
            typedef fsm::fsm_state<this_type, Context, common_init_state_type<this_type> > my_state_base;

            fsm_common_state(my_state_base::my_context ctx):my_state_base(ctx) 
            { std::cout << "enter fsm_common_state\n"; }
            ~fsm_common_state() { std::cout << "exit fsm_common_state\n"; }
        };

    }
}

#endif

 下一步搭配正交区域.目前遇到的问题是当前状态跳转时,实现fading时需要进入一个中间状态,而不能直接跳转(例如下一个场景),将需要某种回调机制.当然这些实际上可以通过statechart的event和reaction模拟,但之前都是通过全局变量来控制,而且场景建立删除牢牢的变为当前状态的一部分了.如果level能够做成继承多态的,而不是绑定到状态上,靠状态区分level,应是更合适的方法.目前已经定死了,解决办法就是再添加2个全局的事件,通知通用子状态,因为退出时需要进行一个延迟几秒左右的处理,来进行类似淡出的效果.当然,如果渲染和逻辑能够支持多线程,就容易处理多了.也就不纠结这几秒的延迟事件了.暂告一段落.

 可能需要搭配的event带模板的.如下:

    template<class Host> struct EffectEvent_Fading : public sc::event<EffectEvent_Fading<Host>> {};
    template<class Host> struct EffectEvent_Blooming : public sc::event<EffectEvent_Blooming<Host>> {};