Unity学习之FSM有限状态机

 更新时间:2021年06月25日 12:09:43   作者:念丶小宇  
这篇文章主要介绍了Unity学习之FSM有限状态机,通过详细的代码案例来进行解析说明,希望这篇文章对你有所帮助

前言:一个游戏里的一个人物会存在多种状态,那么就需要有一个专门管理这些状态的类。不然会显得杂乱无章,不易于后面状态的增加或者减少。
思路:既然要方便管理,那么首先肯定得有个系统类(专门用来存放所有的状态、状态的增删等功能);然后就是需要把所有的状态都单独写一个类(已达到修改某个状态的时候,其他状态不会受到影响)。

状态管理类:

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

public class FSMSystem 
{
    private Dictionary<StateID, FSMState> states = new Dictionary<StateID, FSMState>();

    private StateID currentStateID;
    private FSMState currentFSMState;

    public void Update(GameObject npc)
    {
        currentFSMState.Act(npc);
        currentFSMState.Reason(npc);
    }

    /// <summary>
    /// 添加状态
    /// </summary>
    /// <param name="fSMState"></param>
    public void AddState(FSMState fSMState)
    {
        if (fSMState == null) return;

        //if (currentFSMState == null)
        //{
            currentStateID = fSMState.ID;
            currentFSMState = fSMState;
        //}
        if (states.ContainsKey(currentStateID)) return;
        states.Add(currentStateID, currentFSMState);
    }
    /// <summary>
    /// 删除状态
    /// </summary>
    /// <param name="stateID"></param>
    public void DeleteState(StateID stateID)
    {
        if (stateID == StateID.Null) return;
        if (!states.ContainsKey(stateID)) return;

        states.Remove(stateID);
    }
    

    /// <summary>
    /// 执行状态条件转换
    /// </summary>
    /// <param name="transition"></param>
    public void PerformTransition(Transition transition)
    {
        if (transition == Transition.NullTransition) return;

        StateID stateID = currentFSMState.GetStateID(transition);
        if (stateID == StateID.Null) return;
        if (!states.ContainsKey(stateID)) return;

        FSMState fSMState = states[stateID];
        currentFSMState.StateExit();
        currentFSMState = fSMState;
        currentStateID = fSMState.ID;
        currentFSMState.StateEnter();
    }
}

状态基类:

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

public enum Transition
{
    NullTransition,
    SeePlayer,//发现玩家
    LostPlayer,//玩家脱离视野范围
    AttackPlayer,//攻击玩家
}
public enum StateID
{
    Null,
    Chase,//追逐
    Patrol,//巡逻
    Attack,//攻击
}
public abstract class FSMState
{
    protected Transition transition;

    protected StateID stateID;
    protected FSMSystem fSM;
    public StateID ID
    {
        get { return stateID; }
    }

    protected Dictionary<Transition, StateID> dic = new Dictionary<Transition, StateID>();

    public FSMState(FSMSystem fSM)
    {
        this.fSM = fSM;
    }

    /// <summary>
    /// 增加状态
    /// </summary>
    /// <param name="transition"></param>
    /// <param name="stateID"></param>
    public void AddTransition(Transition transition, StateID stateID)
    {
        if (transition == Transition.NullTransition) return;
        if (stateID == StateID.Null) return;
        if (dic.ContainsKey(transition)) return;

        dic.Add(transition, stateID);
    }
    /// <summary>
    /// 删除状态
    /// </summary>
    /// <param name="transition"></param>
    public void DeleteTransition(Transition transition)
    {
        if (transition == Transition.NullTransition) return;
        if (!dic.ContainsKey(transition)) return;

        dic.Remove(transition);
    }
    /// <summary>
    /// 获取状态
    /// </summary>
    /// <param name="transition"></param>
    /// <returns></returns>
    public StateID GetStateID(Transition transition)
    {
        if (transition == Transition.NullTransition) return StateID.Null;
        if (!dic.ContainsKey(transition)) return StateID.Null;
        return dic[transition];
    }

    /// <summary>
    /// 进入状态
    /// </summary>
    public virtual void StateEnter() { }
    /// <summary>
    /// 退出状态
    /// </summary>
    public virtual void StateExit() { }

    /// <summary>
    /// 状态持续中,,,
    /// </summary>
    /// <param name="npc"></param>
    public abstract void Act(GameObject npc);
    /// <summary>
    /// 状态退出前,,,
    /// </summary>
    /// <param name="npc"></param>
    public abstract void Reason(GameObject npc);
}

巡逻状态:

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

/// <summary>
/// 巡逻状态
/// </summary>
public class PatrolState : FSMState
{
    /// <summary>
    /// 巡逻路径点集合
    /// </summary>
    private Transform[] paths;
    /// <summary>
    /// 当前巡逻路径点索引
    /// </summary>
    private int index = 0;
    /// <summary>
    /// 移动速度
    /// </summary>
    private float moveSpeed = 0.5f;
    /// <summary>
    /// 玩家
    /// </summary>
    private Transform player;
    public PatrolState(FSMSystem fSM, Transform player) : base(fSM)
    {
        this.player = player;
        paths = GameObject.Find("Path").GetComponentsInChildren<Transform>();
        stateID = StateID.Patrol;
    }

    public override void Act(GameObject npc)
    {
        npc.transform.LookAt(paths[index].position);
        npc.transform.Translate(Vector3.forward * Time.deltaTime * moveSpeed);
        if (Vector3.Distance(npc.transform.position, paths[index].position) < 1)
        {
            index++;
            index %= paths.Length;
        }
    }

    public override void Reason(GameObject npc)
    {
        npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed );
        if (Vector3.Distance(player.position, npc.transform.position) < 10)
        {
            fSM.PerformTransition(Transition.SeePlayer);
        }
    }
}

追逐状态:

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

/// <summary>
/// 追逐状态
/// </summary>
public class ChaseState : FSMState
{
    /// <summary>
    /// 移动速度
    /// </summary>
    private float moveSpeed = 2f;
    /// <summary>
    /// 玩家
    /// </summary>
    private Transform player;
    public ChaseState(FSMSystem fSM, Transform player) : base(fSM)
    {
        stateID = StateID.Chase;
        this. player = player;
    }

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

    public override void Reason(GameObject npc)
    {
        npc.GetComponent<Animator>().SetFloat("Speed", moveSpeed / 2);
        if (Vector3.Distance(player.position, npc.transform.position) >= 10)
        {
            fSM.PerformTransition(Transition.LostPlayer);
        }
        else if (Vector3.Distance(player.position, npc.transform.position) <= 1f )
        {
            fSM.PerformTransition(Transition.AttackPlayer);
        }
    }
}

攻击状态:

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

/// <summary>
/// 攻击状态
/// </summary>
public class AttackState : FSMState
{
    /// <summary>
    /// 玩家
    /// </summary>
    private Transform player;
    public AttackState(FSMSystem fSM, Transform player) : base(fSM)
    {
        stateID = StateID.Attack;
        this.player = player;
    }
    public override void Act(GameObject npc)
    {

    }

    public override void Reason(GameObject npc)
    {
        if (Vector3.Distance(player.position, npc.transform.position) > 1f)
        {
            if (Vector3.Distance(player.position, npc.transform.position) >= 10)
            {
                fSM.PerformTransition(Transition.LostPlayer);
            }
            else if (Vector3.Distance(player.position, npc.transform.position) < 10)
            {
                fSM.PerformTransition(Transition.SeePlayer);
            }
            return;
        }
        npc.GetComponent<Animator>().SetTrigger("Attack01");
    }
}

状态持有者实现类:

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

public class Enemy : MonoBehaviour
{
    private FSMSystem fSM;
    private Transform player;
    private void Start()
    {
        fSM = new FSMSystem();
        FSMState patrolState = new PatrolState(fSM, player);
        patrolState.AddTransition(Transition.SeePlayer, StateID.Chase);
        patrolState.AddTransition(Transition.AttackPlayer, StateID.Attack);
        //patrolState.AddTransition(Transition.LostPlayer, StateID.Patrol);

        FSMState chaseState = new ChaseState(fSM, player);
        chaseState.AddTransition(Transition.LostPlayer, StateID.Patrol);
        chaseState.AddTransition(Transition.AttackPlayer, StateID.Attack);
        //chaseState.AddTransition(Transition.SeePlayer, StateID.Chase);

        FSMState attackState = new AttackState(fSM, player);
        attackState.AddTransition(Transition.SeePlayer, StateID.Chase);
        attackState.AddTransition(Transition.LostPlayer, StateID.Patrol);
        //attackState.AddTransition(Transition.AttackPlayer, StateID.Attack);

        fSM.AddState(patrolState);
        fSM.AddState(chaseState);
        fSM.AddState(attackState);
    }

    private void Update()
    {
        fSM.Update(gameObject);
    }
}

到此这篇关于Unity学习之FSM有限状态机的文章就介绍到这了,更多相关UnityFSM有限状态机内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#使用linq对数组进行筛选排序的方法

    C#使用linq对数组进行筛选排序的方法

    这篇文章主要介绍了C#使用linq对数组进行筛选排序的方法,实例分析了C#实用linq扩展进行数组排序的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-04-04
  • C#实现简易计算器功能(1)(窗体应用)

    C#实现简易计算器功能(1)(窗体应用)

    这篇文章主要为大家详细介绍了C#实现简易计算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • C#绘制时钟的方法

    C#绘制时钟的方法

    这篇文章主要为大家详细介绍了C#绘制时钟的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • 基于C#的图表控件库 ScottPlot编译visual studio 2022

    基于C#的图表控件库 ScottPlot编译visual studio 2022

    基于 C# 的 图表控件库 ScottPlot,开源免费,可以用于开发一些上位机软件,如电压、电流波形的显示,开发【示波器】图形界面,可以显示一些图表、波形,总之功能比较的强大,本文介绍了基于C#的图表控件库 ScottPlot编译visual studio 2022,需要的朋友可以参考下
    2022-06-06
  • C#实现自定义FTP操作封装类实例

    C#实现自定义FTP操作封装类实例

    这篇文章主要介绍了C#实现自定义FTP操作封装类,涉及C#操作FTP的连接、传输、下载等操作的实现技巧,非常具有实用价值,需要的朋友可以参考下
    2015-03-03
  • c# 垃圾回收(GC)优化

    c# 垃圾回收(GC)优化

    这篇文章主要介绍了c# 垃圾回收(GC)优化的相关资料,帮助大家更好的理解和学习c#,感兴趣的朋友可以了解下
    2021-02-02
  • 如何利用c#实现通用守护进程

    如何利用c#实现通用守护进程

    这篇文章主要给大家介绍了关于如何利用c#实现通用守护进程的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用c#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10
  • utf8编码检测方法分享

    utf8编码检测方法分享

    这篇文章主要介绍了utf8编码检测方法示例,需要的朋友可以参考下
    2014-02-02
  • richtextbox控件插入链接代码分享

    richtextbox控件插入链接代码分享

    richtextbox控件插入链接,暂时使用这个来解决链接的中文文本显示
    2013-12-12
  • C#实现在线更新软件

    C#实现在线更新软件

    winform程序相对web程序而言,功能更强大,编程更方便,但软件更新却相当麻烦,要到客户端一台一台地升级,面对这个实际问题,在最近的一个小项目中,本人设计了一个通过软件实现自动升级技术方案,弥补了这一缺陷,有较好的参考价值
    2015-05-05

最新评论