Unity3d 有限状态机

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

//装换条件
public enum Transition
{
NullTransition=0,
SeePlayer,
LostPlayer
}
public enum StateID
{
    NullStateID=0,
    Patrol,
    Chase
}


//FSMState所有状态的基类
//每个状态单独一个类,
//每个状态要一个StateId(枚举类型),方便让FSMSystem来管理
public abstract class FSMState  {
    protected StateID stateID;
    public StateID ID
    {
        get { return stateID; }
    }
    //每个子类都有一个映射
    //protected方便子类访问
    protected Dictionary<Transition, StateID> map = new Dictionary<Transition, StateID>();

    protected FSMSystem fsm; //这个状态归哪个System管理的
    public FSMState(FSMSystem fsm)
    {
        this.fsm = fsm;
       
    }


    //添加转换条件和状态
    public void AddTransition(Transition trans,StateID id)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition"); return;
        }
        if (id == StateID.NullStateID)
        {
            Debug.LogError("不允许NullStateID"); return;
        }
        if (map.ContainsKey(trans))
        {
            Debug.LogError("添加转换条件的时候,"+trans+"已经存在于map"); return;
        }
        map.Add(trans, id);
    }
    public void DeleteTranition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("不允许NullTransition"); return;
        }
        if (map.ContainsKey(trans)==false)
        {
            Debug.LogError("删除转换条件的时候," + trans + "不存在于map"); return;
        }
        map.Remove(trans);
    }
    //根据转换条件获得触发状态
    public StateID GetOutPutState(Transition trans)
    {
        if (map.ContainsKey(trans))
        {
            return map[trans];
        }
        return StateID.NullStateID;
    }

    public virtual void DoBeforeEntering() { }
    public virtual void DoAfterLeaving() { }
    public abstract void Act(GameObject npc); //必须重写 //  //当前状态应该做的事情
    public abstract void Reason(GameObject npc); //判断转换条件是否满足


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

//FSMSystem管理所有的状态和条件跳转
public class FSMSystem  {

    //存储状态机的所有状态
    Dictionary<StateID, FSMState> states=new Dictionary<StateID, FSMState>();

    private StateID currentStateID;
    private FSMState currentState;

    public void Update(GameObject npc)
    {   //执行当前状态要做的事情
        currentState.Act(npc);
        //判断转换条件
        currentState.Reason(npc);
    }

    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("状态"+s.ID+"已经存在,无法重复添加"); return;
        }
        states.Add(s.ID, s);
    }

    public void DeleteState(StateID id)
    {
        if (id == StateID.NullStateID)
        {
            Debug.LogError("无法删除空状态" ); return;
        }
        if (states.ContainsKey(id) == false)
        {
            Debug.LogError("无法不存在的状态"); return;
        }
        states.Remove(id);
    }

    //执行转换条件
    public void PerformTrasition(Transition trans)
    {
        if (trans == Transition.NullTransition)
        {
            Debug.LogError("无法执行空的转换条件"); return;
        }
      StateID id= currentState.GetOutPutState(trans); //根据转换条件获得对应的状态
        if (id == StateID.NullStateID) //不需要转换
        {
            Debug.LogWarning("当前状态" + currentState + "无法根据转换条件" + trans + "发生转换"); return;
        }
        if (states.ContainsKey(id) == false)
        {
            Debug.LogError("状态机里面不存在状态"+id+"无法进行转换"); return;
        }
        FSMState state = states[id]; //根据id获得要转换状态
        currentState.DoAfterLeaving();//旧的状态进入之前要做什么
        currentState = state;
        currentStateID = id;
        currentState.DoBeforeEntering();//新状态进入之前要作什么
    }

}

用法

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

//巡逻状态
public class PatrolState : FSMState
{
    private List<Transform> path=new List<Transform>();
    private int index = 0;
    private Transform playerTransform;

    //构造函数
    public PatrolState(FSMSystem fsm):base(fsm) 
    {
        stateID = StateID.Patrol;


        Transform pathTransform = GameObject.Find("Path").transform;
        Transform[] childern= pathTransform.GetComponentsInChildren<Transform>();
        foreach (Transform child in childern)
        {
            if (child != pathTransform)
            {
                path.Add(child);
            }
        }

        playerTransform = GameObject.Find("Player").transform;
    }

    //当前状态应该做的事情
    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(path[index].position);
        npc.transform.Translate(Vector3.forward * Time.deltaTime * 3);
        if (Vector3.Distance(npc.transform.position,path[index].position)<1)
        {
            index++;
            index %= path.Count;
        }
    }
    //状态转换
    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(playerTransform.position, npc.transform.position) < 2)
        {
            fsm.PerformTrasition(Transition.SeePlayer);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//追逐状态
public class ChaseState : FSMState
{
    private Transform playerTransform;

    public ChaseState( FSMSystem fsm) : base(fsm)
    {
        stateID = StateID.Chase;

        playerTransform = GameObject.Find("Player").transform;
    }

    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(playerTransform.position);
        npc.transform.Translate(Vector3.forward*2*Time.deltaTime);
    }

    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(playerTransform.position, npc.transform.position) > 6)
        {
            fsm.PerformTrasition(Transition.LostPlayer);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Enemy : MonoBehaviour {

    private FSMSystem fsm;

    void InitFSM()
    {
        fsm = new FSMSystem();
        FSMState patrolState = new PatrolState(fsm);
        fsm.AddState(patrolState);

        FSMState chaseState=new ChaseState(fsm);
        fsm.AddState(chaseState);

        patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);

        chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);
    }

	// Use this for initialization
	void Start () {
        InitFSM();

    }
	
	// Update is called once per frame
	void Update () {
        fsm.Update(this.gameObject);
	}
}

猜你喜欢

转载自blog.csdn.net/m0_37981386/article/details/83692321