008 == 有限状态机实例

=====结构=====

1、FSMSystem ---- 状态管理器

        /// 状态的增加
        /// 状态的删除
        /// 状态的修改
        /// 状态的查找

2、FSmStateBase - -- 各种状态的基类

人物的各种状态都继承这个类

public class StateAttack : FSMStateBase

public classStateFollow : FSMStateBase

public class StatePatrol : FSMStateBase

3、最后一个

public class FMSController : MonoBehaviour  ===控制所有的状态切换

===FSMSysytem=====
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace FSM
{
    /// <summary>
    /// 状态管理器
    /// 
    /// 状态的增加
    /// 状态的删除
    /// 状态的修改
    /// 状态的查找
    /// </summary>
    public class FSMSystem
    {
        public FSMSystem()
        {

        }

        private List<FSMStateBase> listState = new List<FSMStateBase>();//存储状态的容器
        private FSMStateBase curState;//当前状态,
        public FSMStateBase CurState { get { return curState; } }
				
        /// <summary>
        /// 添加状态
        /// </summary>
        /// <param name="state"></param>
        public void addState(FSMStateBase state)//基类的引用
        {
            if (state == null)
            {
                return;
            }
            if (listState.Count == 0)//容器中还没有,准备存第一个状态
            {
                listState.Add(state);
                curState = state;
                return;
            }
            if (!listState.Contains(state))//保证没有重复的状态
            {
                listState.Add(state);
            }

        }
        /// <summary>
        /// 删除状态
        /// </summary>
        /// <param name="stateName">状态的名字</param>
        public void deleteState(string stateName)
        {
            if (string.IsNullOrEmpty(stateName))
            {
                return;
            }
            for (int i = 0; i < listState.Count; i++)
            {
                if (listState[i].Name == stateName)
                {
                    listState.Remove(listState[i]);
                    //listState.RemoveAt(i);
                    break;
                }
            }
        }
        /// <summary>
        /// 转换状态
        /// </summary>
        /// <param name="transition">条件</param>
        public void doTransition(ETransition transition)
        {
            if (transition == ETransition.NULL)
            {
                return;
            }
            string newStateName=curState.getOutState(transition);//获取当前状态要装换到的下一个状态名字
            if (string.IsNullOrEmpty(newStateName))
            {
                return;
            }
            //转换状态
            for (int i = 0; i < listState.Count; i++)
            {
                if (newStateName.Equals(listState[i].Name))
                {
                    curState.doBeforeLeaving();//当前状态离开时候要做的事情
                    curState=listState[i];//更换当前状态
                    curState.doBeforeEntering();//进入当前状态做的事情
                    break;
                }
            }
        }
    }
}

=====FSMStateBase=======
using UnityEngine;
using System.Collections;
using System.Collections.Generic;//各种集合,数据结构
namespace FSM
{
    public enum ETransition//状态机中的连线(转换条件)
    {
        NULL,//不需要转换
        PATROL_TO_FOLLOW,//巡逻到跟随
        PATROL_TO_ATTACK,//巡逻到攻击
        FOLLOW_TO_ATTACK,//跟随到攻击
        FOLLOW_TO_PATROL,//跟随到巡逻
        ATTACK_TO_FOLLOW,//攻击到跟随
        ATTACK_PATROL,//攻击到巡逻
    }
    public abstract class FSMStateBase
    {
        protected string name;              //状态的名字

        protected float curRotateSpeed = 20;//角速度
        protected float curSpeed = 10;      //移动速度

        protected FSMSystem fms;            //状态机管理器
        protected Transform transTarget;    //追踪的目标
        protected Transform transSelf;      //自己

        
        public string Name { get { return name; } }

        //转换条件和状态的名字
        protected Dictionary<ETransition, string>  map = new Dictionary<ETransition, string>();
       //==========================================


        /// <summary>
        /// 添加条件
        /// </summary>
        /// <param name="transition"></param>
        /// <param name="stateName"></param>
        public void addTransition(ETransition transition, string stateName)
        {
            if (transition == ETransition.NULL || string.IsNullOrEmpty(stateName))
            {
                return;
            }
            if (!map.ContainsKey(transition))
            {
                map.Add(transition,stateName);
            }
        }

        /// <summary>
        /// 删除条件
        /// </summary>
        /// <param name="transition"></param>
        public void deleteTransition(ETransition transition)
        {
            if (transition == ETransition.NULL)
            {
                return;
            }
            if (map.ContainsKey(transition))
            {
                map.Remove(transition);
            }

        }
        /// <summary>
        /// 旋转当前位置到目标位置
        /// </summary>
        /// <param name="cur"></param>
        /// <param name="aim"></param>
        public void rotateTheTarget(Transform cur, Transform aim)
        {
            //旋转到目标的位置
            Quaternion destRotation;

            Vector3 relativePos;

            Vector3 tmpCur;
            Vector3 tmpAim;

            tmpCur = cur.position;
            tmpAim = aim.position;

            tmpCur.y = 0.0f;
            tmpAim.y = 0.0f;

            relativePos = tmpAim - tmpCur;

            destRotation = Quaternion.LookRotation(relativePos);
            cur.rotation = Quaternion.Slerp(cur.rotation, destRotation, Time.deltaTime * curRotateSpeed);//插值运算
        }
        /// <summary>
        /// 获取新的状态,如果有状态过渡
        /// </summary>
        /// <param name="transition"></param>
        /// <returns></returns>
        public string getOutState(ETransition transition)
        {
            if (map.ContainsKey(transition))
            {
                return map[transition];
            }
            else
            {
                return null;
            }
        }
        //进入之前做的事情
        public virtual void doBeforeEntering() { }
        //离开之前做的事情
        public virtual void doBeforeLeaving() { }
        public abstract void action();//控制行为(循环函数Update,控制物体的移动)
        public abstract void reason();//检测转换(条件检测)

    }
}

======状态控制器====
using UnityEngine;
using System.Collections;
using FSM;
public class FMSController : MonoBehaviour {
    private FSMSystem fms;///FSM系统,用来管理状态
    public Transform[] points;
    public Transform firePoint;
    public Transform fireLight;
	// Use this for initialization
	void Start () {
        //查找巡逻点
        GameObject curGo = GameObject.FindGameObjectWithTag("PointsPatrol");
        int count=curGo.transform.childCount;
        points=new Transform[count];
        int index=0;
        foreach (Transform a in curGo.transform)
        {
            points[index] = a;
            index++;
        }
        //创建有限状态机
        makeFMS();//状态机系统的初始化
	}
	
	// Update is called once per frame
	void Update () {
        if (fms.CurState!=null)
        {
            fms.CurState.action();
            fms.CurState.reason();
            print("fms.CurState.Name=" + fms.CurState.Name);
        }
        
	}
    private void makeFMS()
    {
        fms = new FSMSystem();//状态机管理系统

        StatePatrol statePatrol = new StatePatrol(fms, points,transform);//巡逻状态
        statePatrol.addTransition(ETransition.PATROL_TO_FOLLOW, "follow");
        statePatrol.addTransition(ETransition.PATROL_TO_ATTACK, "attack");



        StateFollow stateFollow = new StateFollow(fms, transform);//跟随状态
        stateFollow.addTransition(ETransition.FOLLOW_TO_ATTACK, "attack");
        stateFollow.addTransition(ETransition.FOLLOW_TO_PATROL, "patrol");

        StateAttack stateAttack = new StateAttack(fms, transform, firePoint, fireLight);//攻击状态
        stateAttack.addTransition(ETransition.ATTACK_TO_FOLLOW, "follow");
        stateAttack.addTransition(ETransition.ATTACK_PATROL, "patrol");

        fms.addState(statePatrol);
        fms.addState(stateFollow);
        fms.addState(stateAttack);

    }
}

===追击状态
using UnityEngine;
using System.Collections;
namespace FSM
{
    /// <summary>
    /// 攻击状态
    /// </summary>
    public class StateAttack : FSMStateBase
    {
        CharacterController characterController;//这个组件专门控制角色移动

        private float lastFire = -1;
        private float frequency = 0.1f;//子弹发射频率
        public GameObject prefabBullet;
        public Transform transFirePoint;//发射点
        public Transform transFireLight;//发射火光
        public Transform[] transBullets;
        public StateAttack(FSMSystem fms, Transform trans, Transform transFirePoint, Transform transFireLight)
        {
            this.fms = fms;
            this.name = "attack";//状态名字就叫攻击
            this.transSelf = trans;
            transTarget = GameObject.FindGameObjectWithTag("Player").transform;
            characterController = transSelf.GetComponent<CharacterController>();
            this.transFirePoint = transFirePoint;
            this.transFireLight = transFireLight;
            prefabBullet = Resources.Load("NewPrefabs/bullet") as GameObject;
            GameObject goBullet=GameObject.Find("Bullets_Monster1");
            if(goBullet!=null)
            {
                int num = goBullet.transform.childCount;
                transBullets=new Transform[num];
                int index=0;
                foreach(Transform t in goBullet.transform)
                {
                    transBullets[index] = t;
                    index++;
                }
            }
            
        }
        public override void action()
        {
            rotateTheTarget(transSelf,transTarget);
            //characterController.Move(transSelf.forward * Time.deltaTime * curSpeed);
            Animation animation = transSelf.GetComponent<Animation>();
            animation.CrossFade("idle");//播放战力开火动画,(老版本动画播放模式)
            
            if (Time.time > lastFire + frequency)
            {
                transFireLight.gameObject.SetActive(true);
                lastFire = Time.time;
                //GameObject curGo = GameObject.Instantiate(prefabBullet, transFirePoint.position, transFirePoint.rotation) as GameObject;//以世界旋转为参考
                Transform curBullet = getBullet();
                if (curBullet == null) return;
                curBullet.gameObject.SetActive(true);
                curBullet.position = transFirePoint.position;
                curBullet.rotation = transFirePoint.rotation;
                RaycastHit hitInfo;
                Bullet b = curBullet.GetComponent<Bullet>();
                if (Physics.Raycast(curBullet.position, curBullet.forward, out hitInfo))
                {
                    if (b)
                    {
                        b.distanceMove = hitInfo.distance;
                    }
                    //施加力,减少生命,播放音乐
                    //Vector3 force = transform.forward * 10;
                    //if (hitInfo.rigidbody)
                    //{
                    //    hitInfo.rigidbody.AddForceAtPosition(force, hitInfo.point, ForceMode.Impulse);
                    //}

                    //if (health)
                    //{
                    //    // Apply damage
                    //    // health.OnDamage(damagePerSecond / frequency, -spawnPoint.forward);
                    //}

                }
                else {
                    if (b)
                    {
                        b.distanceMove = 1000;
                    }
                }
            }
        }

        public override void reason()
        {
            float dis=Vector3.Distance(transSelf.position, transTarget.position);
            if (dis > 3 && dis < 6)//
            {
                fms.doTransition(ETransition.ATTACK_TO_FOLLOW);
            }
            else if(dis>6)
            {
                fms.doTransition(ETransition.ATTACK_PATROL);
            }
        }
        public Transform getBullet()
        {
            for (int i = 0; i < transBullets.Length; i++)
            {
                if (!transBullets[i].gameObject.activeInHierarchy)
                { 
                    return transBullets[i];
                }
            }
            return null;
        }
    }

}

==巡逻状态
using UnityEngine;
using System.Collections;
namespace FSM
{
    /// <summary>
    /// 追踪状态
    /// </summary>
    public class StateFollow : FSMStateBase
    {
        CharacterController characterController;
        public StateFollow(FSMSystem fms, Transform trans)
        {
            this.fms = fms;
            this.name = "follow";
            this.transSelf = trans;
            transTarget = GameObject.FindGameObjectWithTag("Player").transform;
            characterController = transSelf.GetComponent<CharacterController>();
        }
        public override void action()
        {
            Animation animation = transSelf.GetComponent<Animation>();
            animation.CrossFade("run_forward");
            rotateTheTarget(transSelf,transTarget);
            characterController.Move(transSelf.forward * Time.deltaTime * curSpeed);
            //Vector3 moveDirection = transNpc.TransformDirection(Vector3.Cross(Vector3.up, Vector3.left));
            //Vector3 velocity = moveDirection.normalized * curSpeed;
            //if (characterController != null)
            //{
            //    characterController.SimpleMove(velocity);
            //}
            //播放动画
            
        }

        public override void reason()
        {
            float dis = Vector3.Distance(transSelf.position, transTarget.position);
            if (dis > 6)
            {
                fms.doTransition(ETransition.FOLLOW_TO_PATROL);
            }
            else if (dis <= 3)//距离目标3米转到攻击状态
            {
                fms.doTransition(ETransition.FOLLOW_TO_ATTACK);
            }
        }
    }

}

===巡逻状态
using UnityEngine;
using System.Collections;
namespace FSM
{
    /// <summary>
    /// 巡逻状态
    /// </summary>
    public class StatePatrol : FSMStateBase
    {
        private Transform[] points;//巡逻点
        private Transform transRandNextPoint;//要巡逻的点(随机获取)
        CharacterController characterController;//控制器,通过它来移动物体
        public StatePatrol(FSMSystem fms, Transform[] points, Transform trans)
        {
            this.fms = fms;
            this.points = points;
            this.name = "patrol";//当前状态的名字
            this.transSelf = trans;
            this.transTarget = GameObject.FindGameObjectWithTag("Player").transform;
            characterController = transSelf.GetComponent<CharacterController>();
            getNextPoint();
        }
        
        public void getNextPoint()
        {
            if (points != null && points.Length>0)
            {
                Transform nextTrans=null;
                nextTrans = points[Random.Range(0, points.Length)];
                while (transRandNextPoint!=null&&transRandNextPoint.Equals(nextTrans))
                {
                    nextTrans = points[Random.Range(0, points.Length)];
                }
                transRandNextPoint = nextTrans;//更换不一样的巡逻点
                
            }
        }
        /// <summary>
        /// 执行当前状态的行为
        /// </summary>
        public override void action()
        {
            float dis = Vector3.Distance(transSelf.position, transRandNextPoint.position);//计算两个点之间的距离
            if (dis < 1)
            {
                getNextPoint();//选择下一个巡逻点

            }
            //确定方向
            rotateTheTarget(transSelf,transRandNextPoint);
            //移动

            characterController.Move(transSelf.forward * Time.deltaTime * curSpeed);
            //Vector3 moveDirection = transNpc.TransformDirection(Vector3.Cross(Vector3.up, Vector3.left));
            //Vector3 velocity = moveDirection.normalized * curSpeed;
            //if (characterController != null)
            //{
            //    characterController.SimpleMove(velocity);
            //}
            //播放动画
            Animation animation = transSelf.GetComponent<Animation>();
            animation.CrossFade("run_forward");
        }

        public override void reason()
        {
            float dis = Vector3.Distance(transTarget.position, transSelf.position);
            if (dis < 3)//巡逻的时候进入攻击范围
            {
                fms.doTransition(ETransition.PATROL_TO_ATTACK);
            }
            else if (dis > 3 && dis < 6)
            {
                fms.doTransition(ETransition.PATROL_TO_FOLLOW);
            }
        }
    }

}



猜你喜欢

转载自blog.csdn.net/qq_38104858/article/details/80433797
今日推荐