当前位置: 首页 > news >正文

Unity 状态机

文章目录

  • 前言
  • 一、状态机
  • 二、应用
    • 1、场景切换
    • 2、人物行为切换
    • 3、宝箱、机关切换
    • 4、AI
  • 三、人物行为
  • 总结


前言

提到Unity状态机,接触不久的开发者会想到Unity的动画状态机,而对于老油条来说,可能会回忆起自己实现的动画状态机。当然,常见的框架设计中都会出现属于自己的状态机接口,之前一篇文章也提到了一种FSM的写法。
状态机是分为有限状态机和无限状态机,而Unity开发的基本上都是有限状态机(FSM),无限状态机主要是在编译原理中可能用到,基本上属于概念向的东西,所以本篇主要介绍有限状态机(FSM)的使用。


一、状态机

相信大家都用过Unity的动画状态机,也就是Animator。我们知道一种状态在不同的条件下可以跳转到不同的状态中去,每个状态要转移到其他状态都必须满足它们之间的连线条件,而且状态与状态之间不一定有连线,因为两种状态之间有可能是不允许转换的。

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳主要是出于对状态机内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下。
·现态:是指当前所处的状态。 ·条件:又称“事件”,当一个条件被满足时,将会触发一个动作,或者执行一次状态的迁移。
·动作:条件满足后执行的动作。动作执行完毕后,既可以迁移到新的状态,也可以仍旧保持原状态。动作不是必须的,在条件满足后,也可以不执行任何动作,直接迁移到新状态。
·次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”。

二、应用

1、场景切换

场景是独立的,一般来说只有一个场景展示在游戏或软件中。在玩游戏的时候我们都不希望有漫长的等待时间,通常会进入登陆页面,对应的就是登陆场景;在进入游戏主场景就会销毁登陆页面的UI、模型等,在主场景生成游戏内容,这些操作我们需要统一在场景管理模块处理。

2、人物行为切换

人物通常只有一种状态,如:走、跑、跳等,如果想在跑步途中吃东西、挥舞武器则需要在跑步动作中加参数,根据传参的不同执行不同跑步动画。

3、宝箱、机关切换

宝箱、机关的状态可以看作独立的状态,即不是开就是关,对应的动画同理。

4、AI

敌人的AI根据游戏的不同,会用行为树或状态机实现。游戏中守卫在巡逻过程中,发现敌人就会追击并攻击,此时守卫的状态切换到了攻击状态,距离敌人或巡逻地点太远后会返回并退出攻击状态。

三、人物行为

人物的行为可以划分为待机、走路、攻击和受伤等状态。在状态机的处理中,人物在不同状态之间进行转换,具体如下:
待机状态(Idle):人物处于静止不动的状态,循环播放"idle"动画,等待玩家输入或者外部触发事件。
走路状态(Walking):人物进行移动,可能是根据玩家输入的方向键或者自动巡逻等行为。
攻击状态(Attacking):人物进行攻击行为,可能是使用武器、释放技能等。
受伤状态(Injured):人物受到伤害,处于受伤状态下,不能进行攻击。
状态机的处理需要根据具体的游戏逻辑和需求来设计转移条件和动作,确保人物在不同状态之间的转换符合游戏规则,并且能够实现预期的游戏体验。

Class BaseState
{Public virtual void OnEnter(){}Public virtual void OnExit(){}Public virtual void Update(){}
}Class IdleState
{Public override void OnEnter(){role.playAnimation(“idle”,loop);}
}Class AttackState
{Public override void OnEnter(){Role.playAnimation(“attack”,once);}Public override void Update(){If(!Role.IsPlayingAnimation(“attack”)){AttackStateFinish();}}Public override void OnExit(){GotoIdleState();}
}
Class HurtState
{Public override void OnEnter(){role.playAnimation(“hurt”,Once);}Public override void Update(){If(!Role.IsPlayingAnimation(“hurt”)){HurtFinish();}}Public override void OnExit(){GotoIdleState();}}Class MoveState
{Public override void OnEnter(){Role.playAnimation(“walk”,loop);}Public override void Update(){Move();}Public override void OnExit(){GotoIdleState();}
}

状态机管理类的处理如下:

class RoleStateController
{private IdleState idleState;private MoveState moveState;private AttackState attackState;private HurtState hurtState;private BaseState currentState;public void OnHurt(){ReduceHP();If(currentState != hurtState){ChangeToHurtState();}}public void InputAttack(){If(currentState  == hurtState) return;   // 受伤状态下不可攻击If(currentState == attackState) return;  // 攻击状态还没结束时不可重新开始攻击ChangeToAttackState();}Public void InputMove(){}
}

书中的代码为伪代码,但我们不难理解,状态机控制类存储了各个状态,并且提供了输入的接口,但输入的事件是状态机外部提供的,可能是玩家的操作。状态机的本质就是系统行为的数学模型,通过状态、转移条件和动作来控制系统在不同状态之间的转换。代码逻辑是存储状态,再提供输入接口。
实际应用中大量的逻辑会在每个状态内部实现,如果状态很多,管理类还需要改成列表存储状态进行切换。


总结

综合而言,状态机是一种数学模型,用于描述系统在不同状态下的行为转换,通过状态、转移条件和动作来控制系统的行为。在Unity中,状态机被广泛运用于处理各种行为切换,如场景切换、人物行为切换、宝箱、机关切换以及AI行为控制等。在编写特定模块时,状态机被证明是非常有用和实用的工具。

相关文章:

Unity 状态机

文章目录 前言一、状态机二、应用1、场景切换2、人物行为切换3、宝箱、机关切换4、AI 三、人物行为总结 前言 提到Unity状态机,接触不久的开发者会想到Unity的动画状态机,而对于老油条来说,可能会回忆起自己实现的动画状态机。当然&#xff…...

一毛钱不到的FH8208C单节锂离子和锂聚合物电池一体保护芯片

前言 目前市场上电池保护板,多为分体方案,多数场合使用没有问题,部分场合对空间有进一步要求,或者你不想用那么多器件,想精简一些,那么这个芯片就很合适,对于充电电池来说,应在使用…...

python数据可视化:显示两个变量间的关系散点图scatterplot()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 python数据可视化: 显示两个变量间的关系 散点图 scatterplot() [太阳]选择题 请问关于以下代码表述错误的选项是? import seaborn as sns import matplotlib.pyplot …...

【QT教程】QT6硬件高级编程入门 QT硬件高级编程

QT6硬件高级编程入门 使用AI技术辅助生成 QT界面美化视频课程 QT性能优化视频课程 QT原理与源码分析视频课程 QT QML C扩展开发视频课程 免费QT视频课程 您可以看免费1000个QT技术视频 免费QT视频课程 QT统计图和QT数据可视化视频免费看 免费QT视频课程 QT性能优化视频免费看…...

Android 蓝牙实战——蓝牙电话通话状态同步(二十四)

前面分析了蓝牙电话通话状态的广播,我们可以在蓝牙电话中实时监听蓝牙电话的状态,但如果是其他音乐类 APP 呢,在播放的时候也需要知道当前是否有通话正在进行,但是有完全没必要实时监听电话的状态,这就需要一个获取通话状态的方法。 一、通话状态处理 1、CallsManager …...

docker 指定根目录 迁移根目录

docker 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、启动docker程序前就手动指定docker根目录为一个大的分区(支持动态扩容),事前就根本上解决根目录空间不够问题3.1.0、方法思路3.1.1、docker官网安装文档3.1.2、下载docker安装包3.1.3、安装doc…...

React 项目报错解决办法收录

React 使用 引入文件报错 (react 别名配置craco) react ,vue 初始项目都是不支持 别名引入文件的。 vue 一般项目初始化的时候会 在 vue.config.js 文件中配置好,所以不需要我们自己配置react 初始化的时候是没有配置的, 需要我们自己配置 …...

Linux专题-Makefile(1)

1.Makefile中的注释使用 # 2. Makefile中的静默执行。 makefile中,默认情况下执行一行命令前会先把这一行命令打印出来,然后再执行这条命令。如果不想看到打印的命令,则可以使用静默执 行的功能,即仅打印出命令执行的结果。使用方…...

机器学习算法应用——CART决策树

CART决策树(4-2) CART(Classification and Regression Trees)决策树是一种常用的机器学习算法,它既可以用于分类问题,也可以用于回归问题。CART决策树的主要原理是通过递归地将数据集划分为两个子集来构建决…...

Sqli-labs第五,六关

目录 首先找到他们的闭合方式 操作 总结: 第五关根据页面结果得知是字符型但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。如果…...

上海AI Lab开源首个可替代GPT-4V的多模态大模型

与开源和闭源模型相比,InternVL 1.5 在 OCR、多模态、数学和多轮对话等 18 个基准测试中的 8 个中取得了最先进的结果。 上海AI Lab 推出的 InternVL 1.5 是一款开源的多模态大语言模型 (MLLM),旨在弥合开源模型和专有商业模型在多模态理解方面的能力差距…...

Python教程:一文了解PageObject模式

PageObject 模式是一种用于测试自动化的设计模式,它将页面的功能和页面的实现分开,提高了代码的可维护性和可重用性。本文将从基础概念开始,逐步介绍 Python 中的 PageObject 模式,并提供详细的代码示例。 1. 什么是 PageObject 模…...

SpringBoot 启动时查询数据库数据,并赋值给全局变量

创建一个组件 AreaData import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;import java.u…...

【Python】selenium爬虫常见用法和配置,以及常见错误和解决方法

欢迎来到《小5讲堂》 这是《Python》系列文章,每篇文章将以博主理解的角度展开讲解。 温馨提示:博主能力有限,理解水平有限,若有不对之处望指正! 目录 前言无执行文件代码报错信息错误路径手动下载自动下载 选项配置Ch…...

minio上传文件失败如何解决

1. 做了什么操作 通过接口上传excel文件,返回响应值 2. 错误如图 2. 如何解决 根据错误描述定位到了部署minio的地方minio通过docker部署,找到docker - compose发现配置文件中minio有两个端口,一个是用于api的,一个是用于管理界面…...

Java自动化测试框架--TestNG详解

一. 什么是TestNG TestNG是一个开源的自动化测试框架&#xff0c;它受JUnit和NUnit启发&#xff0c;其中“NG”即表示Next Generation&#xff0c;其功能更强大使用更方便。 二. TestNG配置 2.1 POM文件配置 在maven工程的pom.xml文件中加入以下依赖&#xff1a; <depe…...

【分布式 | 第五篇】何为分布式?分布式锁?和微服务关系?

文章目录 5.何为分布式&#xff1f;分布式锁&#xff1f;和微服务关系&#xff1f;5.1何为分布式&#xff1f;5.1.1定义5.1.2例子5.1.3优缺点&#xff08;1&#xff09;优点&#xff08;2&#xff09;缺点 5.2何为分布式锁&#xff1f;5.2.1定义5.2.2必要性 5.3区分分布式和微服…...

JavaScript百炼成仙自学笔记——13

函数七重关之六&#xff08;“new”一个函数&#xff09; 看个代码&#xff1a; function hello(){console.log(this); } 1、this&#xff1a;也是JavaScript中的一个关键字&#xff0c;永远指向当前函数的调用者 解释一下,有两层意思&#xff1a; ①this要嘛不出现&#…...

【skill】小米10让app永驻后台

小米10&#xff08;国行&#xff09;&#xff0c; 8128不能让app驻留后台我也忍了&#xff0c;但是12256依然如此&#xff0c;各种尝试&#xff0c;全网检索不杀app的方法&#xff0c;除了在系统设置里调&#xff0c;什么adb、shizuku冰箱冰柜的没一个能用 系统版本试过国行版…...

《架构风清扬-Java面试系列第29讲》聊聊DelayQueue的使用场景

DelayQueue是BlockingQueue接口的一个实现类之一 这个属于基础性问题&#xff0c;老规矩&#xff0c;我们将从使用场景和代码示例来进行讲解 来&#xff0c;思考片刻&#xff0c;给出你的答案 1&#xff0c;使用场景 实现&#xff1a;延迟队列&#xff0c;其中元素只有在其预定…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

前端倒计时误差!

提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

基于TurtleBot3在Gazebo地图实现机器人远程控制

1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

Git常用命令完全指南:从入门到精通

Git常用命令完全指南&#xff1a;从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

c++第七天 继承与派生2

这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分&#xff1a;派生类构造函数与析构函数 当创建一个派生类对象时&#xff0c;基类成员是如何初始化的&#xff1f; 1.当派生类对象创建的时候&#xff0c;基类成员的初始化顺序 …...