unity状态机

来源:互联网 发布:2016茶叶种类消费数据 编辑:程序博客网 时间:2024/05/29 03:10

http://www.cnblogs.com/unity3/archive/2013/04/05/3000692.html

本文通过一个实例实现了在Unity下的有限状态机(参考了wiki上的教程)。

      有限状态机是一个设备具有有限数量的状态,他可以在任何时间根据输入进行操作,使得一个状态进入另个一个状态。一个状态机在任何瞬间只能处于一种状态。

      具体可以参考  状态设计模式。

      本例是这样一种状态装换。

     游戏人物NPC在空闲时处于巡逻状态,当看见Player在视野内的时候,转入转入追逐Player状态;一旦和Player距离拉大,便返回巡逻状态。

复制代码
using UnityEngine;using System.Collections;using System;using System.Collections.Generic;//无论是NPC还是Player都有很多状态,在状态切换的时候为了使得程序显得清晰明了,采用了状态机制//首先实际状态都是继承自某个状态抽象类的,这个抽象类定义了进入,退出一个状态虚方法//定义了检测环境是否发生状态改变,以及在该状态下执行的动作的抽象方法// 该实例主要涉及到一个NPC在指定的位置进行巡逻,当看到Playeer的时候切换状态进入追逐Player状态public enum Translate    //如果进入一个新的状态,需要一些触发,比如NPC看到了Player,由巡逻状态进入跟踪状态{                            NullTrans,    SeePlayer,    LosePlayer   }public enum StateID     //每个状态都应该有一个ID,作为识别改状态的标志{     NullState,    Chaseingplayer,    FollowPath }public abstract class FMS_State    //定一个抽象类{    private StateID id;            //定一个状态ID作为变量来标识    public StateID ID    {        set { id = value; }        get { return id; }    }    private Dictionary<Translate, StateID> map = new Dictionary<Translate, StateID>();    //在某一状态下,事件引起了触发进入另一个状态// 于是我们定义了一个字典,存储的便是触发的类型,以及对应要进入的状态    public void addDictionary(Translate tr, StateID id1)  //向字典里添加    {        if (tr == Translate.NullTrans)        {            Debug.LogError("Null Trans is not allower to adding into");            return;        }        if (ID == StateID.NullState)        {            Debug.LogError("Null State id not ~~~");            return;        }        if (map.ContainsKey(tr))              //NPC  任何时候都只能出于一种状态,所以一旦定义了一个触发的枚举类型,对应的只能是接下来的一种状态        {            Debug.LogError(id1.ToString() + "is already added to");            return;        }        map.Add(tr, id1);    }    public void deleateDictionary(Translate tr) //删除字典里存储的一个状态    {        if (tr == Translate.NullTrans)        {            Debug.LogError("TransNull is not allowed to delate");            return;        }        if (map.ContainsKey(tr))        {            map.Remove(tr);            return;        }        Debug.LogError(tr.ToString() + "are not exist");    }    public StateID GetOutState(Translate tr)  //由状态的触发枚举类型返回一个对应的状态类型    {        if (map.ContainsKey(tr))        {           // Debug.Log("Translate " + tr + "State" + map[tr]);            return map[tr];                   }        return StateID.NullState;    }    public virtual void DoBeforeEnter() { }    //虚方法    public virtual void DoBeforeMoveing() { }    public abstract void Reason(GameObject player, GameObject NPC); //  抽象方法    public abstract void Act(GameObject player, GameObject NPC);}
复制代码

随后根据这个基类派生出巡逻类,和追逐类。

复制代码
using UnityEngine;using System.Collections;using System;using System.Collections.Generic;public class Follow_State:FMS_State  //派生出一个巡逻的类{    private GameObject[] waypoints;    //在这些位置巡逻    private int currentWayPoint;        public Follow_State(GameObject[] ob)    {          waypoints= ob;            currentWayPoint = 0;          ID = StateID.FollowPath;        //当前状态的ID    }    public override void Reason(GameObject player, GameObject NPC)    //与环境交互,来判断是否需要状态切换    {        RaycastHit hit;        if(Physics.Raycast(NPC.transform.position,NPC.transform.forward,out hit ,15))        {        if(hit.transform.tag=="Player")        {         FMS_Machine_Manage.GetInstance.changeState(Translate.SeePlayer);        }        }    }    public override void Act(GameObject player, GameObject NPC)   //在该状态下改做点什么呢    {        Vector3 vel = NPC.rigidbody.velocity;        Vector3 dir =waypoints[currentWayPoint].transform.position- NPC.transform.position;        if(dir.magnitude<1)        {            currentWayPoint++;           // Debug.Log("currentwappoint " + currentWayPoint);            if(currentWayPoint>=waypoints.Length)            {                currentWayPoint = 0;            }        }        else        {            vel = dir.normalized*10;            NPC.transform.rotation = Quaternion.Lerp(NPC.transform.rotation, Quaternion.LookRotation(dir), Time.deltaTime * 5);            NPC.transform.eulerAngles = new Vector3(0, NPC.transform.localEulerAngles.y, 0);        }        NPC.rigidbody.velocity = vel;    }    public override void DoBeforeMoveing()    {           }    public override void DoBeforeEnter()    {          }}
复制代码
复制代码
using UnityEngine;using System.Collections;using System;using System.Collections.Generic;public class Chaseing_State : FMS_State {   //派生出了一个追逐类    public Chaseing_State()    {        ID = StateID.Chaseingplayer;   //定义  状态ID        }    public override void Reason(GameObject player, GameObject NPC)    {       if(Vector3.Distance(player.transform.position,NPC.transform.position)>=5)       {         FMS_Machine_Manage.GetInstance.changeState(Translate.LosePlayer);       }    }    public override void Act(GameObject player, GameObject NPC)    {        Vector3 vel = NPC.rigidbody.velocity;        Vector3 moveDir = player.transform.position - NPC.transform.position;        NPC.transform.rotation = Quaternion.Lerp(NPC.transform.rotation, Quaternion.LookRotation(moveDir), Time.deltaTime * 5);        NPC.transform.eulerAngles = new Vector3(0, NPC.transform.eulerAngles.y, 0);        vel = moveDir * 3;        NPC.rigidbody.velocity = vel;    }        }
复制代码

通常对状态的管理,我们会建立一个stateMachine来管理。

复制代码
using UnityEngine;using System.Collections;using System;using System.Collections.Generic;//状态管理类,对状态进行管理public class FMS_Machine_Manage:MonoBehaviour{    private List<FMS_State> states;//存储所有状态的的List    private FMS_State currentState;  //当前状态    private StateID currentStateID;//当前状态ID    public FMS_State CurrentState {        set { currentState = value; }        get { return currentState; } }     public StateID CurrentStateID {        set { currentStateID = value; }        get { return currentStateID; } }    public GameObject player;    public GameObject[] path;    public GameObject NPC;    private static  FMS_Machine_Manage instance;    public static  FMS_Machine_Manage GetInstance    {        get         {            if (instance == null)            {               // instance = new FMS_Machine_Manage();                 GameObject n = new GameObject();                n.name = "FMS_Machine_Manage";                 instance = n.AddComponent<FMS_Machine_Manage>() as FMS_Machine_Manage;            }                         return instance;        }    }    public void UpdateFunction()    {                   CurrentState.Reason(player, NPC);            CurrentState.Act(player, NPC);        }          public void Revert()    {             }    void Awake()    {        states = new List<FMS_State>();   //初始化        NPC = GameObject.FindGameObjectWithTag("NPC");              player = GameObject.FindGameObjectWithTag("Player");        path = GameObject.FindGameObjectsWithTag("path");            }    public void MakeFMSMachine()    {        Follow_State follow = new Follow_State(path);        follow.addDictionary(Translate.SeePlayer, StateID.Chaseingplayer);        Chaseing_State chase = new Chaseing_State();        chase.addDictionary(Translate.LosePlayer, StateID.FollowPath);            GetInstance. AddFmsState(follow);       GetInstance. AddFmsState(chase);        }    public void AddFmsState(FMS_State s)//注册所有状态    {        if (s == null)        {            Debug.LogError(" Null reference is not allowed");        }        if (states.Count == 0)        {            states.Add(s);                   //设置默认状态(important);            currentState = s;            currentStateID = s.ID;            return;        }        foreach (FMS_State state in states)        {            if (state == s)            {                Debug.LogError(s.ID.ToString() + "has already been added");                return;            }        }        states.Add(s);    }    public void delateFmsState(StateID id)    {        if (id == StateID.NullState)        {            Debug.LogError("NullStateID is not allowed for a real state");            return;        }        foreach (FMS_State state in states)        {            if (state.ID == id)            {                states.Remove(state);                return;            }        }    }    public void changeState(Translate tr)           //更改状态    {        if (tr == Translate.NullTrans)        {            Debug.LogError("NullTransition is not allowed for a real transition");            return;        }        //if (currentState.GetOutState(tr) == StateID.NullState)        //{        //    Debug.Log("translate" + "          " + tr + "           " + currentState.GetOutState(tr)+"         "+CurrentStateID);        //    Debug.LogError("1234");        //    return;        //}        StateID id = CurrentState.GetOutState(tr);   //当前状态会进入的新的状态        currentStateID = id;    //    Debug.Log("Prives" + Prives.ID);        foreach (FMS_State state in states)          //通过注册的所有状态,进行搜索来获取要进入的状态实例        {            if (currentStateID == state.ID)            {                CurrentState.DoBeforeMoveing();     //退出状态前,留下点什么,比如挥舞下手臂                currentState = state;                CurrentState.DoBeforeEnter();     //进入状态                break;            }        }    }}
复制代码
按 Ctrl+C 复制代码
using UnityEngine;
using System.Collections;
using System;
using System.Collections.Generic;


public class NPC_Control : MonoBehaviour {
    public void Start()
    {

        FMS_Machine_Manage.GetInstance.MakeFMSMachine();
        
    }


    public void FixedUpdate()
     {

         FMS_Machine_Manage.GetInstance.UpdateFunction();

        
     }
 
}
0 0
原创粉丝点击