c# 状态机实现

时间:2023-01-11 00:00:36

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&num;状态机实现

    目标 采用了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&plus;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. 【20160924】GOCVHelper综述

    GOCVHelper(GreenOpen Computer Version Helper )是我在这几年编写图像处理程序的过程中积累下来的函数库.主要是对Opencv的适当扩展和在实现Mfc程序时候的 ...

  2. css导航条

    #nav ul { display: none; position: absolute; padding-top: 0px;} #nav li:hover ul { display: block;}

  3. queue模块回顾

    queue queue是python中的标准库,俗称队列. 在python中,多个线程之间的数据是共享的,多个线程进行数据交换的时候,不能够保证数据的安全性和一致性,所以当多个线程需要进行数据交换的时 ...

  4. OGG遇到相关问题汇总

    OGG初始化加载数据时遇到的问题 1.target端拒绝source端访问 2016-12-13 14:31:03 INFO OGG-00963 Oracle GoldenGate Manager f ...

  5. dp之二维背包poj2576

    题意:有一群sb要拔河,把这群sb分为两拨,两拨sb数只差不能大于1,输出这两拨人的体重,小的在前面...... 思路:把总人数除2,总重量除2,之后你会发现就是个简单的二维背包,有两个限制..... ...

  6. 47、Python面向对象中的继承有什么特点?

    继承的优点: 1.建造系统中的类,避免重复操作. 2.新类经常是基于已经存在的类,这样就可以提升代码的复用程度. 继承的特点: 1.在继承中基类的构造(__init__()方法)不会被自动调用,它需要 ...

  7. ctrl &plus;z

    #bg 1 [1]+ /root/bin/rsync.sh & 用 jobs 命令查看正在运行的任务: #jobs [1]+ Running /root/bin/rsync.sh & ...

  8. Stars&lpar;树状数组单点更新)

    Astronomers often examine star maps where stars are represented by points on a plane and each star h ...

  9. 如何在在页面中清除一个已知的cookie?

    前些天在写一个项目的时候,使用cookie来存储一些用户数据,在用户登出时需要清理以往的数据,对于一个初学者来说,我需要学习如何清除一个已知的cookie. 首先,引入两个js文件: 1.jquery ...

  10. &lbrack;洛谷P2394&rsqb;yyy loves Chemistry I

    题目大意:给你一个实数x($0<x\leq 1$),要你求x/23的值(保留8位小数). 解题思路:此题用double读的精度是不够的,用long double直接读入也会WA,正确做法是“sc ...