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

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

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

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

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

using System;
using System.Collections;
using System.Collections.Generic; namespace StateChart
{
public enum EResult
{
None,
Forward,
Resume,
Defered,
} public enum EHistory
{
Shallow,
Deep,
} public abstract class IEvent { public Type type { get { return GetType(); } } } public delegate void Reaction<T>(T fsm);
public delegate EResult Reaction<U, T>(U fsm, T evt);
interface IReaction {
EResult Execute<FSM, EVENT>(FSM fsm_, EVENT evt);
}
public class CReaction<FSM, EVENT> : IReaction {
Reaction<FSM, EVENT> reaction;
public CReaction(Reaction<FSM, EVENT> reaction_) { reaction = reaction_; }
public EResult Execute<F, E>(F fsm_, E evt)
{ return reaction((FSM)(object)fsm_, (EVENT)(object)evt); }
} public abstract class IState<FSM> where FSM : IStateMachine<FSM>
{
public Type type { get { return GetType(); } }
public EHistory History { get; set; }
public Reaction<FSM> Entry { get; set; }
public Reaction<FSM> Exit { get; set; } //could calc on runtime, but we need more fast spped this time.
public int Depth { get; set; }
public IState<FSM> OuterState { get; set; }
public IState<FSM> ActiveState { get; set; } Dictionary<Type, IReaction> reactions = new Dictionary<Type, IReaction>();
Dictionary<Type, Type> transitions = new Dictionary<Type, Type>();
List<IState<FSM>> subStates = new List<IState<FSM>>(); IState<FSM> initState = null;
public IState<FSM> InitState
{
get
{
if (initState == null)
if (subStates.Count > )
initState = subStates[];
return initState;
}
set { initState = value; }
} public IState(IState<FSM> ostate)
{
History = EHistory.Shallow;
OuterState = ostate;
if (OuterState != null) OuterState.AddSubState(this);
} public IState(IState<FSM> ostate, EHistory history_)
{
OuterState = ostate;
History = history_;
if (OuterState != null) OuterState.AddSubState(this);
} public void DoEntry(FSM fsm_)
{
//UnityEngine.Debug.Log("Entry: " + type.ToString());
Console.WriteLine("Entry: " + type.ToString());
if (Entry != null) Entry(fsm_);
else OnEntry(fsm_);
}
public void DoExit(FSM fsm_)
{
//UnityEngine.Debug.Log("Exit : " + type.ToString());
Console.WriteLine("Exit : " + type.ToString());
if (Exit != null) Exit(fsm_);
else OnExit(fsm_);
} protected virtual void OnEntry(FSM fsm_) { }
protected virtual void OnExit(FSM fsm_) { } public EResult Process<EVENT>(FSM fsm_, EVENT evt) where EVENT : IEvent
{
IReaction reaction = null;
bool hasit = reactions.TryGetValue(evt.type, out reaction);
if (!hasit) return EResult.Forward;
return reaction.Execute<FSM, EVENT>(fsm_, evt);
} public void Bind<EVENT>(Reaction<FSM, EVENT> reaction) where EVENT : IEvent
{
if (transitions.ContainsKey(typeof(EVENT)))
throw new System.InvalidOperationException();
IReaction ireaction = new CReaction<FSM, EVENT>(reaction);
reactions.Add(typeof(EVENT), ireaction);
} public void Bind<EVENT, TSTATE>()
where EVENT : IEvent
where TSTATE : IState<FSM>
{
if (reactions.ContainsKey(typeof(EVENT)))
throw new System.InvalidOperationException();
transitions.Add(typeof(EVENT), typeof(TSTATE));
} public void AddSubState(IState<FSM> sstate)
{
IState<FSM> state = subStates.Find((x) => x.type == sstate.type);
if (state != null) return;
subStates.Add(sstate);
} public IEnumerable<IState<FSM>> IterateSubState()
{
foreach (IState<FSM> state in subStates)
yield return state;
}
}
}
using System;
using System.Collections;
using System.Collections.Generic; namespace StateChart
{ public abstract class IStateMachine<HOST> where HOST : IStateMachine<HOST>
{
Dictionary<Type, IState<HOST>> typeStates = new Dictionary<Type, IState<HOST>>();
List<IState<HOST>> activeStates = new List<IState<HOST>>();
Queue<IEvent> eventQueue = new Queue<IEvent>();
IState<HOST> outestState = null;
bool bSuspend = false; public IStateMachine() { } public void Init(IState<HOST> state)
{
IState<HOST> pstate = state; //add outer states
while (pstate.OuterState != null) {
pstate.OuterState.ActiveState = pstate;
activeStates.Add(pstate);
pstate = pstate.OuterState;
}
activeStates.Add(pstate);
outestState = pstate; //build global type-to-state table
BuildStateTable(outestState, ); //add init sub states
pstate = state;
while (pstate.InitState != null) {
pstate.ActiveState = pstate.InitState;
pstate = state.InitState;
if(pstate != null) activeStates.Add(pstate);
} activeStates.Sort((x, y) => x.Depth - y.Depth);
foreach (IState<HOST> astate in activeStates) {
astate.DoEntry((HOST)this);
}
} void BuildStateTable(IState<HOST> state, int depth_)
{
if (state == null) return;
state.Depth = depth_;
typeStates.Add(state.type, state);
foreach (IState<HOST> sstate in state.IterateSubState()) {
BuildStateTable(sstate, depth_ + );
}
} EResult Transit(IState<HOST> state)
{
IState<HOST> lstate = null; lstate = outestState;
while (lstate.ActiveState != null) { // we could save it if state tree is too high.
lstate = lstate.ActiveState;
} IState<HOST> rstate = state;
if (state.History == EHistory.Shallow)
while (rstate.InitState != null)
rstate = state.InitState;
else
while (rstate.ActiveState != null)
rstate = rstate.ActiveState; IState<HOST> ltail = lstate; //save tail of active states
IState<HOST> rtail = rstate; //save tail of init states int dis = lstate.Depth - rstate.Depth;
if (dis > )
{ IState<HOST> tstate = lstate; lstate = rstate; rstate = tstate; } //rstate will be deepest state dis = Math.Abs(dis);
for (int i = ; i < dis; i++) {
rstate = rstate.OuterState;
}
if (rstate == lstate) //is family
return EResult.None;
do
{ //find nearest outer state
rstate = rstate.OuterState;
lstate = lstate.OuterState;
} while (lstate != rstate); do // call exit chain
{
ltail.DoExit((HOST)this);
ltail = ltail.OuterState;
} while (ltail != lstate); //add tail chain active states
activeStates.RemoveRange(rstate.Depth + , activeStates.Count - rstate.Depth - );
do
{
activeStates.Add(rtail);
lstate = rtail;
rtail = rtail.OuterState;
rtail.ActiveState = lstate;
} while (rtail != rstate); // do entry chain
while (rstate.ActiveState != null)
{
rstate = rstate.ActiveState;
rstate.DoEntry((HOST)this);
} activeStates.Sort((x, y) => x.Depth - y.Depth);
return EResult.None;
} public EResult Transit(Type stateType)
{
IState<HOST> state = null;
if (!typeStates.TryGetValue(stateType, out state))
return EResult.None;
return Transit(state);
} public EResult Transit<TSTATE>()
{ return Transit(typeof(TSTATE)); } public void Process<EVENT>(EVENT evt) where EVENT : IEvent
{
if (bSuspend) return; eventQueue.Enqueue(evt);
int eventCount = eventQueue.Count;
while (eventCount > ){
eventCount--;
IEvent pevent = eventQueue.Dequeue();
foreach (IState<HOST> state in activeStates)
if (bSuspend || state.Process((HOST)this, pevent) == EResult.None)
break;
}
} public void PostEvent<EVENT>(EVENT evt) where EVENT : IEvent
{
if (bSuspend) return;
eventQueue.Enqueue(evt);
} public void Suspend()
{ bSuspend = true; }
public void Resume()
{ bSuspend = false; }
}

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. python实现http get请求

    接口请求方式为get请求,如下图抓包查看 Python实现脚本请求接口并以中文打印接口返回的数据 import urllib.parse import urllib.request url = &qu ...

  2. vue去掉#——History模式

    打开index.js文件 加在 Vue.use(Router) export default new Router({ mode: 'history', ] }) 若有不明白请加群号:复制 69518 ...

  3. 配置react, redux, next.js环境

    1. react https://reactjs.org/docs/add-react-to-a-new-app.html npm install -g create-react-app create ...

  4. window.localStorag使用

    H5本地缓存: 删除: window.localStorage.removeItem("parentNode") 写入: window.localStorage.setItem(& ...

  5. HTTP rfc是什么及其工作过程

    概念: HTTP协议描述的是发送方与接收方的通信协议,通过两方的自觉遵守而存在,HTTP是运行于应用层的协议,基于TCP协议而运作.基本上是客户/服务器对答模式,其中也包括在传输过程中的代理,网关,通 ...

  6. Ubuntu安装vsftpd并通过xftp连接

    1.在ubuntu中安装xftp: sudo apt-get update sudo apt-get install vsftpd sudo service vsftpd restart 2.防火墙添 ...

  7. SQL的decode()函数

    decode()函数简介: 主要作用:将查询结果翻译成其他值(即以其他形式表现出来,以下举例说明): 使用方法: Select decode(columnname,值1,翻译值1,值2,翻译值2,.. ...

  8. sql 中取整,四舍五入取整,向下取整,向上取整。

    SELECT round(52.45, 0) AS round4, round(52.54, 0) AS round5, round(52.45, 1) AS round41, round(52.54 ...

  9. leetcode python 030 Substring with Concatenation of All Words

    ## 您将获得一个字符串s,以及一个长度相同单词的列表.## 找到s中substring(s)的所有起始索引,它们只包含所有单词,## eg:s: "barfoothefoobarman&q ...

  10. intelij idea设置成eclipse快捷键

    1.导入jar包文件: https://pan.baidu.com/s/1QSd_CY5X_dUUw74evbckXg  密码: 23rq 2.idea -->settting ---> ...