状态机设计模式_有限状态机(finite-state machine)(一)

有限状态机在游戏、AI和编译器程序中广泛应用。本文介绍了有限状态机的基本概念,包括状态、进入动作、退出动作和过渡动作,并通过一个简单的例子说明其工作原理。此外,还提到了层次状态机和下推状态机作为有限状态机的扩展。后续文章将讨论更完整、扩展性更高的FSM实现。
摘要由CSDN通过智能技术生成

有限状态机是我们游戏程序中非常常用的一种设计模式。不止游戏,在AI和编译器程序方面很出名。

什么是有限状态机?

有限状态机是表示有限个状态以及在这些状态之间的过渡和动作等行为的数学计算模型[^1]。(数学计算模型这个词要是觉得难理解,在脑海中换成结构即可。)

有限状态机的元素

a.状态(status)
b.进入动作(entry action):在进入状态时进行
c.退出动作(exit action):在退出状态时进行
d.过渡动作(transition action)在进行特定过渡时进行

a94a63c30c91bde2f4bac35c27501431.png

写一个简单版本的有限状态机的例子

public class FSMMachine<T>
{
  private string fsmName;
  private bool running = false;
  Dictionary<T,StateBehaviour> stateBehaviourDic = new Dictionary<T, StateBehaviour>();
  public T DefaultState{get; set;} = default(T);
  private T currentState;
  public T CurrentState
  {
    get
    {
      return currentState;
    } 
    set
    {
      ChangeStatus(value);
    }
  }

  //构造函数中添加默认状态
  public FSMMachine(string fsmName)
  {
    this.fsmName = fsmName;
  }

  //添加状态
  public void AddStatus(T state,StateBehaviour stateBehaviour)
  {
    stateBehaviourDic[state] = stateBehaviour;
  }

  //移除状态
  public void RemoveStatus(T state)
  {
    if(!stateBehaviourDic.ContainsKey(state))
      return;

    stateBehaviourDic.Remove(state);
  }

  //改变状态
  public void ChangeStatus(T state)
  {
    if(!stateBehaviourDic.ContainsKey(state)||stateBehaviourDic[state] == null)
      throw new InvalidOperationException(string.Format("[FSM {0}] : Can't call 'ChangeStatus' before the stateBehaviour of state has been settled.",fsmName));

    stateBehaviourDic[currentState].OnLeave();
    stateBehaviourDic[state].OnEnter();
    currentState = state;
  }

  public void Run()
  {

    if(!stateBehaviourDic.ContainsKey(DefaultState)||stateBehaviourDic[DefaultState] == null)
      throw new InvalidOperationException(string.Format("[FSM {0}] : Can't call 'ChangeStatus' before the stateBehaviour of state has been settled.",fsmName));

    stateBehaviourDic[DefaultState].OnEnter();
    currentState = DefaultState;
    running = true;
  }

  public void Stop()
  {

    if(!stateBehaviourDic.ContainsKey(currentState)||stateBehaviourDic[currentState] == null)
      throw new InvalidOperationException(string.Format("[FSM {0}] : Can't call 'ChangeStatus' before the stateBehaviour of state has been settled.",fsmName));

    stateBehaviourDic[currentState].OnLeave();
    running = false;
  }
}
public class StateBehaviour 
{
  public virtual void OnEnter()
  {
  }

  public virtual void OnLeave()
  {
  }
}
//例子:
public enum StateExample
{
  LightOffOn,
  LightColorSwitch
}
public class FSMExample : MonoBehaviour 
{
  FSMMachine<StateExample> fSMMachine;
  // Use this for initialization
  void Start () {

    fSMMachine = new FSMMachine<StateExample>("Example");
    fSMMachine.DefaultState =  StateExample.LightOffOn;
    fSMMachine.AddStatus(StateExample.LightOffOn, new LightingSwitchOffState());
    fSMMachine.AddStatus(StateExample.LightColorSwitch, new LightingColorChangeState(Color.red));

    fSMMachine.Run();

    StartCoroutine(ChangeState());
  }

  IEnumerator ChangeState()
  {
    yield return new WaitForSeconds(2f);
    fSMMachine.CurrentState = StateExample.LightColorSwitch;
  }
}
public class LightingColorChangeState : StateBehaviour {

    private Color targetColor;
    private Color oriColor;
    private Light light;
    public LightingColorChangeState(Color TargetColor)
    {
        targetColor = TargetColor;
    }

    public override void OnEnter()
    {
        base.OnEnter();
        light = GameObject.FindObjectOfType<Light>();
        oriColor = light.color;//记录原来的颜色
        light.color = targetColor;
    }

    public override void OnLeave()
    {
        base.OnEnter();
        light.color = targetColor;//恢复颜色
    }
}
public class LightingSwitchOffState : StateBehaviour {

    private Light light;
    public override void OnEnter()
    {
        base.OnEnter();
        light = GameObject.FindObjectOfType<Light>();
        light.enabled = false;
    }

    public override void OnLeave()
    {
        base.OnEnter();
        light.enabled = true;
    }
}

这个简单版本的有限状态机,已经基本完成了。而且可以满足很多状况下的需求了。 但是,对有一定经验的程序员来说,这是远远不够的。因为,例子中的FSM是没有把转换(Transition)这个概念给抽象出来的。 这样,我们的转换方向是任意的,且转换的条件永远是以来一个参数的不同值,这个值就是CurrentState。

状态机除了基础的有限状态机,还有层次状态机和下推状态机。(游戏编程模式这本书里有介绍,有作者自己维护的网页版和中国人翻译的网页版)

下一篇,我们会实现一个更加完整,扩展性更高的FSM。

Potro:有限状态机(finite-state machine)(二)​zhuanlan.zhihu.com

Github仓库网址:https://github.com/PotroChen/FSM-Unity3d

参考:
有限状态机wiki百科
游戏编程模式

[^1]: 数学计算模型:这个词听上去好像学术,会让人感觉很难其实并没有。 简单来讲,数学计算模型是一种用于描述某种结构的具体组织方式的东西。只要这种结构能根据一组输入值,得到输出值。所以,这个听上去很高大上很学术的词,本身就是一个抽象的词用于描述一类东西的,我们不用太在意的。有限状态机是我们游戏程序中非常常用的一种设计模式。不止游戏,在AI和编译器程序方面很出名。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值