日期:2014-05-16  浏览次数:21700 次

C# FSM (仿Unity 中的Mecanim动画系统的状态机)

刚自学Unity,发现Unity 之所以很火,因为很多系统,编辑器,还有一些设计很强大,用起来都比较容易维护。(当然除了:发布程序跨平台之外)


自学中,发现,一个挺有趣的系统:Animator,这个在Unity 中,有一个独立的子面板:Animator的一个动画状态机切换可视化管理系统:FSM,如下图:

(游戏中,动画系统是一个比较复杂的系统,单单一个角色,可能动画就包含了N种,如果要想很好的管理,最好的就是使用FSM)


由于比较好奇,就着手写了个简单的FSM 测试项目源项目




以上,就是单个动画的状态机可视化管理界面;

any state就是每次都会处理的状态;(任意状态)

idle(闲置状态)

run(跑动状态)

dead(死亡状态)


大家应该也发现了,idle、run、dead这些状态之间都有一些带有方向的线段连接起来;

这些带方向的线段就是:Transition(等会我的代码,会有对应的类),意思就是设置了一些过渡参数,来从,原来的状态,过渡到:指定的状态;

如图:



而每个Transition其实是可以有多个:过渡管道;(Pipeline,有对应的类),就是管理,状态之间可以过渡的参数管理


以上是单个Pipeline,一个Transition中,含多个Pipeline的话,左边的视图中,带方向的的Transition外观会变成:带有三个方向的箭头:

如图:


以上,一个Transition有,两个Pipeline,第一个是当speed>10时(红色线部份),会从:idle过渡到:run状态,

而第二个Pipeline是,hp>50(看绿色线的部份),也会从:idle过渡到:run状态;

多个Pipeline之间的逻辑是:or,运算符:||的关系,意思是:

if (speed > 10 || hp > 50) 

    // transilated to run


其中,上图中,大家都应该看到了:Condition栏中的:speed,Greater,或是hp,Greater这些设置过渡的参数;

这些参数都对应:“源项目”的FSMParam类,如图:


FSM相关的声明:(注释挺少的,不过代码600多行,我就不贴上来了,有提供百度网盘下载就可以了,往下看)

    /// <summary>
    /// 状态机中,当前状态发生改变的事件委托声明
    /// </summary>
	public delegate void CurStateChangedEventHandler(FSM sender);

	/// <summary>
    /// 状态机中,当有参数发生变化时的事件委托声明
    /// </summary>
    public delegate void ParamsChangedEventHandler(FSM sender, ParamsChangedEvent args);

    /// <summary>
    /// 过渡参数为函数委托的声明
    /// </summary>
	public delegate bool FSMFuncParamHandler(params object[] objs);

    /// <summary>
    /// 状态机中,当有参数发生变化时的参数类声明
    /// </summary>
    public class ParamsChangedEvent : EventArgs;

    /// <summary>
    /// 有限状态机
    /// (
    ///     设计思路,参考:Unity 4.3.2f 版本的Mecanim动画系统中的状态机,
    ///     根据使用上的功能,来猜想实现思路,当然可能我的实现方式不是最好,
    ///     如果大家还有比较好的一些见解,那大家一起交流交流吧。
    ///     该博文就不多说其它的,我的文采也不好,直接上代码吧。
    /// )
    /// @author :   Jave.Lin(afeng)
    /// @time   :   2014-03-11
    /// @version:   1.0
    /// </summary>
	public class FSM;

	/// <summary>
    /// 状态
    /// </summary>
	public abstract class State;

	/// <summary>
    /// 状态之间的过度处理(可包含多个过度管道)
    /// </summary>
	public class Transition;

	/// <summary>
    /// 状态之间的过度管道(可包含多个过度条件)
    /// </summary>
	public class ChangStatePipeline;

	/// <summary>
    /// 过度参数的成立条件类型
    /// </summary>
	[Flags]
	public enum ConditionType;

	/// <summary>
    /// 过度参数类型
    /// </summary>
	public enum FSMParamType;

	/// <summary>
    /// 过度参数是函数类型
    /// </summary>
	public class FSMParamFunc : FSMParam;

	/// <summary>
    /// 过度参数是值类型
    /// </summary>
	public class FSMParamValue : FSMParam;

	/// <summary>
    /// 过度的参数类
    /// </summary>
	public abstract class FSMParam;

调用部份:(部份不算很多,我就全部拿上来了,这里比较清楚的可以看到,我们平时在Unity 操作Mecanim的一些设置中,大概内部是如何调用的一个过程)