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


猜你喜欢
- 最近公司项目中有一个类似滴滴出行填写验证码的弹框,下面是我撸出来的效果: 中间的那个输入密码的6个框框其实就是用shape画的背景
- 不记得从哪找的了,修改了部分代码,修复在Android平台下使用时,时区时间格式异常的问题。package cn.aikongmeng.de
- 项目最终的文件结构1 添加maven依赖 <dependency> <groupI
- Lambda,希腊字母λ,在C#编程语言中,被引入为Lambda表达式,表示为匿名函数(匿名方法)。编程时离不开函数,
- 简单介绍华为鸿蒙系统应用开发工具 DevEco Studio的安装和使用据说12月份鸿蒙系统会推出手机的SDK哦,作为一名普通的开发者,表示
- Monkeyrunner 常用按键 &nbs
- 本文介绍Android九宫格程序的设计代码,供大家参考,具体内容如下一.相关介绍(一)效果显示1.程序刚运行时的效果:2.在页面上点击选择并
- 最近公司因为短信接口被盗刷的比较严重,需要做一个类似于淘宝的滑动验证,用于特定环境,以增加一层保障。拿到需求首先想到的是自定义ViewGro
- 首先,确保 IDEA 软件正确安装完成,Java 开发工具包 JDK 安装完成。IDEA 的 Java 项目 (Project) 则相当于
- 在没讲.net如何随机生成汉字之前先给大家讲下汉字编码组成及原理。1、汉字编码原理到底怎么办到随机生成汉字的呢?汉字从哪里来的呢?是不是有个
- 我们先来看本地如何生成图片验证码的,再来写输出到网页的验证码如何实现。先来看最简单的—实现的功能是,将一个字符串变成图片写入到文件中实现代码
- 前言:1.最近项目上在测试人员压测过程中发现了OOM问题,项目使用springboot搭建项目工程,通过查看日志中包含信息:unable t
- 一、递归概念递归本质:程序调用自身的编程技巧叫做递归。程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言
- 一:简述如果我们想要生成一个随机数,通常会使用Random类。但是在并 * 况下Random生成随机数的性能并不是很理想,今天给大家介绍一下J
- 一、ReentrantLockpackage com.ietree.basicskill.mutilthread.lock;import j
- spring boot 秉承约定优于配置,spring boot在静态资源的处理上就已经默认做了处理。1.默认资源映射映射”/**”的路径到
- char类在C#中表示一个unicode字符,正是这些unicode字符构成了字符串。unicode字符是目前计算机中通用的字符编码,它为针
- C++的 bitset 在 bitset 头文件中,它是一种类似数组的结构,它的每一个元素只能是0或1,每个元素仅用1bit空间。下面是具体
- 项目结构项目路径可以自己定义,只要路径映射正确就可以pom.xml <properties> <spring.versio
- 一、变量C#共有其中变量类型有:静态变量、实类变量、数组元素、数值参数、引用参数、输出参数和局部变量先定义一个简单的类来说明,如下:publ