Unity有限状态机实现
更新:HHH   时间:2023-1-7


 有限状态机主要是用于状态之间的切换,状态之间的切换也可以通过Switch Case或者if else实现。由于使用二者实现主要是对用用户扩展不是很方便,所以就有了有限状态机的概念。 有限状态机主要是用于不同的状态频繁的切换。那在Unity中我们如何定义有限状态机?其实有限状态机主要包括三部分,切换状态,进入状态,退出状态。接下来我们就利用Unity实现有限状态机并给大家展示如何应用。

首先我们定义FSMState.cs脚本,我们通过委托对函数状态进行切换.代码如下:

using System;
using System.Collections.Generic;


namespace FSM
{
 public class FSMState
 {
  private int stateName;
  private Dictionary<int, int> transitions = new Dictionary<int, int>();

  //设置状态名字
  public void SetStateName(int newStateName)
  {
   this.stateName = newStateName;
  }

  //获取状态名字
  public int GetStateName()
  {
   return this.stateName;
  }

  //加入状态
  public void AddTransition(int transition, int outputState)
  {
   this.transitions[transition] = outputState;
  }

  //使用状态
  public int ApplyTransition(int transition)
  {
   int result = this.stateName;
   if (this.transitions.ContainsKey(transition))
   {
    result = this.transitions[transition];
   }
   return result;
  }
 }
}

 

以上的类定义的是状态。下面我们定义对外接口,有限状态机FStateMachine.cs脚本

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
namespace FSM
{
 public class FStateMachine
 {

//声明了一个委托用于状态之间的切换
  public delegate void OnStateChangeDelegate(int fromStateName, int toStateName);
  private List<FSMState> states = new List<FSMState>();
  private volatile int currentStateName;
  public FiniteStateMachine.OnStateChangeDelegate onStateChange;
  private object locker = new object();

    //增加状态
  public void AddState(object st)
  {
   int stateName = (int)st;
   FSMState fSMState = new FSMState();
   fSMState.SetStateName(stateName);
   this.states.Add(fSMState);
  }

  //增加所有状态
  public void AddAllStates(Type statesEnumType)
  {
   IEnumerator enumerator = Enum.GetValues(statesEnumType).GetEnumerator();
   try
   {
    while (enumerator.MoveNext())
    {
     object current = enumerator.Current;
     this.AddState(current);
    }
   }
   finally
   {
    IDisposable disposable;
    if ((disposable = (enumerator as IDisposable)) != null)
    {
     disposable.Dispose();
    }
   }
  }

 //该函数是表示从from到to的转换
  public void AddStateTransition(object from, object to, object tr)
  {
   int num = (int)from;
   int outputState = (int)to;
   int transition = (int)tr;
   FSMState fSMState = this.FindStateObjByName(num);
   fSMState.AddTransition(transition, outputState);
  }


  public int ApplyTransition(object tr)
  {
   object obj = this.locker;
   Monitor.Enter(obj);   
   int result;
   try
   {
    int transition = (int)tr;
    int num = this.currentStateName;
    this.currentStateName = this.FindStateObjByName(this.currentStateName).ApplyTransition(transition);
    if (num != this.currentStateName)
    {
     if (this.onStateChange != null)
     {
      this.onStateChange(num, this.currentStateName);
     }
    }
    result = this.currentStateName;
   }
   finally
   {
    Monitor.Exit(obj);
   }
   return result;
  }
  public int GetCurrentState()
  {
   object obj = this.locker;
   Monitor.Enter(obj);
   int result;
   try
   {
    result = this.currentStateName;
   }
   finally
   {
    Monitor.Exit(obj);
   }
   return result;
  }
  public void SetCurrentState(object state)
  {
   int toStateName = (int)state;
   if (this.onStateChange != null)
   {
    this.onStateChange(this.currentStateName, toStateName);
   }
   this.currentStateName = toStateName;
  }
  private FSMState FindStateObjByName(object st)
  {
   int num = (int)st;
   FSMState result;
   foreach (FSMState current in this.states)
   {
    if (num.Equals(current.GetStateName()))
    {
     result = current;
     return result;
    }
   }
   result = null;
   return result;
  }

 }
}
以上定义的是有限状态机类,那接下来我给大家展示如何实现。

我们可以先初始化状态,那如何初始化,看下面的函数:

  private void InitStates()
  {
   this.fsm = new FStateMachine();
   this.fsm.AddAllStates(typeof(TCPSocketLayer.States));
   this.fsm.AddStateTransition(TCPSocketLayer.States.Disconnected, TCPSocketLayer.States.Connecting, TCPSocketLayer.Transitions.StartConnect);
   this.fsm.AddStateTransition(TCPSocketLayer.States.Connecting, TCPSocketLayer.States.Connected, TCPSocketLayer.Transitions.ConnectionSuccess);
   this.fsm.AddStateTransition(TCPSocketLayer.States.Connecting, TCPSocketLayer.States.Disconnected, TCPSocketLayer.Transitions.ConnectionFailure);
   this.fsm.AddStateTransition(TCPSocketLayer.States.Connected, TCPSocketLayer.States.Disconnected, TCPSocketLayer.Transitions.Disconnect);
   this.fsm.SetCurrentState(TCPSocketLayer.States.Disconnected);
  }

 

首先实例化一个有限状态机对象fsm,然后我们做了一个枚举值TCPSocketLayer,然后将其加入状态转换函数AddAllStates,比如AddStateTransition(TCPSocketLayer.States.Disconnected, TCPSocketLayer.States.Connecting, TCPSocketLayer.Transitions.StartConnect);
表示是从Disconnected到Connecting之间的转换。

函数的末尾是设置当前状态为Disconnected。

如果我们关闭连接,我们可以使用Disconnect状态,如下函数所示:

  public void Kill()
  {
   this.fsm.ApplyTransition(TCPSocketLayer.Transitions.Disconnect);
   this.connection.Close();
  }

总结一下:刚开始我们要把所有的状态之间的切换加入到表里,后面我们就可以随意的使用状态了。以上主要是利用网络通信举的事例。

返回开发技术教程...