欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式学习之路(九) ------ 有限状态机

程序员文章站 2024-03-19 18:31:34
...
  • 理论:http://wiki.unity3d.com/index.php/Finite_State_Machine

设计模式学习之路(九) ------ 有限状态机

实例:

       战士AI,使用有限状态机实现

战士有限战斗机状态虚类,后面的状态都要继承于它:

public enum SoldierTransition //转换的条件
{
    NullTansition = 0,
    SeeEnemy,
    NoEnmey,
    CanAttack
}
public enum SoldierStateID //状态ID,保证唯一
{
    NullState,
    Idle,
    Chase,
    Attack
}
/// <summary>
/// 战士有限战斗机状态虚类,后面的状态都要继承于它
/// </summary>
public abstract class ISoldierState
{
    //条件有多个,而字典只需包含当前状态能够转换的状态对应的条件即可
    protected Dictionary<SoldierTransition, SoldierStateID> mMap = new Dictionary<SoldierTransition, SoldierStateID>();
    protected SoldierStateID mStateID;   //唯一,根据ID寻找状态,实例化状态的时候设置
    protected ICharacter mCharacter;  
    protected SoldierFSMSytem mFSM; //状态管理对象
    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="fsm"></param>
    /// <param name="character"></param>
    public ISoldierState(SoldierFSMSytem fsm,ICharacter character)
    {
        mFSM = fsm;
        mCharacter = character;
    }

    public SoldierStateID stateID { get { return mStateID; } }
    /// <summary>
    /// 添加转换条件
    /// </summary>
    /// <param name="trans"></param>
    /// <param name="id"></param>
    public void AddTransition(SoldierTransition trans, SoldierStateID id)
    {
        if (trans == SoldierTransition.NullTansition)
        {
            Debug.LogError("SoldierState Error: trans不能为空"); return;
        }
        if (id == SoldierStateID.NullState)
        {
            Debug.LogError("SoldierState Error: id状态ID不能为空"); return;
        }
        if (mMap.ContainsKey(trans))
        {
            Debug.LogError("SoldierState Error: " + trans + " 已经添加上了"); return;
        }
        mMap.Add(trans, id);
    }

    /// <summary>
    /// 删除转换条件
    /// </summary>
    /// <param name="trans"></param>
    public void DeleteTransition(SoldierTransition trans)
    {
        if (mMap.ContainsKey(trans) == false)
        {
            Debug.LogError("删除转换条件的时候, 转换条件:[" + trans + "]不存在"); return;
        }
        mMap.Remove(trans);
    }
    //当前字典是否包含转换条件,包含则将ID返回,可以根据这个函数判断条件可以转换成什么状态
    public SoldierStateID GetOutPutState(SoldierTransition trans)
    {
        if (mMap.ContainsKey(trans) == false)
        {
            return SoldierStateID.NullState;
        } else
        {
            return mMap[trans];
        }
    }
    //进入状态之前要做的事情
    public virtual void DoBeforeEntering() { }
    //离开状态之前要做的事情
    public virtual void DoBeforeLeaving() { }

    //Reason Act都是每帧执行
    //判断是否需要转换成其他状态
    public abstract void Reason( List<ICharacter> targets );
    //处理当前状态的操作
    public abstract void Act(List<ICharacter> targets);
}

状态机的拥有者,管理状态:

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
/// <summary>
/// 状态机的拥有者,管理状态
/// </summary>
public class SoldierFSMSytem
{
    //状态列表
    private List<ISoldierState> mStates = new List<ISoldierState>();

    private ISoldierState mCurrentState;
    //当前状态
    public ISoldierState currentState { get { return mCurrentState; } }
    //添加状态,每次创建出一个状态都要给FSMSytem进行管理
    public void AddState(params ISoldierState[] states)
    {
        foreach (ISoldierState s in states)
        {
            AddState(s);
        }
    }
    public void AddState(ISoldierState state)
    {
        if (state == null)
        {
            Debug.LogError("要添加的状态为空"); return;
        }
        if (mStates.Count == 0)
        {
            mStates.Add(state);
            mCurrentState = state;
            return;
        }
        foreach (ISoldierState s in mStates)
        {
            if (s.stateID == state.stateID)
            {
                Debug.LogError("要添加的状态ID[" + s.stateID + "]已经添加"); return;
            }
        }
        mStates.Add(state);
    }
    //删除状态
    public void DeleteState(SoldierStateID stateID)
    {
        if (stateID == SoldierStateID.NullState)
        {
            Debug.LogError("要删除的状态ID为空" + stateID); return;
        }
        foreach (ISoldierState s in mStates)
        {
            if (s.stateID == stateID)
            {
                mStates.Remove(s);
                return;
            }
        }
        Debug.LogError("要删除的StateID不存在集合中:" + stateID);
    }
    //根据转换条件转换状态,state只要调用这个方法将转换条件传过来即可
    public void PerformTransition(SoldierTransition trans)
    {
        if (trans == SoldierTransition.NullTansition)
        {
            Debug.LogError("要执行的转换条件为空 : " + trans); return;
        }
        SoldierStateID nextStateID = mCurrentState.GetOutPutState(trans); //当前状态有没有满足转换条件的状态ID
        if (nextStateID == SoldierStateID.NullState)
        {
            Debug.LogError("在转换条件 [" + trans + "] 下,没有对应的转换状态"); return;
        }
        //遍历状态列表
        foreach (ISoldierState s in mStates)
        {
            if (s.stateID == nextStateID)
            {
                mCurrentState.DoBeforeLeaving(); //执行状态离开的函数
                mCurrentState = s; //设置当前
                mCurrentState.DoBeforeEntering();
                return;
            }
        }
    }
}

追逐状态:

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;

public class SoldierChaseState:ISoldierState
{
    public SoldierChaseState(SoldierFSMSytem fsm, ICharacter c) : base(fsm, c) { mStateID = SoldierStateID.Chase; }
    public override void Reason(List<ICharacter> targets)
    {
        if (targets == null || targets.Count == 0)
        {
            mFSM.PerformTransition(SoldierTransition.NoEnmey); return;
        }
        float distance = Vector3.Distance(targets[0].position, mCharacter.position);
        if (distance <= mCharacter.atkRange)
        {
            mFSM.PerformTransition(SoldierTransition.CanAttack); //转换
        }
    }

    public override void Act(List<ICharacter> targets)
    {
        //当前状态要做的判断操作
        if (targets != null && targets.Count > 0)
        {
            mCharacter.MoveTo(targets[0].position);
        }
    }
}

有限状态机控制类:

//有限状态机控制类
public abstract class ISoldier:ICharacter
{
    protected SoldierFSMSytem mFSMSystem;//有限状态机管理对象

    public ISoldier():base()
    {
        MakeFSM();
    }

    
    //更新状态机
    public override void UpdateFSMAI( List<ICharacter> targets )
    {
        if (mIsKilled) return;
        mFSMSystem.currentState.Reason(targets);
        mFSMSystem.currentState.Act(targets);
    }
    /// <summary>
    /// 制作状态机,在战士初始化的时候被调用
    /// </summary>
    private void MakeFSM()
    {
        mFSMSystem = new SoldierFSMSytem();

        SoldierIdleState idleState = new SoldierIdleState(mFSMSystem, this);
        idleState.AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        SoldierChaseState chaseState = new SoldierChaseState(mFSMSystem, this);
        chaseState.AddTransition(SoldierTransition.NoEnmey, SoldierStateID.Idle);
        chaseState.AddTransition(SoldierTransition.CanAttack, SoldierStateID.Attack);

        SoldierAttackState attackState = new SoldierAttackState(mFSMSystem, this);
        attackState.AddTransition(SoldierTransition.NoEnmey, SoldierStateID.Idle);
        attackState.AddTransition(SoldierTransition.SeeEnemy, SoldierStateID.Chase);

        mFSMSystem.AddState(idleState,chaseState,attackState);
    }
    public override void Update()
    {
        UpdateFSMAI();
    }
}