1、有限状态机的定义
定义:一个有限状态机是一个设备,或是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使得从一个状态变换到另一个状态,或者是促使一个输出或者一种行为的发生。一个有限状态机在任何瞬间只能处在一种状态。
举个例子:
灯的开关是一个非常简单的有限状态机。他有两种状态:开或关。状态之间的变换是通过你手指的输入产生的。向上按开关,产生从关到开的状态变换,向下按开关,产生从开到关的状态变换。
2、有限状态机的实现
方法1、switch/if
以灯的开关为例
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public enum StateType
{
LightOn,
LightOff
}
public class FSMTest : MonoBehaviour
{
private StateType _state;
private bool switchDir;//开关方向 false为向下,true为向上,通过你的输入可以改变这个值
// Start is called before the first frame update
void Start()
{
_state = StateType.LightOff;
switchDir = false;
}
// Update is called once per frame
void Update()
{
UpdateState(_state);
}
void UpdateState(StateType state)
{
switch (state)
{
//关灯状态
case StateType.LightOff:
if (switchDir)
{
state = StateType.LightOn;
//...一些别的操作
}
break;
//开灯状态
case StateType.LightOn:
if (!switchDir)
{
state = StateType.LightOff;
//...一些别的操作
}
break;
}
}
}
上述方法在遇到状态较复杂,或者状态的拓展较频繁时,代码会变得非常难懂,拓展状态也并不灵活
方法2、状态变换表
一个例子:
当前状态 | 条件 | 状态转换 |
---|---|---|
逃跑 | 安全 | 巡逻 |
攻击 | 比敌人弱 | 逃跑 |
巡逻 | 受到威胁并比敌人强 | 攻击 |
巡逻 | 受到威胁并比敌人弱 | 逃跑 |
表中的每个状态可以抽象为一个对象或者是一个函数,这个表会被智能体在规则的时间间隔内询问,这样做的话,状态的结构会更加的条理清晰,增加新的状态模块也会更加方便一些
方法3、内置的规则
例子:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class State
{
public virtual void Execute(Player player)
{
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Runaway : State
{
public override void Execute(Player player)
{
if (player.isSafe)
{
player.ChangeState(new Sleep());
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sleep : State
{
public override void Execute(Player player)
{
if (player.isThreatened)
{
player.ChangeState(new Runaway());
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
private State curState;
public bool isSafe;//判断是否处于安全状态
public bool isThreatened;//判断是否处于受威胁状态
// Update is called once per frame
void Update()
{
if(curState != null)
{
curState.Execute(this);
}
}
public void ChangeState(State newState)
{
curState = newState;
}
}
state作为状态类的一个基类,拥有一个虚函数供子类重写,每当有一个新的状态,就继承state类,并重写Execute方法。player类里面执行的状态完全由curState的值来决定,这样的话,状态本身进行了封装并且在内部给出了影响状态变换的规则。
这个结构被称为状态设计模式,它提供了一种优雅的方式来实现状态驱动行为。它非常容易为每种状态增加进入状态和退出状态的动作,你只需要为每个状态创建Enter和Exit方法并相应的调整智能体的ChangeState方法即可。