博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AI自主决策——有限状态机
阅读量:5167 次
发布时间:2019-06-13

本文共 9787 字,大约阅读时间需要 32 分钟。

本文章参考自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 {    ///     /// 玩家Transfrom组件    ///     protected Transform playerTransform;    ///     /// 下一个目标    ///     protected Vector3 destPos;    ///     /// 攻击速率    ///     protected float attackRate;    ///     /// 攻击间隔    ///     protected float elapsedTime;    ///     /// 初始化    ///     protected virtual void Init() { }    ///     /// Update    ///     protected virtual void FSMUpdate() { }    ///     /// FixedUpdate    ///     protected virtual void FSMFixedUpdate() { }    void Start()    {        Init();    }    void Update()    {        FSMUpdate();    }    void FixedUpdate()    {        FSMFixedUpdate();    }}

  

  AdvanceFSM.cs

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

 

  FSMState.cs

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

 

  AIController.cs

public class AIController : AdvanceFSM {    ///     /// 角色生命值    ///     private int health;    ///     /// 初始化AI角色的FSM,在FSM基类的Start函数中调用。    ///     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();    }    ///     /// 这个函数在初始化Init方法中调用,为AI角色构造FSM。    ///     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);    }    ///     /// 这个方法在每个状态类的Reason中被调用。    ///     ///     public void SetTransition(Transition t)    {        PerformTransition(t);    }    ///     /// AI角色与其他物体碰撞时,调用这个函数。    ///     ///     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{    ///     /// 初始化状态    ///     public IdleState()    {        stateID = FSMStateID.Idling;        rotSpeed = 6.0f;        speed = 10.0f;    }    ///     /// 播放动画    ///     ///     ///     public override void Act(Transform player, Transform monster)    {        Animator anim = monster.GetComponent
(); } ///
/// 是否进行状态转移 /// ///
///
public override void Reason(Transform player, Transform monster) { //如果玩家与怪物距离小于等于追逐距离,那么转移状态为追逐 if (Vector3.Distance(player.position,monster.position) <= chaseDistance) { monster.GetComponent
().SetTransition(Transition.SawPlayer); } }}

  

  

 

转载于:https://www.cnblogs.com/SHOR/p/6622557.html

你可能感兴趣的文章
js调用局部打印功能并还原
查看>>
web of knowledge分析文献引用情况(引)
查看>>
matlab写入二进制文件注意事项
查看>>
mac ssh key 的获取 (转)
查看>>
Java 学习 day04
查看>>
Jobdu 1005
查看>>
webapi 给自己挖的坑
查看>>
linux —— ubuntu 初次安装问题
查看>>
传纸条
查看>>
济南清北学堂游记 Day 2.
查看>>
应届毕业生如何打破面试焦虑
查看>>
修改/etc/resolv.conf又恢复到原来的状态
查看>>
redhat6安装git出现的问题
查看>>
Excel 4.0宏躲避杀软检测(转)
查看>>
远程登录 - telnet、mstsc等工具的使用及遇到的问题
查看>>
springmvc的运行原理个人见解
查看>>
[转载]VC6中的文件后缀
查看>>
CUDA memory
查看>>
getnumdevices.c && setgetdevicetype例程
查看>>
《我们不一样》β冲刺_3
查看>>