备忘:
项目中大量使用了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>> {};