综合---有限状态机实例(附带普通状态模式)

来源:互联网 发布:对冲平仓 知乎 编辑:程序博客网 时间:2024/06/05 04:30

1.枚举的切换条件

//有哪些状态切换条件
public enum ETransition
{
    NullTransition =0,
    SawPlayer,//看见主角
    LosePlay//丢失主角
}

2.枚举的所有状态(唯一状态)

//状态id,表示有哪些状态,每一个状态的唯一标志,
public enum EStateID
{
    NullStateID = 0,
    Patrol,//巡逻状态
    Chase//追逐状态
}

3.抽象的状态类State

public abstract class FSMState{
    //状态对应的ID,我们为了方便的获取FSMState
    protected EStateID m_stateID;
    //指定某个状态是由哪个状态机控制的,哪怕是同一类的两个敌人,也有两个状态机
    public FSMSystem m_system;
    public EStateID m_StateID { get{return m_stateID; }}
    protected Dictionary<ETransition, EStateID> m_tranDic;

    protected FSMState()
    {
        m_tranDic = new Dictionary<ETransition, EStateID>();
    }
    //1.添加一个在该状态可以通过某个条件切换到某个状态
    public void _AddTransition(ETransition tran,EStateID id)
    {
        if (tran == ETransition.NullTransition || id == EStateID.NullStateID)
        {
            Debug.LogError("you add a null ERtansition or a null EStateID");
            return;
        }
        if (m_tranDic.ContainsKey(tran))
        {
            Debug.LogError("m_tranDic is alreadey contains the key");
            return;
        }
        m_tranDic.Add(tran, id);
    }
    //2.删除一个在该状态的切换条件
    public void _DeleteTransition(ETransition tran)
    {
        if (m_tranDic.ContainsKey(tran) == false)
        {
            Debug.LogWarning("you want to delete a not exist key" + tran);
            return;
        }
        m_tranDic.Remove(tran);
    }
    //3.通过某个切换条件得到这个条件要切换的状态
    public EStateID _GetStateID(ETransition tran)
    {
        if (m_tranDic.ContainsKey(tran))
        {
            return m_tranDic[tran];
        }
        return EStateID.NullStateID;
    }
    //在某个状态进入之前要做的动作
    public virtual void _OnEnterBefore() { }
    //在某个状态持续中要做的动作
    public abstract void _OnStayUpdate();
    //在某个状态即将推出的时候要做的动作
    public virtual void _OnQuitBefore() { }
}

4.所有的状态管理类:状态机System

public class FSMSystem 
{
    //当前状态机有哪些状态
    private Dictionary<EStateID, FSMState> m_statesDic;
    //状态机处于什么状态
    private FSMState m_currentState;
    public FSMState m_CurrentState   {get{ return m_currentState;} }
    public FSMSystem()
    {
        m_statesDic = new Dictionary<EStateID, FSMState>();
    }
    //1.在一个特定的某个角色的状态机上,标志哪个状态是开始状态
    public void _StartFSM(EStateID startStateID)//即为图中的Register方法,注意的是:只指定开始状态是谁,而不是指定状态机是谁
    {
        FSMState state;
        bool isGet = m_statesDic.TryGetValue(startStateID,out state);
        if (state == null)
        {
            Debug.Log(startStateID + " not exist fsmState");
        }
        else
        {
            m_currentState = state;
            m_currentState._OnEnterBefore();
        }
    }
    //2.给某个角色状态机添加一个状态(该状态的枚举和该状态)
    public void _AddStateID(FSMState state)
    {
        if (state == null)
        {
            Debug.LogError("id is null of nullStateID");
            return;
        }
        if (m_statesDic.ContainsKey(state.m_StateID))
        {
            Debug.Log(state + "the staete is already exist");
        }
        m_statesDic.Add(state.m_StateID, state);
        //设置这个状态的状态机是谁,每个敌人的状态机都是不相同的,这就是初始化的过程
        state.m_system = this;

    }
    public void _DeleteState(FSMState state)
    {
        if (m_statesDic.ContainsKey(state.m_StateID) == false)
        {
            Debug.Log(state + " is not exist");
        }
        else
            m_statesDic.Remove(state.m_StateID);
    }
    //3.在当前状态下给予一个切换条件,如果成立,则切换到另外状态
    public void _PerformTransition(ETransition tran)
    {
        if (tran == ETransition.NullTransition)
        {
            Debug.Log("tran is nullTransiion"); return;
        }
        EStateID id = m_currentState._GetStateID(tran);
        if (id == EStateID.NullStateID)
        {
            Debug.Log("transition is not be happend"); return;
        }
        FSMState state;
        m_statesDic.TryGetValue(id, out state);
        //当前状态退出
        m_CurrentState._OnQuitBefore();
        //切换到一个新状态
        m_currentState = state;
        m_currentState._OnEnterBefore();
    }
}

5.继承了状态类的某个NPC

public class NPCControl : MonoBehaviour {
    private FSMSystem m_fsm;
    public GameObject m_npc;
    public Transform[] m_pathPointTras;
    public Transform m_target;
    void Start()
    {
        _InitFSM();
    }
    void Update()
    {
        //调用当前状态的持续方法
        m_fsm.m_CurrentState._OnStayUpdate();
    }
    void _InitFSM()
    {
        m_fsm = new FSMSystem();


        PatrolState patrolState = new PatrolState(m_pathPointTras,m_npc,m_target);
        patrolState._AddTransition(ETransition.SawPlayer, EStateID.Chase);
        


        ChaseState chaseState = new ChaseState(m_npc,m_target);
        chaseState._AddTransition(ETransition.LosePlay, EStateID.Patrol);


        m_fsm._AddStateID(patrolState);
        m_fsm._AddStateID(chaseState);


        m_fsm._StartFSM(EStateID.Patrol);
    }
}

6.该NPC的行为之一:巡逻

需要在里面设置他所属的的State

做具体的事情以及切换到其他状态

7.该NPC的行为之二:追逐

做具体的事情以及切换到其他状态


附带普通的状态模式

//一个引用状态的类

class Context
{
    IState state;

//指定初始化的状态
    public void _SetState(IState state)
    {
        this.state = state;
    }
    public void _Show(int arg)
    {
        state._Show(arg);
    }
}

//状态类接口
interface IState
{
    void _Show(int arg);
}
class StateA:IState
{
    Context c;

//指定他所属于哪个调用他的类
    public StateA(Context c)
    {
        this.c = c;
    }
    public void _Show(int arg)
    {
        if (arg > 10)
        {
            Debug.Log("开始处理");
        }
        else
        {
            Debug.Log("处理不了,开始转换");

//否则的话切换状态
            c._SetState(new StateB(c));
        }
    }
}
class StateB : IState
{
    Context c;
    public StateB(Context c)
    {
        this.c = c;
    }
    public void _Show(int arg)
    {
        if (arg < 10)
        {
            Debug.Log("开始处理");
        }
        else
        {
            Debug.Log("处理不了,开始转换");
            c._SetState(new StateA(c));
        }
    }
}

//调用在unity里调用

public class StatePattern : MonoBehaviour {
    void Start()
    {
        Context c = new Context();
        c._SetState(new StateA(c));
        c._Show(15);
        c._Show(5);
        c._Show(5);
        c._Show(35);
        c._Show(25);
    }
}

阅读全文
0 0
原创粉丝点击