首页 > 代码库 > Unity状态机的实现,以《塔防》为例

Unity状态机的实现,以《塔防》为例

什么是有限状态机?

通俗点讲,有限状态机是:将对象的状态(攻击、闲置、晕眩)的实现代码,提取出来,封装成状态。由状态机负责在各个状态之间调度。

对象持有状态管理类(状态机)的引用,与具体的状态解耦。

 

OK,那接下来开始设计一个塔的状态,我们有一个父类FiniteState,状态机只和父类交互,屏蔽了状态具体实现

 

 

塔与状态是一对一的关系,也就是说,在塔创建的时候,全部状态已经生成好了(GenerateStateList方法), 我们根据状态的枚举类进行切换。

using System.Collections.Generic;

/// <summary>
/// 塔的状态机工具类
/// </summary>
public class TowerStateHelper
{
    /// <summary>
    /// 状态个数
    /// </summary>
    private const int STATE_COUNT = 4;

    /// <summary>
    /// 创建状态集合
    /// </summary>
    /// <param name="tower">作用对象</param>
    /// <returns></returns>
    public static Dictionary<StateType, FiniteState> GenerateStateList(TowerBase tower)
    {
        Dictionary<StateType, FiniteState> stateList = new Dictionary<StateType, FiniteState>(STATE_COUNT);

        stateList.Add(StateType.Idle, new StateIdle() { TargetTower = tower, StateTypeId = StateType.Idle });
        stateList.Add(StateType.Guard, new StateGuard() { TargetTower = tower, StateTypeId = StateType.Guard });
        stateList.Add(StateType.Attack, new StateAttack() { TargetTower = tower, StateTypeId = StateType.Attack });
        stateList.Add(StateType.Spell, new StateSpell() { TargetTower = tower, StateTypeId = StateType.Spell });

        return stateList;
    }
}

/// <summary>
/// 状态类型
/// </summary>
public enum StateType
{
    /// <summary>
    /// 不可用
    /// </summary>
    Innit,

    /// <summary>
    /// 闲置
    /// </summary>
    Idle,

    /// <summary>
    /// 攻击
    /// </summary>
    Attack,

    /// <summary>
    /// 警惕
    /// </summary>
    Guard,

    /// <summary>
    /// 吟唱
    /// </summary>
    Spell
}

 

状态机,它的职责是负责在各个状态之间进行调度

using System.Collections.Generic;

/// <summary>
/// 状态机
/// </summary>
public class TowerStateMachine
{
    #region 公共属性

    /// <summary>
    /// 追溯前面的状态
    /// </summary>
    public StateType PreviousStateType
    {
        get; set;
    }

    #endregion

    #region 私有属性
    /// <summary>
    /// 全局状态
    /// </summary>
    private FiniteState _globalState;

    /// <summary>
    /// 当前状态
    /// </summary>
    private FiniteState _currentState;

    /// <summary>
    /// 状态列表
    /// </summary>
    private Dictionary<StateType, FiniteState> _stateList;

    #endregion

    #region 重写事件

    /// <summary>
    /// 初始化方法
    /// </summary>
    /// <param name="globalState">全局状态</param>
    /// <param name="newStateType">当前状态</param>
    public TowerStateMachine(TowerBase tower, FiniteState globalState, StateType newStateType)
    {
        PreviousStateType= StateType.Innit;
        _stateList = TowerStateHelper.GenerateStateList(tower);

        if (null != globalState)
        {
            globalState.OnEnter();
            _globalState = globalState;
        }

        _stateList[newStateType].OnEnter();
        _currentState = _stateList[newStateType];
    }

    #endregion

    #region 公共方法

    /// <summary>
    /// 执行
    /// </summary>
    public void Excute()
    {
        if (null != _globalState)
            _globalState.OnExcute();

        if (null != _currentState)
            _currentState.OnExcute();
    }

    /// <summary>
    /// 改变状态
    /// </summary>
    /// <param name="newStateType"></param>
    public void ChangeStatus(StateType newStateType)
    {
        if (newStateType == _currentState.StateTypeId)
            return;

        PreviousStateType = _currentState.StateTypeId;
        _currentState.OnExit();

        _stateList[newStateType].OnEnter();
        _currentState = _stateList[newStateType];
    }

    #endregion
}

 

状态基类,我们定义了进入、OnExcute(每次update被调用)、退出方法

/// <summary>
/// 状态基类
/// </summary>
public abstract class FiniteState
{
    /// <summary>
    /// 状态机类型
    /// </summary>
    public StateType StateTypeId { get; set; }

    /// <summary>
    /// 塔对象
    /// </summary>
    public TowerBase TargetTower { get; set; }

    /// <summary>
    /// 进入
    /// </summary>
    public abstract void OnEnter();

    /// <summary>
    /// 执行
    /// </summary>
    public abstract void OnExcute();

    /// <summary>
    /// 退出
    /// </summary>
    public abstract void OnExit();
}

 

调用对象

 //声明
 private TowerStateMachine _stateMachine;

//初始化
_stateMachine = new TowerStateMachine(this, null, StateType.Idle);

//在Update方法里调用
  _stateMachine.Excute();

 

状态的切换由具体状态类满足条件自动触发、或者手动触发都可以。