FSM 和動畫管理器做的AI

FSM控制AI的行爲切換,每次切換都通過委託給動畫控制器發消息,改變AI的行爲與動畫。



代碼:

FSM管理類:

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

/// <summary>
/// 管理類
/// </summary>
public class FSMSystem  {
    public Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();
    
    private StateID currentStateID;
    private FSMState currentState;

    /// <summary>
    /// 遍歷字典  測試是使用
    /// </summary>
    public void Foreach()
    {
        foreach (var item in states)
        {
            Debug.Log("System:"+item.Key + "::" + item.Value);
        }
    }

    public void Update(GameObject obj)
    {
        if (currentState == null)
        {
            Debug.LogError(currentState+"狀態爲空");
            return;
        }
        currentState.Act(obj);
        currentState.Reason(obj);
    }

    /// <summary>
    /// 添加狀態
    /// </summary>
    /// <param name="s">狀態</param>
    public void AddState(FSMState s)
    {
        if(s==null)
        {
            Debug.LogError("FSMState爲空");
            return;
        }
        if (currentState ==null)
        {
            currentState = s;
            currentStateID = s.ID;
        }
        if (states .ContainsKey (s.ID))
        {
            Debug.LogError("該狀態已存在");
            return;
        }
        states.Add(s.ID, s);
    }
    /// <summary>
    /// 狀態刪除
    /// </summary>
    /// <param name="id"></param>
    public void DelegateState(StateID id)
    {
        if(id ==StateID .NullStateID)
        {
            Debug.LogError("無法刪除空狀態");
            return;
        }
        if (states .ContainsKey (id )==false)
        {
            Debug.LogError("無法刪除不存在的狀態");
            return;
        }
        states.Remove(id);
    }
    
    /// <summary>
    /// 狀態轉換
    /// </summary>
    /// <param name="trans"></param>
    public void PerfromTransition(Transition trans)
    {
       if(trans==Transition.NullTransition)
        {
            Debug.LogError("空的轉換條件");
            return;
        }
        StateID id = currentState.GetOutputState(trans);

//        Debug.Log(id);

        if (id == StateID.NullStateID)
        {
            Debug.LogError("無法根據條件轉換");
            return;
        }
        if (states.ContainsKey(id )==false)
        {
            Debug.LogError(id +"::狀態機裏不存在該轉態,無法轉換");
            return;
        }
        FSMState state = states[id];
        currentState.DoAdterLeaving();
        currentState = state;
        currentStateID = id;
        currentState.DoBeforEntering();
    }
}


FSM基類:


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




/// <summary>
/// 狀態基類
/// </summary>
public abstract   class FSMState {
    protected StateID stateID;
    public StateID ID {get{return stateID ;}}
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();

    protected FSMSystem fsm;
    protected  int Id; 
    protected AnimatorStateInfo ani;
    protected   FSMState(FSMSystem fsm ,Transform trans)
    {
        Id = trans.GetInstanceID(); 
        
        //Debug.Log(ani );
        this.fsm = fsm;
        
    }



    /// <summary>
    /// 查錯
    /// </summary>
    public void Foreach()
    {
        foreach (var item in map)
        {
            Debug.Log(item.Key + "::" + item.Value);

        }
    }

    /// <summary>
    /// 添加狀態
    /// </summary>
    /// <param name="trans"></param>
    /// <param name="id"></param>
    public void Addtransition(Transition  trans,StateID id)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允許NullTransition");
            return;
        }
        if (id  == StateID .NullStateID)
        {
            Debug.LogError("不允許Nullstate");
            return;
        }
        if (map .ContainsKey (trans ))
        {            
            Debug.LogError("已存在");
            return;
        }
        map.Add(trans, id);
        
       
    }
    /// <summary>
    /// 刪除狀態
    /// </summary>
    /// <param name="trans"></param>
    public void DeleteTransition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允許NullTransition");
            return;
        }
        
        if (map.ContainsKey(trans)==false )
        {
            Debug.LogError("不存在");
            return;
        }

        map.Remove(trans);
    }

    /// <summary>
    /// 判斷當前狀態
    /// </summary>
    /// <param name="trans"></param>
    /// <returns></returns>
    public StateID GetOutputState(Transition trans)
    {
        if (map.ContainsKey (trans))
        {
            return map[trans];
        }
        return StateID.NullStateID;
    }


    /// <summary>
    /// 進入狀態之前所做的事情
    /// </summary>
    public  virtual void DoBeforEntering() { }
    /// <summary>
    /// 離開狀態的時候
    /// </summary>
    public virtual void DoAdterLeaving() { }

    /// <summary>
    /// 在當前狀態下要做的事情
    /// </summary>
    public abstract void Act(GameObject obj);

    /// <summary>
    /// 判斷轉換條件
    /// </summary>
    public abstract void  Reason(GameObject obj);
}

繼承基類的狀態:

    Idle

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Idel狀態
/// </summary>
public class IdelState : FSMState
{


    private Transform playerTransform;
    public float attackJvLi = 3;

    public IdelState(FSMSystem fsm, Transform trans) : base(fsm, trans)
    {
        stateID = StateID.Idel;
        playerTransform = GameObject.FindGameObjectWithTag(StringText.Player).transform;
    }



    public override void DoBeforEntering()
    {
        SelectState.Instance.OnEvent(Id, stateID);
        
        // Enemy.Instance.Enemy_Idel();
    }

    public override void Act(GameObject obj)
    {
        Quaternion q = Quaternion.LookRotation(playerTransform.position - obj.transform.position);

        obj.transform.rotation = Quaternion.Lerp(obj.transform.rotation, q, Time.deltaTime * 5);
    }

    public override void Reason(GameObject obj)
    {
        if (Vector3.Angle(obj.transform.forward, playerTransform.position - obj.transform.position) < 20)
        {
            fsm.PerfromTransition(Transition.AttackPlayer);
        }
        else if (Vector3.Distance(playerTransform.position, obj.transform.position) > attackJvLi)
        {
            fsm.PerfromTransition(Transition.LostPlayer);
        }

    }
}

動畫管理器:


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

/// <summary>
/// 動畫狀態機管理類
/// </summary>
public class StateMger  {

    // 定義一個鏈表來存放人物的所有狀態
    // 存放人物所能擁有的所有行爲狀態
    private List<StateBase> mStateList = new List<StateBase>();
    // 人物所處的狀態
    public StateBase mCurrentState = null;


    /// <summary>
    /// 添加狀態
    /// </summary>
    /// <param name="state"></param>
    public void AddState(StateBase state)
    {
        if (!mStateList.Contains(state))
        {
            mStateList.Add(state);
            if (mStateList.Count == 1)
            {
                mCurrentState = state;
            }
        }
        
    }
    /// <summary>
    /// 刪除狀態
    /// </summary>
    /// <param name="state"></param>
    public void RemoveState(StateBase state) {
        if (mStateList.Contains(state))
        {
            mStateList.Remove(state);
        }
    }


    /// <summary>
    /// 更換狀態
    /// </summary>
    /// <param name="state"></param>
    public void ChangeState(Type state )
    {
        foreach(StateBase s in mStateList)
        {
            if (s.GetType() == state)
            {
                if (mCurrentState != null)
                {
                    mCurrentState.OnExit();
                }
                mCurrentState = s;
                mCurrentState.OnEnter();

                break;
            }
        }
    }

    //public void Update()
    //{
    //    mCurrentState.OnUpdate(); 
    //}
}

動畫基類:

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

/// <summary>
/// 狀態機基類
/// </summary>
public abstract class StateBase  {

    // 表示每個狀態所影響的那個對象
    public Transform transform = null;

    public StateBase(Transform transform)
    {
        this.transform = transform;
    }

    public abstract void OnEnter();
    public abstract void OnUpdate();
    public abstract void OnExit();

    public static implicit operator StateBase(Type v)
    {
        throw new NotImplementedException();
    }
}

繼承動畫基類:

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

public class Enemy_Idle : StateBase {

    public Enemy_Idle(Transform transform) : base(transform)
    {

    }

    #region
    public override void OnEnter()
    {
        this.transform.GetComponent<Animator>().SetBool(StringText.Idle, true);
    }
    public override void OnUpdate()
    {
       
    }
    public override void OnExit()
    {
        this.transform.GetComponent<Animator>().SetBool(StringText.Idle, false);
    }
    #endregion

}

連接兩個管理器的單例:

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

public class SelectState
{

    #region 單例  

    private static SelectState instance;

    public static SelectState Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new SelectState();
            }

            return instance;
        }
    }
    SelectState() { }

    #endregion

    //委託字典  
    Dictionary<int, Enemy> dic = new Dictionary<int, Enemy>();


    public void AddInt(int n, Enemy e)
    {
        //if(!dic .ContainsKey(n))
        //{
        dic.Add(n, e);
        //}
    }


    /// <summary>  
    /// 調用 
    /// </summary>  
    /// <param name="protoID"></param>  
    /// <param name="handler"></param>  
    public void OnEvent(int protoID, StateID state)
    {
        if (dic.ContainsKey(protoID))
        {
            switch (state)
            {
                case StateID.Attack:
                    dic[protoID].Enemy_Attack();

                    break;
                case StateID.Death:
                    dic[protoID].Enemy_Deate();

                    break;
                case StateID.Idel:
                    dic[protoID].Enemy_Idel();

                    break;
                case StateID.Patorl:
                    dic[protoID].Enemy_Walk();

                    break;
                case StateID.Chase:
                    dic[protoID].Enemy_Run();
                    break;
            }

        }
    }


    public void OnEvent(int protoID, Transition x)
    {
        if (dic.ContainsKey(protoID))
        {

            dic[protoID].fsm.PerfromTransition(x);
        }
    }
}


初始化兩個管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SelectState
{

    #region 單例  

    private static SelectState instance;

    public static SelectState Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new SelectState();
            }

            return instance;
        }
    }
    SelectState() { }

    #endregion

    //委託字典  
    Dictionary<int, Enemy> dic = new Dictionary<int, Enemy>();


    public void AddInt(int n, Enemy e)
    {
        //if(!dic .ContainsKey(n))
        //{
        dic.Add(n, e);
        //}
    }


    /// <summary>  
    /// 調用 
    /// </summary>  
    /// <param name="protoID"></param>  
    /// <param name="handler"></param>  
    public void OnEvent(int protoID, StateID state)
    {
        if (dic.ContainsKey(protoID))
        {
            switch (state)
            {
                case StateID.Attack:
                    dic[protoID].Enemy_Attack();

                    break;
                case StateID.Death:
                    dic[protoID].Enemy_Deate();

                    break;
                case StateID.Idel:
                    dic[protoID].Enemy_Idel();

                    break;
                case StateID.Patorl:
                    dic[protoID].Enemy_Walk();

                    break;
                case StateID.Chase:
                    dic[protoID].Enemy_Run();
                    break;
            }

        }
    }


    public void OnEvent(int protoID, Transition x)
    {
        if (dic.ContainsKey(protoID))
        {

            dic[protoID].fsm.PerfromTransition(x);
        }
    }
}


-------------------------------

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

public class AI_AnimationInit : MonoBehaviour
{

    public StateMger m_stateMgr;

    /// <summary> 
    /// 初始化動畫狀態機
    /// </summary>
    private void Start()
    {
        this.GetComponent<Enemy>().Enemy_Walk = OnJoystickDragAction;
        this.GetComponent<Enemy>().Enemy_Run = OnRun;
        this.GetComponent<Enemy>().Enemy_Attack = OnSkillButonClickAction;
        this.GetComponent<Enemy>().Enemy_Deate = Death;
        this.GetComponent<Enemy>(). Enemy_Idel = OnJoysticksUPAction;


        m_stateMgr = new StateMger();
        Enemy_Run run = new Enemy_Run(transform);
        m_stateMgr.AddState(run);
        Enemy_Idle idle = new Enemy_Idle(transform);
        m_stateMgr.AddState(idle);
        Enemy_Walk walk = new Enemy_Walk(transform);
        m_stateMgr.AddState(walk);
        Enemy_Attack attack = new Enemy_Attack(transform);
        m_stateMgr.AddState(attack);
        Enemy_Death death = new Enemy_Death(transform);
        m_stateMgr.AddState(death);



        //默認Idle狀態
        m_stateMgr.ChangeState(typeof(Enemy_Walk));
    }



   



    /// <summary>
    /// 拖拽時
    /// </summary>
    /// <param name="coor"></param>
    private void OnJoystickDragAction()
    {


        //Vector3 dir = new Vector3(coor.x, 0, coor.y);
        //Quaternion q = Quaternion.LookRotation(dir);
        //transform.rotation = Quaternion.Lerp(transform.rotation, q, Time.deltaTime);
        // 人物進入RUN狀態
        m_stateMgr.ChangeState(typeof(Enemy_Walk));
    }

    /// <summary>
    /// 停止移動時
    /// </summary>
    private void OnJoysticksUPAction()
    {

        // 人物進入Idle狀態
        m_stateMgr.ChangeState(typeof(Enemy_Idle));
    }

    /// <summary>
    /// 看見player的時候
    /// </summary>
    private void OnRun()
    {

        m_stateMgr.ChangeState(typeof(Enemy_Run));
    }

    /// <summary>
    /// 釋放技能時
    /// 
    /// </summary>
    /// <param name="arg"></param>
    private void OnSkillButonClickAction()
    {
        m_stateMgr.ChangeState(typeof(Enemy_Attack));
    }

    /// <summary>
    /// 捱打動作
    /// </summary>
    private void OnWound()
    {

    }
    /// <summary>
    /// 死亡
    /// </summary>
    private void Death()
    {
        m_stateMgr.ChangeState(typeof(Enemy_Death));
    }

    /// <summary>
    /// 持續調用OnUpdate狀態
    /// </summary>
    //private void Update()
    //{
    //    m_stateMgr.Update();
    //}
}






發佈了58 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章