• AI自主决策——有限状态机


    本文章参考自Unity3D人工智能编程精粹,转载请注明出处。

    有限状态机的FSM图

      有限状态机(FSM)由一组状态(包括一个初始状态)、输入和根据输入及现有状态转换为下一个状态的转换函数组成。

      什么是状态?

        飞翔,行走,攻击,跑步,游泳,这些动词是状态。高兴,伤心,生气这些形容词也是状态,一些名词也能表示状态。状态的关键意义是:不同的状态对应不同的行为。

      关于有限状态机(FSM),需要了解以下几点:

      1. 有限状态机是AI系统中最简单的,同时也是最为有效和最常用的方法。对于游戏中的每个对象,都可以在其生命周期内区分出一些状态。

      2. 当某些条件发生时,状态机从当前状态转换为其他状态。在不同的状态下,游戏对象对外部激励做出不同的反应或执行不同的动作。有限状态机方法让我们可以很容易地把游戏对象的行为划分为小块,这样更容易调试和扩展。

      3. 用户编写的每个程序都是状态机。当没写下一个if语句的时候,就创造出了一段至少拥有两个状态的代码——写的代码越多,程序就可能具有越多的状态。Switch和if语句数量的爆发会让事情很快失去控制,程序会出现奇怪的BUG。

      4. 有限状态机是AI中最容易的部分,但也很容易出错。在设计有限状态机的时候,一定要认真地考虑清楚其中的每个状态和转换部分。

      简易的FSM图

    有限状态机的状态转移矩阵

      状态转移矩阵是简介表明FSM图的转移矩阵,分别有当前状态,输入,输出状态。如上图的状态转移矩阵可以为

    用FSM框架实现通用的有限状态机

      介绍一个通用的FSM框架,可以在unitycommunity.com上找到,地址是http://wiki.unity3d.com/index/php?title=Finite_State_Machine。

      其实仔细想想,这个FSM框架是不是跟Animator动画状态机非常像,对!动画状态机、有限状态机,你没看错。但是我们还是得会写才是王道!

      上面的状态UML图为

      FSM: AdvancedFSM的父类,继承MonoBehaviour,封装了其中的Start,Update,FixedUpdate方法。定义了巡逻数组等。

      AdvanceFSM: 管理所有的状态类,FSM的派生类,负责管理FSMState的派生类,并且随着当前状态和输入,进行状态更新。

      FSMState: 所有状态的基类,状态类中具有添加转换,删除转换的方法,用于管理记录这些转换。在FSMState中有一个字典对象,用来存储 “转换—状态” 对,表明在当前状态(即这个类所代表的状态)下,如果发生某个 “转换” ,FSM将会转移到何种状态。可以通过AddTransition方法和DeleteTransition方法(自己写)添加或删除 “转换—状态” 对。另外这个类中还包括Reason方法和Act方法,Reason用来确定是否需要转换状态。Act方法定义了在本状态角色行为,例如移动,动画等。

      AICotroller: AdvanceFSM的派生类,负责创建有限状态机,通过它来控制角色。

      代码如下:

      FSM.cs

    public class FSM : MonoBehaviour {
    
        /// <summary>
        /// 玩家Transfrom组件
        /// </summary>
        protected Transform playerTransform;
    
        /// <summary>
        /// 下一个目标
        /// </summary>
        protected Vector3 destPos;
    
        /// <summary>
        /// 攻击速率
        /// </summary>
        protected float attackRate;
        /// <summary>
        /// 攻击间隔
        /// </summary>
        protected float elapsedTime;
    
        /// <summary>
        /// 初始化
        /// </summary>
        protected virtual void Init() { }
        /// <summary>
        /// Update
        /// </summary>
        protected virtual void FSMUpdate() { }
        /// <summary>
        /// FixedUpdate
        /// </summary>
        protected virtual void FSMFixedUpdate() { }
    
        void Start()
        {
            Init();
        }
    
        void Update()
        {
            FSMUpdate();
        }
    
        void FixedUpdate()
        {
            FSMFixedUpdate();
        }
    
    }

      

      AdvanceFSM.cs

    public class AdvanceFSM : FSM {
    
        private List<FSMState> fsmStates;
    
        private FSMStateID currentStateID;
        public FSMStateID CurrentStateID { get { return currentStateID; } }
    
        private FSMState currentState;
        public FSMState CurrentState { get { return currentState; } }
    
        public AdvanceFSM()
        {
            fsmStates = new List<FSMState>();
        }
    
        /// <summary>
        /// 添加状态
        /// </summary>
        /// <param name="fsmState"></param>
        public void AddFSMState(FSMState fsmState)
        {
            if (fsmState == null)
            {
                return;
            }
    
            if (fsmStates.Count == 0)
            {
                fsmStates.Add(fsmState);
                currentState = fsmState;
                currentStateID = fsmState.ID;
                return;
            }
    
            foreach (FSMState state in fsmStates)
            {
                if (state.ID == fsmState.ID)
                {
                    return;
                }
            }
            fsmStates.Add(fsmState);
        }
    
        /// <summary>
        /// 删除状态
        /// </summary>
        /// <param name="fsmState"></param>
        public void DelFSMState(FSMStateID fsmState)
        {
            foreach (FSMState state in fsmStates)
            {
                if (state.ID == fsmState)
                {
                    fsmStates.Remove(state);
                    return;
                }
            }
        }
    
        /// <summary>
        /// 转移新状态
        /// </summary>
        /// <param name="transition"></param>
        public void PerformTransition(Transition transition)
        {
            FSMStateID id = currentState.GetOutputState(transition);
    
            currentStateID = id;
    
            foreach (FSMState state in fsmStates)
            {
                if (state.ID == currentStateID)
                {
                    currentState = state;
                    return;
                }
            }
        }
    
    }
    
    public enum Transition
    {
        /// <summary>
        /// 看到玩家
        /// </summary>
        SawPlayer = 0,
        /// <summary>
        /// 接近玩家
        /// </summary>
        ReachPlayer,
        /// <summary>
        /// 玩家离开视线
        /// </summary>
        LostPlayer,
        /// <summary>
        /// 被伤害
        /// </summary>
        Injured,
        /// <summary>
        /// 死亡
        /// </summary>
        NoHealth,
    }
    
    public enum FSMStateID
    {
        /// <summary>
        /// 巡逻状态
        /// </summary>
        Idling = 0,
        /// <summary>
        /// 追逐状态
        /// </summary>
        Chasing,
        /// <summary>
        /// 攻击状态
        /// </summary>
        Attacking,
        /// <summary>
        /// 受伤状态
        /// </summary>
        Injuring,
        /// <summary>
        /// 死亡状态
        /// </summary>
        Dead,
    }

      FSMState.cs

    public abstract class FSMState
    {
        
        /// <summary>
        /// 转换-状态,信息字典
        /// </summary>
        protected Dictionary<Transition, FSMStateID> map = new Dictionary<Transition, FSMStateID>();
    
        /// <summary>
        /// 状态编号ID
        /// </summary>
        protected FSMStateID stateID;
        /// <summary>
        /// ID公开
        /// </summary>
        public FSMStateID ID
        {
            get
            {
                return stateID;
            }
        }
    
        /// <summary>
        /// 目标位置
        /// </summary>
        protected Vector3 destPos;
    
        /// <summary>
        /// 转向速度
        /// </summary>
        protected float rotSpeed;
        /// <summary>
        /// 移动速度
        /// </summary>
        protected float speed;
        /// <summary>
        /// 追逐距离
        /// </summary>
        protected float chaseDistance = 7.0f;
        /// <summary>
        /// 攻击距离
        /// </summary>
        protected float attackDistance = 1.4f;
        /// <summary>
        /// 到达距离
        /// </summary>
        protected float arriveDistance = 1.4f;
    
        /// <summary>
        /// 添加“转换-状态”
        /// </summary>
        /// <param name="transition"></param>
        /// <param name="id"></param>
        public void AddTransition(Transition transition, FSMStateID id)
        {
            if (map.ContainsKey(transition))
            {
                Debug.LogWarning("GG");
            }
    
            map.Add(transition, id);
        }
    
        /// <summary>
        /// 删除“转换-状态”
        /// </summary>
        /// <param name="transition"></param>
        public void DelTransition(Transition transition)
        {
            if (map.ContainsKey(transition))
            {
                map.Remove(transition);
            }
        }
    
        /// <summary>
        /// 获取转换后新状态编号
        /// </summary>
        /// <param name="transition"></param>
        /// <returns></returns>
        public FSMStateID GetOutputState(Transition transition)
        {
            Debug.Log(transition);
            return map[transition];
        }
    
        /// <summary>
        /// 是否需要转换,如何转换
        /// </summary>
        /// <param name="player"></param>
        /// <param name="monster"></param>
        public abstract void Reason(Transform player, Transform monster);
        
        /// <summary>
        /// 角色行为
        /// </summary>
        /// <param name="player"></param>
        /// <param name="monster"></param>
        public abstract void Act(Transform player, Transform monster);
    
    }

      AIController.cs

    public class AIController : AdvanceFSM {
    
        /// <summary>
        /// 角色生命值
        /// </summary>
        private int health;
    
        /// <summary>
        /// 初始化AI角色的FSM,在FSM基类的Start函数中调用。
        /// </summary>
        protected override void Init()
        {
            health = 100;
            Blood.Instance.Change(health);
    
            elapsedTime = 0.0f;
    
            attackRate = 2.0f;
    
            GameObject objPlayer = GameObject.FindGameObjectWithTag("Player");
            playerTransform = objPlayer.transform;
    
            if (!playerTransform)
                print("GG");
    
            ConstructFSM();
        }
    
        /// <summary>
        /// 这个函数在初始化Init方法中调用,为AI角色构造FSM。
        /// </summary>
        private void ConstructFSM()
        {
            IdleState idle = new IdleState();
            idle.AddTransition(Transition.SawPlayer, FSMStateID.Chasing);
            idle.AddTransition(Transition.Injured, FSMStateID.Injuring);
            idle.AddTransition(Transition.NoHealth, FSMStateID.Dead);
    
            ChaseState chase = new ChaseState();
            chase.AddTransition(Transition.LostPlayer, FSMStateID.Idling);
            chase.AddTransition(Transition.ReachPlayer, FSMStateID.Attacking);
            chase.AddTransition(Transition.Injured, FSMStateID.Injuring);
            chase.AddTransition(Transition.NoHealth, FSMStateID.Dead);
    
            AttackState attack = new AttackState();
            attack.AddTransition(Transition.LostPlayer, FSMStateID.Idling);
            attack.AddTransition(Transition.SawPlayer, FSMStateID.Chasing);
            attack.AddTransition(Transition.Injured, FSMStateID.Injuring);
            attack.AddTransition(Transition.NoHealth, FSMStateID.Dead);
    
            InjuryState injury = new InjuryState();
            injury.AddTransition(Transition.LostPlayer, FSMStateID.Idling);
            injury.AddTransition(Transition.SawPlayer, FSMStateID.Chasing);
            injury.AddTransition(Transition.NoHealth, FSMStateID.Dead);
    
            DeadState dead = new DeadState();
            dead.AddTransition(Transition.NoHealth, FSMStateID.Dead);
    
            AddFSMState(idle);
            AddFSMState(chase);
            AddFSMState(attack);
            AddFSMState(injury);
            AddFSMState(dead);
        }
    
        protected override void FSMUpdate()
        {
            elapsedTime += Time.deltaTime;
        }
    
        protected override void FSMFixedUpdate()
        {
            CurrentState.Act(playerTransform, transform);
            CurrentState.Reason(playerTransform, transform);
    
        }
    
        /// <summary>
        /// 这个方法在每个状态类的Reason中被调用。
        /// </summary>
        /// <param name="t"></param>
        public void SetTransition(Transition t)
        {
            PerformTransition(t);
        }
    
        /// <summary>
        /// AI角色与其他物体碰撞时,调用这个函数。
        /// </summary>
        /// <param name="collider"></param>
        void OnTriggerEnter(Collider collider)
        {
            if (collider.gameObject.tag.Equals("Player"))
            {
                health -= 40;
                Blood.Instance.Change(health);
    
                if (health <= 0)
                {
                    SetTransition(Transition.NoHealth);
                }
                else
                {
                    SetTransition(Transition.Injured);
                }
            }
        }
    
        public void Attack(Animator anim)
        {
            if (elapsedTime >= attackRate)
            {
                anim.SetTrigger("Surround Attack");
                elapsedTime = 0f;
            }
        }
    
        public void Injury(Animator anim)
        {
            anim.SetTrigger("Take Damage");
        }
    }

      IdleState.cs(没有做随机移动,用站立表示默认状态)

    public class IdleState : FSMState
    {
        /// <summary>
        /// 初始化状态
        /// </summary>
        public IdleState()
        {
            stateID = FSMStateID.Idling;
            rotSpeed = 6.0f;
            speed = 10.0f;
        }
    
        /// <summary>
        /// 播放动画
        /// </summary>
        /// <param name="player"></param>
        /// <param name="monster"></param>
        public override void Act(Transform player, Transform monster)
        {
            Animator anim = monster.GetComponent<Animator>();
        }
    
        /// <summary>
        /// 是否进行状态转移
        /// </summary>
        /// <param name="player"></param>
        /// <param name="monster"></param>
        public override void Reason(Transform player, Transform monster)
        {
            //如果玩家与怪物距离小于等于追逐距离,那么转移状态为追逐
            if (Vector3.Distance(player.position,monster.position) <= chaseDistance)
            {
                monster.GetComponent<AIController>().SetTransition(Transition.SawPlayer);
            }
        }
    }

      

      

  • 相关阅读:
    搭建zabbix监控
    liunx 下ctrl+D问题解决方案
    linux配置双线策略
    Discuz! X2.5读写分离
    慢谈MYSQL常用SQL语句
    CentOS 6.5系统安装配置LAMP(Apache+PHP5+MySQL)服务器环境
    自动抓包shell脚本
    zabbix实施部署原理架构
    ftp搭建教程
    DNS搭建教程
  • 原文地址:https://www.cnblogs.com/SHOR/p/6622557.html
Copyright © 2020-2023  润新知