Unity学习之FSM有限状态机
作者:念丶小宇 发布时间:2022-09-10 06:18:33
前言:一个游戏里的一个人物会存在多种状态,那么就需要有一个专门管理这些状态的类。不然会显得杂乱无章,不易于后面状态的增加或者减少。
思路:既然要方便管理,那么首先肯定得有个系统类(专门用来存放所有的状态、状态的增删等功能);然后就是需要把所有的状态都单独写一个类(已达到修改某个状态的时候,其他状态不会受到影响)。
状态管理类:
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); }}
来源:https://blog.csdn.net/qq_43815828/article/details/117918980
猜你喜欢
- timer的schedule和scheduleAtFixedRate方法一般情况下是没什么区别的,只在某个情况出现时会有区别--当前任务没有
- Google 发布的Material Design支持库,对我们的APP设计有很大的影响,如果重新设计APP,支持库应该直接用V4提升到V7
- 一、利用Web服务中的JavaScriptSerializer 类System.Web.Script.Serialization空间,位于S
- name和url属性的作用定义feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调
- final File imageFile = new File(getCacheDir().getPath() + "/img/&
- Quartz简介Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中。它提供了巨大的
- 本文实例为大家分享了java实现文件下载的具体代码,供大家参考,具体内容如下public HttpServletResponse downl
- BigDecimal类对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDe
- 前言在RequestMappingHandlerAdapter对request进行了适配,并且调用了目标handler之后,其会返回一个Mo
- 错误Mybatis-Plus (简称MP) 是mybatis的一个增强工具,在mybatis的基础上只做增强不做改变,简化了开发效率。其实就
- 1介绍MVC框架是什么MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(control
- 首先,要学习Spring中的Bean的注入方式,就要先了解什么是依赖注入。依赖注入是指:让调用类对某一接口的实现类的实现类的依赖关系由第三方
- 前言传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:1、如果所有的内容都配置在.xml
- Mybatis 有两种实现方式其一:通过xml配置文件实现其二:面向接口编程的实现  
- 上篇教程回顾ServerSocket --监听客户端的连接,他的作用主要是建立一个连接-ServerSocket -建立连接,拿到一个Soc
- 使用的场景常常遇到一些项目中多环境切换的问题。比如在开发过程中用到开发环境,在测试中使用测试环境,在生产中用生产环境的情况。springbo
- 使用wait()和notify()实现Java多线程通信:两个线程交替打印A和B,如ABABABpublic class Test { &n
- java中javaBean与Bean的深入理解JavaBean 是Java中的一种特殊的类,可以将多个对象封装到一个对象(bean)中。特点
- 起因:有后端同事反馈在异步线程中获取了request中的参数,然后下一个请求是get请求的话,发现会偶尔出现参数丢失的问题.示例代码:@Ge
- SLF4J是一个日志框架抽象层,底下绑定具体的日志框架,比如说Log4J,Logback,Java Logging API等。SLF4J也有