好久之前写过一篇关于状态机的小例子,可以看这里http://www.cnblogs.com/mawanli/p/5966080.html,这篇博客首先感谢需要感谢当时看到凉鞋的笔记博客,

凉鞋的博客地址先分享出来http://liangxiegame.com/tag/unity_framework/

今天在这里打算在重新谈论一下这些事情,是在一个gameframework的框架里面学到新的设计方法,今天打算是贡献出来,欢迎大家指教。

首先介绍下什么是状态机,状态机说白了就是自己的状态可以通过外界条件或者自身可以转换状态的一种模式。我们需要设计状态机和状态机的状态,每个状态包含进入此状态,离开此状态的事件,状态机里面需要记录当前的状态以及状态机里的事件和状态机调换状态的方法。

先看状态机的状态设计

    public abstract class FSMState
{
private string m_StateName; /// <summary> /// 初始化有限状态机状态基类的新实例 /// </summary> /// <param name="name">状态名称</param> public FSMState(string name)
{
m_StateName = name;
} /// <summary> /// 状态的名字 /// </summary> public string GetStateName
{
get
{
return m_StateName;
}
} /// <summary> /// 有限状态机状态初始化时调用。 /// </summary> /// <param name="fsm">有限状态机引用。</param> public virtual void OnInit()
{ } /// <summary> /// 有限状态机状态进入时调用。 /// </summary> /// <param name="fsm">有限状态机引用。</param> public virtual void OnEnter()
{ } /// <summary> /// 有限状态机状态离开时调用。 /// </summary> /// <param name="fsm">有限状态机引用。</param> /// <param name="isShutdown">是否是关闭有限状态机时触发。</param> public virtual void OnLeave(bool isShutdown)
{ } /// <summary> /// 有限状态机状态销毁时调用。 /// </summary> /// <param name="fsm">有限状态机引用。</param> public virtual void OnDestroy()
{ }
}

接着是状态机的设计,状态机需要继承状态的的基类,先看基类的设计

    public abstract class FSMBase<T,P>
{
private readonly string m_Name; /// <summary> /// 初始化有限状态机基类的新实例。 /// </summary> public FSMBase(): this(null)
{ } /// <summary> /// 初始化有限状态机基类的新实例。 /// </summary> /// <param name="name">有限状态机名称。</param> public FSMBase(string name)
{
m_Name = name ?? string.Empty;
} /// <summary> /// 获取有限状态机名称。 /// </summary> public string Name
{
get
{
return m_Name;
}
} /// <summary> /// 获取有限状态机持有者 /// </summary> public abstract T GetOwner
{
get;
} /// <summary> /// 获取有限状态机中状态的数量。 /// </summary> public abstract int FsmStateCount
{
get;
} /// <summary> /// 获取有限状态机是否正在运行。 /// </summary> public abstract bool IsRunning
{
get;
} /// <summary> /// 获取有限状态机是否被销毁。 /// </summary> public abstract bool IsDestroyed
{
get;
} /// <summary> /// 获取当前有限状态机状态名称。 /// </summary> public abstract string CurrentStateName
{
get;
} /// <summary> /// 关闭并清理有限状态机。 /// </summary> internal abstract void Shutdown();
}

接着看状态的设计

    public sealed class FSM<T,P> : FSMBase<T,P>
{
private readonly Dictionary<P, FSMState> m_States; //记录所有状态机的状态 private readonly Dictionary<int, FsmEventHandler<FSMEventArgs>> m_EventHandler; //记录所有状态机中的事件 private FSMState m_CurrentState; //当前状态 private T m_Owner; //状态机持有者 private bool m_IsDestoryed; //是否被销毁 public FSM(string name, T owner, List<StateTypeData<P>> states): base(name)
{
if (owner == null)
{
Console.WriteLine("状态机持有者无效");
} if (states == null || states.Count < )
{
Console.WriteLine("状态机无效");
} m_Owner = owner;
m_States = new Dictionary<P, FSMState>();
m_EventHandler = new Dictionary<int, FsmEventHandler<FSMEventArgs>>(); foreach (StateTypeData<P> state in states)
{
if (state == null)
{
Console.WriteLine("状态机无效");
break;
}
if (m_States.ContainsKey(state.GetType))
{
Console.WriteLine("状态机中已经存在此状态"); } m_States.Add(state.GetType, state.GetState);
state.GetState.OnInit();
} m_CurrentState = null;
m_IsDestoryed = false;
} /// <summary> /// 状态机持有者 /// </summary> public override T GetOwner
{
get
{
return m_Owner;
}
} /// <summary> /// 状态的数量 /// </summary> public override int FsmStateCount
{
get
{
if (m_States != null)
{
return m_States.Count;
}
else
{
//状态机还未初始化 return ;
}
}
} /// <summary> /// 状态机是否在运行,在运行返回True /// </summary> public override bool IsRunning
{
get
{
return m_CurrentState != null;
}
} /// <summary> /// 状态机是否被销毁 /// </summary> public override bool IsDestroyed
{
get
{
return m_IsDestoryed;
}
} /// <summary> /// 状态名字 /// </summary> public override string CurrentStateName
{
get
{
if (m_CurrentState != null)
{
return m_CurrentState.GetStateName;
}
else
{
//取值无效 return null;
}
}
} public FSMState GetState()
{
return m_CurrentState;
} /// <summary> /// 关闭状态机 /// </summary> internal override void Shutdown()
{
if (m_CurrentState != null)
{
m_CurrentState.OnLeave(true);
m_CurrentState = null;
} foreach (KeyValuePair <P, FSMState> state in m_States)
{
state.Value.OnDestroy();
} m_States.Clear();
//m_Datas.Clear(); //状态机数据 m_IsDestoryed = true;
} /// <summary> /// 开启有限状态机 /// </summary> /// <param name="stateType">起始状态类型</param> public void Start(P stateType)
{
if (IsRunning)
{
//状态机已经在运行 }
FSMState state = GetState(stateType);
if (state == null)
{
//状态机起始状态不存在 }
m_CurrentState = state;
m_CurrentState.OnEnter();
} /// <summary> /// 状态机是否存在此状态 /// </summary> /// <param name="stateType"></param> /// <returns></returns> public bool HasState(P stateType)
{
return m_States.ContainsKey(stateType);
} /// <summary> /// 获取想要的状态 /// </summary> /// <param name="stateType"></param> /// <returns></returns> public FSMState GetState(P stateType)
{
FSMState state = null;
if (m_States.TryGetValue(stateType, out state))
{
return state;
}
return null;
} /// <summary> /// 是否存在此状态 /// </summary> /// <param name="name"></param> /// <returns></returns> public bool HasData(P name)
{
return m_States.ContainsKey(name);
} /// <summary> /// 切换当前有限状态机状态。 /// </summary> /// <param name="stateType">要切换到的有限状态机状态类型。</param> public void ChangeState(P stateType)
{
if (m_CurrentState == null)
{
//状态机已经失效 return;
}
FSMState state = GetState(stateType);
if (state == null)
{
//不能切换到不存在的状态 return;
}
m_CurrentState.OnLeave(false);
m_CurrentState = state;
m_CurrentState.OnEnter();
} /// <summary> /// 订阅有限状态机事件。 /// </summary> /// <param name="eventId">事件编号。</param> /// <param name="eventHandler">有限状态机事件响应函数。</param> public void SubscribeEvent(int eventId, FsmEventHandler<FSMEventArgs> eventHandler)
{
if (eventHandler == null)
{
//响应事件为空 } if (!m_EventHandler.ContainsKey(eventId))
{
m_EventHandler[eventId] = eventHandler;
}
else
{
m_EventHandler[eventId] += eventHandler;
}
} /// <summary> /// 取消订阅有限状态机事件。 /// </summary> /// <param name="eventId">事件编号。</param> /// <param name="eventHandler">有限状态机事件响应函数。</param> public void UnsubscribeEvent(int eventId, FsmEventHandler<FSMEventArgs> eventHandler)
{
if (eventHandler == null)
{
//事件无效 } if (m_EventHandler.ContainsKey(eventId))
{
m_EventHandler[eventId] -= eventHandler;
}
} /// <summary> /// 响应有限状态机事件时调用。 /// </summary> /// <param name="fsm">有限状态机引用。</param> /// <param name="sender">事件源。</param> /// <param name="eventId">事件编号。</param> /// <param name="userData">用户自定义数据。</param> public void OnEvent(object sender, int eventId, FSMEventArgs userData)
{
FsmEventHandler<FSMEventArgs> eventHandlers = null;
if (m_EventHandler.TryGetValue(eventId, out eventHandlers))
{
if (eventHandlers != null)
{
eventHandlers(sender, userData);
}
}
}
}

状态机里的事件设计,,所有事件都要继承此类

    public abstract class FSMEventArgs: EventArgs
{
private String m_Name; /// <summary> /// 初始化事件类 /// </summary> /// <param name="_name">事件名字</param> public FSMEventArgs(String _name)
{
m_Name = _name;
} /// <summary> /// 得到事件的名字 /// </summary> public String GetEventName
{
get
{
return m_Name;
}
}
}
    /// <summary>

    /// 状态机事件

    /// </summary>

    /// <typeparam name="P">状态机的枚举</typeparam>

    /// <param name="sender">发送者</param>

    /// <param name="userData">发送的数据</param>

    public delegate void FsmEventHandler<P>(object sender, P userData) where P : FSMEventArgs;

下面我自己写的三个状态的状态机的例子

首先定义了状态的枚举(方便区分状态,切换状态等都使用此枚举)

    /// <summary>

    /// 状态机枚举

    /// </summary>

    public enum ActioEnum
{
Start,
Update,
LateUpdate,
DisViable,
End
}

接着是几个状态,

    public class StateA : FSMState
{
public StateA() : base(typeof(StateA).FullName)
{
} public override void OnDestroy()
{
base.OnDestroy();
Console.WriteLine("StateA销毁");
} public override void OnEnter()
{
base.OnEnter();
Console.WriteLine("StateA进入");
} public override void OnInit()
{
base.OnInit();
Console.WriteLine("StateA初始化");
} public override void OnLeave(bool isShutdown)
{
base.OnLeave(isShutdown);
Console.WriteLine("StateA离开");
}
}

这是状态A,还有状态A,C, 大家可以根据状态A进行类比B,C,这里就不做出示例

状态机的大家可以参考下面的示例

    void Start ()
{
foreach (BianLiEnum item in Enum.GetValues(typeof(BianLiEnum)))
{
BianLiEnum q = (BianLiEnum)((int)item);
} List<StateTypeData<ActioEnum>> fSMStateList = new List<StateTypeData<ActioEnum>>();
StateA stateA = new StateA();
StateTypeData<ActioEnum> stA = new StateTypeData<ActioEnum>(ActioEnum.Start, stateA); StateB stateB = new StateB();
StateTypeData<ActioEnum> stB = new StateTypeData<ActioEnum>(ActioEnum.Update, stateB); StateC stateC = new StateC();
StateTypeData<ActioEnum> stC = new StateTypeData<ActioEnum>(ActioEnum.LateUpdate, stateC); fSMStateList.Add(stA);
fSMStateList.Add(stB);
fSMStateList.Add(stC); UnityGameObject unityObj = new UnityGameObject();
FSM<UnityGameObject, ActioEnum> m_FSM = new FSM<UnityGameObject, ActioEnum>("第一个状态机", unityObj, fSMStateList);
m_FSM.Start(ActioEnum.Start);
Debug.Log("状态机持有者是" + m_FSM.GetOwner);
m_FSM.ChangeState(ActioEnum.Update);
m_FSM.Shutdown();
Debug.Log("状态机已经销毁");
}

大家会发现示例当中创建状态机很繁琐,

然后我就用反射去创建状态机,下面是我通过反射创建得到所有的子类

    public static List<T> GetTypeChilds<T>(Type parentType)
{
List<T> lstType = new List<T>();
List<Type> typeList = new List<Type>();
List<string> typeNameList = new List<string>();
List<string> typeNameTempList = new List<string>();
Assembly assem = Assembly.GetAssembly(parentType);
foreach (Type tChild in assem.GetTypes())
{
if (tChild.BaseType == parentType)
{
typeList.Add(tChild);
typeNameList.Add(tChild.FullName);
typeNameTempList.Add(tChild.FullName);
//lstType.Add((T)Activator.CreateInstance(tChild)); }
} typeNameTempList.Sort();
int listLength = typeList.Count;
int nowIndex = ;
for (int i = ; i < listLength; i++)
{
nowIndex = typeNameList.IndexOf(typeNameTempList[i]);
lstType.Add((T)Activator.CreateInstance(typeList[nowIndex]));
} return lstType;
}

这只是得到所有的子类,没有添加到状态机当中去,还需要进行完善

下次修改的时候把反射加入到状态机的创建当中去,代码就会瞬间清晰许多

新FSM的一些思路的更多相关文章

  1. 【Android】一种提高Android应用进程存活率新方法

    [Android]一种提高Android应用进程存活率新方法 SkySeraph Jun. 19st 2016 Email:skyseraph00@163.com 更多精彩请直接访问SkySeraph ...

  2. 一种提高Android应用进程存活率新方法

    一.基础知识 1.Android 进程优先级 1.1 进程优先级等级一般分法:- Activte process- Visible Process- Service process- Backgrou ...

  3. Service系统服务(一):安装一个KVM服务器、KVM平台构建及简单管理、virsh基本管理操作、xml配置文件的应用、为虚拟机制作快照备份、快建新虚拟机

    一.安装一个KVM服务器 目标: 本例要求准备一台 RHEL7.2 服务器,将其搭建为KVM平台,主要完成下列操作: 1> 关闭本机的SELinux保护.防火墙服务   2> 挂载RHEL ...

  4. MySQL新特性MTS

    一.MTS:多线程复制 MTS简介 在MySQL 5.6版本之前,Slave服务器上有两个线程I/O线程和SQL Thread线程.I/O线程负责接收二进制日志(Binary Log,更准确的说是二进 ...

  5. 9、链表 & 状态机 & 多线程

    链表的引入 从数组的缺陷说起 数组有2个缺陷:一个是数组中所有元素的类型必须一致:第二个是数组的元素个数必须事先制定并且一旦指定之后不能更改. 如何解决数组的2个缺陷:数组的第一个缺陷靠结构体去解决. ...

  6. Xamarin Android 应用程序内图标上数字提示

    最近在用 Xamarin 做一个 Android 应用,打开应用时,如果有新消息,需要在应用内的 Toolbar 或者首页的图标上显示数字提示.在这里和大家分享一下实现方法,如果你有更新好的实现方法, ...

  7. C# 开发windows服务的一些心得

    最近在做一个windows服务的项目,发现并解决了一些问题,拿出来和大家分享一下,以下windows服务简称“服务” 文章会在适合时间更新,因为朋友们在不断提出新的意见或思路,感谢-.- 1.服务如何 ...

  8. When it comes to intrusion analysis and forensics

    以下内容的出现可以追溯到一个发生在互联网的安全事件: Z公司遭受某种攻击,服务器上被植入了Linux DDOS木马,部分系统命令入ls遭替换,攻击者已经获得该服务器root权限: 影响更恶劣的是,连接 ...

  9. Redis初识、设计思想与一些学习资源推荐

    一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...

随机推荐

  1. 微软必应Bing搜索引擎这几天无法访问!

    一.用必应(Bing)临时域名: www2.bing.com 或者 www4.bing.com 临时域名博主验证有效 二.修改hosts文件: 用户只需要暂时修改下host然后坐等微软服务器恢复后再删 ...

  2. 20175126《Java程序设计》第六周学习总结

    # 20175126 2016-2017-2 <Java程序设计>第五周学习总结 ## 教材学习内容总结 - 本周学习方式主要为手动敲代码并理解内容学习. - 学习内容为教材第七章第十章, ...

  3. [转] spring framework体系结构及内部各模块jar之间的maven依赖关系

    很多人都在用spring开发java项目,但是配置maven依赖的时候并不能明确要配置哪些spring的jar,经常是胡乱添加一堆,编译或运行报错就继续配置jar依赖,导致spring依赖混乱,甚至下 ...

  4. Openssl asn1parse命令

    一.简介 asn1parse命令是一种用来诊断ASN.1结构的工具,也能用于从ASN1.1数据中提取数据 二.语法 openssl asn1parse [-inform PEM|DER] [-in f ...

  5. 关于java工程打exe包的一些问题

    这两天在把一个Java project打包成exe文件时碰到了一些问题,现在把这些问题和解决办法记下来. 1.用java swing做前端时,背景图片无法显示 Solution:把jpg图片换成png ...

  6. wsl

    1.win10设置为开发人员模式,并安装subsystem for linux(命令行输入bash就可以安装) 2.登录并su到root,然后修改/etc/sudoers,在最后一行加(一定要在最后一 ...

  7. pip install rrdtool

    fatal error: rrd.h: No such file or directory apt-get install librrd-dev

  8. OO前三次作业分析

    一,第一次作业分析 度量分析: 第一次的oo作业按照常理来说是不应该有这么多的圈复杂度,但是由于第一次写的时候,完全不了解java的相关知识,按照c语言的方式来写,完全的根据指导书的逻辑,先写好了正确 ...

  9. sql语句性能优化

    需要的准备知识 1最左前缀匹配 mysql会一直向右匹配直到遇到范围查询(>.<.between.like)就停止匹配, 对于where条件 a = 1 and b> 2 and c ...

  10. 20175316 盛茂淞 Arrays和String单元测试

    Arrays和String单元测试 具体描述: 在IDEA中以TDD的方式对String类和Arrays类进行学习 测试相关方法的正常,错误和边界情况 String类 charAt split Arr ...