c#仿boost statechart的状态机。去年转到unity使用c#,statechart原来的风格蛮爽的,缺点是编译忒慢,在c#则编译根本不是问题。

不一样的地方首先是简单!因为没做一些东西如region。其次是每个状态是持久存在的,不像boost statechart当transit时重建。所以entry,exit自己管一下清理。

重入时不包括双方最近的共同outer state,个人喜好。

这不是一个快速的状态机,在它该用的地方保证很爽就是了。不该用的地方比如字符匹配就不要用了。

最近想实现一下行为树,但重新回顾这个状态机,我发现就AI来说,2者其实并无什么质变。该状态机如果实现动态的树结构,那其实就是另一个变异的行为树了。

  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. namespace StateChart
  6. {
  7. public enum EResult
  8. {
  9. None,
  10. Forward,
  11. Resume,
  12. Defered,
  13. }
  14.  
  15. public enum EHistory
  16. {
  17. Shallow,
  18. Deep,
  19. }
  20.  
  21. public abstract class IEvent { public Type type { get { return GetType(); } } }
  22.  
  23. public delegate void Reaction<T>(T fsm);
  24. public delegate EResult Reaction<U, T>(U fsm, T evt);
  25. interface IReaction {
  26. EResult Execute<FSM, EVENT>(FSM fsm_, EVENT evt);
  27. }
  28. public class CReaction<FSM, EVENT> : IReaction {
  29. Reaction<FSM, EVENT> reaction;
  30. public CReaction(Reaction<FSM, EVENT> reaction_) { reaction = reaction_; }
  31. public EResult Execute<F, E>(F fsm_, E evt)
  32. { return reaction((FSM)(object)fsm_, (EVENT)(object)evt); }
  33. }
  34.  
  35. public abstract class IState<FSM> where FSM : IStateMachine<FSM>
  36. {
  37. public Type type { get { return GetType(); } }
  38. public EHistory History { get; set; }
  39. public Reaction<FSM> Entry { get; set; }
  40. public Reaction<FSM> Exit { get; set; }
  41.  
  42. //could calc on runtime, but we need more fast spped this time.
  43. public int Depth { get; set; }
  44. public IState<FSM> OuterState { get; set; }
  45. public IState<FSM> ActiveState { get; set; }
  46.  
  47. Dictionary<Type, IReaction> reactions = new Dictionary<Type, IReaction>();
  48. Dictionary<Type, Type> transitions = new Dictionary<Type, Type>();
  49. List<IState<FSM>> subStates = new List<IState<FSM>>();
  50.  
  51. IState<FSM> initState = null;
  52. public IState<FSM> InitState
  53. {
  54. get
  55. {
  56. if (initState == null)
  57. if (subStates.Count > )
  58. initState = subStates[];
  59. return initState;
  60. }
  61. set { initState = value; }
  62. }
  63.  
  64. public IState(IState<FSM> ostate)
  65. {
  66. History = EHistory.Shallow;
  67. OuterState = ostate;
  68. if (OuterState != null) OuterState.AddSubState(this);
  69. }
  70.  
  71. public IState(IState<FSM> ostate, EHistory history_)
  72. {
  73. OuterState = ostate;
  74. History = history_;
  75. if (OuterState != null) OuterState.AddSubState(this);
  76. }
  77.  
  78. public void DoEntry(FSM fsm_)
  79. {
  80. //UnityEngine.Debug.Log("Entry: " + type.ToString());
  81. Console.WriteLine("Entry: " + type.ToString());
  82. if (Entry != null) Entry(fsm_);
  83. else OnEntry(fsm_);
  84. }
  85. public void DoExit(FSM fsm_)
  86. {
  87. //UnityEngine.Debug.Log("Exit : " + type.ToString());
  88. Console.WriteLine("Exit : " + type.ToString());
  89. if (Exit != null) Exit(fsm_);
  90. else OnExit(fsm_);
  91. }
  92.  
  93. protected virtual void OnEntry(FSM fsm_) { }
  94. protected virtual void OnExit(FSM fsm_) { }
  95.  
  96. public EResult Process<EVENT>(FSM fsm_, EVENT evt) where EVENT : IEvent
  97. {
  98. IReaction reaction = null;
  99. bool hasit = reactions.TryGetValue(evt.type, out reaction);
  100. if (!hasit) return EResult.Forward;
  101. return reaction.Execute<FSM, EVENT>(fsm_, evt);
  102. }
  103.  
  104. public void Bind<EVENT>(Reaction<FSM, EVENT> reaction) where EVENT : IEvent
  105. {
  106. if (transitions.ContainsKey(typeof(EVENT)))
  107. throw new System.InvalidOperationException();
  108. IReaction ireaction = new CReaction<FSM, EVENT>(reaction);
  109. reactions.Add(typeof(EVENT), ireaction);
  110. }
  111.  
  112. public void Bind<EVENT, TSTATE>()
  113. where EVENT : IEvent
  114. where TSTATE : IState<FSM>
  115. {
  116. if (reactions.ContainsKey(typeof(EVENT)))
  117. throw new System.InvalidOperationException();
  118. transitions.Add(typeof(EVENT), typeof(TSTATE));
  119. }
  120.  
  121. public void AddSubState(IState<FSM> sstate)
  122. {
  123. IState<FSM> state = subStates.Find((x) => x.type == sstate.type);
  124. if (state != null) return;
  125. subStates.Add(sstate);
  126. }
  127.  
  128. public IEnumerable<IState<FSM>> IterateSubState()
  129. {
  130. foreach (IState<FSM> state in subStates)
  131. yield return state;
  132. }
  133. }
  134. }
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. namespace StateChart
  6. {
  7.  
  8. public abstract class IStateMachine<HOST> where HOST : IStateMachine<HOST>
  9. {
  10. Dictionary<Type, IState<HOST>> typeStates = new Dictionary<Type, IState<HOST>>();
  11. List<IState<HOST>> activeStates = new List<IState<HOST>>();
  12. Queue<IEvent> eventQueue = new Queue<IEvent>();
  13. IState<HOST> outestState = null;
  14. bool bSuspend = false;
  15.  
  16. public IStateMachine() { }
  17.  
  18. public void Init(IState<HOST> state)
  19. {
  20. IState<HOST> pstate = state;
  21.  
  22. //add outer states
  23. while (pstate.OuterState != null) {
  24. pstate.OuterState.ActiveState = pstate;
  25. activeStates.Add(pstate);
  26. pstate = pstate.OuterState;
  27. }
  28. activeStates.Add(pstate);
  29. outestState = pstate;
  30.  
  31. //build global type-to-state table
  32. BuildStateTable(outestState, );
  33.  
  34. //add init sub states
  35. pstate = state;
  36. while (pstate.InitState != null) {
  37. pstate.ActiveState = pstate.InitState;
  38. pstate = state.InitState;
  39. if(pstate != null) activeStates.Add(pstate);
  40. }
  41.  
  42. activeStates.Sort((x, y) => x.Depth - y.Depth);
  43. foreach (IState<HOST> astate in activeStates) {
  44. astate.DoEntry((HOST)this);
  45. }
  46. }
  47.  
  48. void BuildStateTable(IState<HOST> state, int depth_)
  49. {
  50. if (state == null) return;
  51. state.Depth = depth_;
  52. typeStates.Add(state.type, state);
  53. foreach (IState<HOST> sstate in state.IterateSubState()) {
  54. BuildStateTable(sstate, depth_ + );
  55. }
  56. }
  57.  
  58. EResult Transit(IState<HOST> state)
  59. {
  60. IState<HOST> lstate = null;
  61.  
  62. lstate = outestState;
  63. while (lstate.ActiveState != null) { // we could save it if state tree is too high.
  64. lstate = lstate.ActiveState;
  65. }
  66.  
  67. IState<HOST> rstate = state;
  68. if (state.History == EHistory.Shallow)
  69. while (rstate.InitState != null)
  70. rstate = state.InitState;
  71. else
  72. while (rstate.ActiveState != null)
  73. rstate = rstate.ActiveState;
  74.  
  75. IState<HOST> ltail = lstate; //save tail of active states
  76. IState<HOST> rtail = rstate; //save tail of init states
  77.  
  78. int dis = lstate.Depth - rstate.Depth;
  79. if (dis > )
  80. { IState<HOST> tstate = lstate; lstate = rstate; rstate = tstate; } //rstate will be deepest state
  81.  
  82. dis = Math.Abs(dis);
  83. for (int i = ; i < dis; i++) {
  84. rstate = rstate.OuterState;
  85. }
  86. if (rstate == lstate) //is family
  87. return EResult.None;
  88. do
  89. { //find nearest outer state
  90. rstate = rstate.OuterState;
  91. lstate = lstate.OuterState;
  92. } while (lstate != rstate);
  93.  
  94. do // call exit chain
  95. {
  96. ltail.DoExit((HOST)this);
  97. ltail = ltail.OuterState;
  98. } while (ltail != lstate);
  99.  
  100. //add tail chain active states
  101. activeStates.RemoveRange(rstate.Depth + , activeStates.Count - rstate.Depth - );
  102. do
  103. {
  104. activeStates.Add(rtail);
  105. lstate = rtail;
  106. rtail = rtail.OuterState;
  107. rtail.ActiveState = lstate;
  108. } while (rtail != rstate);
  109.  
  110. // do entry chain
  111. while (rstate.ActiveState != null)
  112. {
  113. rstate = rstate.ActiveState;
  114. rstate.DoEntry((HOST)this);
  115. }
  116.  
  117. activeStates.Sort((x, y) => x.Depth - y.Depth);
  118. return EResult.None;
  119. }
  120.  
  121. public EResult Transit(Type stateType)
  122. {
  123. IState<HOST> state = null;
  124. if (!typeStates.TryGetValue(stateType, out state))
  125. return EResult.None;
  126. return Transit(state);
  127. }
  128.  
  129. public EResult Transit<TSTATE>()
  130. { return Transit(typeof(TSTATE)); }
  131.  
  132. public void Process<EVENT>(EVENT evt) where EVENT : IEvent
  133. {
  134. if (bSuspend) return;
  135.  
  136. eventQueue.Enqueue(evt);
  137. int eventCount = eventQueue.Count;
  138. while (eventCount > ){
  139. eventCount--;
  140. IEvent pevent = eventQueue.Dequeue();
  141. foreach (IState<HOST> state in activeStates)
  142. if (bSuspend || state.Process((HOST)this, pevent) == EResult.None)
  143. break;
  144. }
  145. }
  146.  
  147. public void PostEvent<EVENT>(EVENT evt) where EVENT : IEvent
  148. {
  149. if (bSuspend) return;
  150. eventQueue.Enqueue(evt);
  151. }
  152.  
  153. public void Suspend()
  154. { bSuspend = true; }
  155. public void Resume()
  156. { bSuspend = false; }
  157. }

c# 状态机实现的更多相关文章

  1. 适合WebApi的简单的C#状态机实现

    目标 采用了Restful WebApi的架构,再把业务逻辑状态转移放到后端就有点违背初衷了.实际上只要后端Api的权限设置的好,把状态转移放到前端也未尝不可.我考虑的结果是,一般如果变更这个状态本身 ...

  2. 趣说游戏AI开发:对状态机的褒扬和批判

    0x00 前言 因为临近年关工作繁忙,已经有一段时间没有更新博客了.到了元旦终于有时间来写点东西,既是积累也是分享.如题目所示,本文要来聊一聊在游戏开发中经常会涉及到的话题--游戏AI.设计游戏AI的 ...

  3. Workflow笔记2——状态机工作流

    状态机工作流 在上一节Workflow笔记1——工作流介绍中,介绍的是流程图工作流,后来微软又推出了状态机工作流,它比流程图功能更加强大. 状态机工作流:就是将工作流系统中的所有的工作节点都可以看做成 ...

  4. Unity Animator动画状态机 深入理解(一)

    接触Unity以来就已经有了Animator,Animation用的少,不过也大概理解他俩之间的一个区别于联系. 图中其实就是Animator和Animation之间的区别于联系了,啊!你肯定会告诉我 ...

  5. FSM(状态机)、HFSM(分层状态机)、BT(行为树)的区别

    游戏人工智能AI中最常听见的就是这三个词拉: FSM 这个不用说拉,百度一大堆解释, 简单将就是将游戏AI行为分为一个一个的状态,状态与状态之间的过渡通过事件的触发来形成. 比如士兵的行为有“巡逻”, ...

  6. JavaScript状态机程序逻辑编辑器

    制作背景 之前做Win8 Metro动态加载内容框架的时候,由于采用了XAML+JavaScript的方法,程序复杂的执行逻辑是由JavaScript控制的,而页面一多,流程一复杂,制作起来就非常麻烦 ...

  7. react+redux教程(二)redux的单一状态树完全替代了react的状态机?

    上篇react+redux教程,我们讲解了官方计数器的代码实现,react+redux教程(一).我们发现我们没有用到react组件本身的state,而是通过props来导入数据和操作的. 我们知道r ...

  8. Game中的状态机

    我相信大多数博友都会玩游戏. 玩游戏,牵涉到状态包含 登陆,正常,死亡,复活,下线, 在上面状态的基础上.同时包含 站立,走动,跑动,不可移动施法状态, 战斗状态, 通常这是三个不同的分组.也就说可以 ...

  9. SharePoint 2013 状态机工作流之扩展自定义状态

    当我们使用SharePoint 2013的状态机工作流时,发现一个非常不爽的事情,就是SharePoint 所有的工作流状态,都是固定的那些,没办法显示我们自定义的状态,后来经过Google发现,原来 ...

  10. SharePoint 2013 状态机工作流之日常报销示例

    简单介绍下状态机工作流,状态机工作流提供了一系列的状态.工作流从初始状态开始,到终止状态结束.两个状态之间定义行为进行过渡.通常情况下,状态机工作流对事件作出反应,事件的发生将会使状态发生改变. 1. ...

随机推荐

  1. 【转】 ISP概述、工作原理及架构

    1.概述 ISP全称Image Signal Processing,即图像信号处理.主要用来对前端图像传感器输出信号处理的单元,以匹配不同厂商的图象传感器. ISP 通过一系列数字图像处理算法完成对数 ...

  2. guxh的python笔记五:面向对象

    1,面向对象编程思想 类:一类具有相同属性的抽象 属性(静态属性):实例变量.类变量.私有属性 方法(动态属性):构造函数.析构函数(默认就有).函数.私有函数 对象/实例:类经过实例化后,就是对象/ ...

  3. 机器学习 之梯度提升树GBDT

    目录 1.基本知识点简介 2.梯度提升树GBDT算法 2.1 思路和原理 2.2 梯度代替残差建立CART回归树 1.基本知识点简介 在集成学习的Boosting提升算法中,有两大家族:第一是AdaB ...

  4. JAVA的原子性和可见性,线程同步的理解

    1.原子性 (1)原子是构成物质的基本单位(当然电子等暂且不论),所以原子的意思代表着——“不可分”: (2)原子性是拒绝多线程操作的,不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它 ...

  5. fedora liveuser 切换root;su -l root

    安装完Fedora 14后,默认没有启用sudo,首先应该是对sudo进行设置.sudo的作用就是使当前非root用户在使用没有权限的命令时,直接在命令前加入sudo,在输入自己当前用户的密码就可以完 ...

  6. 基于vue的实战步骤

    1.脚手架vue-cli安装 npm install -g vue-cli (npm init -f 生成package.json文件) vue init webpack myapp cd myapp ...

  7. 第一章02: 常用的DOS命令

    win+R=命令框 +输入CMD ,进入命令行.或者控制台 DOS命令如下: cd命令 1. CD.. = 返回上级目录 2. cd\ = 直接退到根目录 3.cd (地址)= 直接到指定文件 切盘符 ...

  8. python异常处理机制

    python有五种异常处理机制,分别是 1.默认异常处理器. 如果我们没有对异常进行任何预防,那么程序在执行过程中发生异常就会中断程序,调用python默认的异常处理器,并在终端输出异常信息,如图所示 ...

  9. java数学函数Math类中常用的方法

    Math类提供了常用的一些数学函数,如:三角函数.对数.指数等.一个数学公式如果想用代码表示,则可以将其拆分然后套用Math类下的方法即可. Math.abs(12.3);               ...

  10. Jsの数组练习-求一组数中的最大值和最小值,以及所在位置

    要求:求一组数中的最大值和最小值,以及所在位置 代码实现: <!DOCTYPE html> <html lang="en"> <head> &l ...