Unity学习笔记(五)什么是状态机

前言

本文为 Udemy 课程 The Ultimate Guide to Creating an RPG Game in Unity 学习笔记。

前面开发模式的问题

之前的开发中,我们的代码都集中在 Player2 这个文件下,这种开发模式存在以下缺点:

  • 代码在同一个文件中,代码量大后非常难以维护。
  • 角色的行为逻辑直接在对应的方法中维护,后续新增功能会频繁修改这些方法,容易导致大量 Bug。

例如:

一开始实现的移动代码

private void Movement() {rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);
}

加入冲刺后

private void Movement() {xInput = Input.GetAxisRaw("Horizontal");if (dashTime > 0) {rb.velocity = new Vector2(facingDir * dashSpeed, 0);} else {rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);}
}

再加入攻击后

private void Movement() {xInput = Input.GetAxisRaw("Horizontal");if (isAttacking) {rb.velocity = new Vector2(0, 0);} else if (dashTime > 0) {rb.velocity = new Vector2(facingDir * dashSpeed, 0);} else {rb.velocity = new Vector2(xInput * moveSpeed, rb.velocity.y);}
}

每次新增功能,都需要修改 Movement() 方法,导致代码越来越臃肿,维护起来非常困难。

使用状态模式解决

为了避免上述问题,可以使用**状态模式(状态机)**来实现。


什么是状态模式(State Pattern)?

状态模式是一种面向对象的设计模式,其核心思想是:

当对象的内部状态改变时,其行为也随之改变

通过将对象的行为和状态分离,每个状态封装为独立的类,从而实现状态切换的清晰性和易扩展性。


状态模式的结构

状态模式通常包括以下几个关键部分:

1. 上下文(Context)

  • 表示当前工作的对象,包含当前状态的引用。
  • 通过调用当前状态的方法完成具体的行为。

2. 状态接口(State)

  • 定义接口或抽象类,用于表示所有可能的状态。
  • 每个状态都实现该接口。

3. 具体状态(Concrete States)

  • 实现状态接口的类,每个类表示一种特定状态并定义该状态的具体行为。

4. 状态切换

  • 状态切换通过上下文类完成,可以由上下文主动切换,也可以由状态自身决定何时切换。

状态模式的示例代码

以下是使用状态模式模拟角色行为(站立、行走、跑步)的代码示例:

1. 定义状态接口

public interface IState {void EnterState(Player player);void UpdateState(Player player);
}

2. 定义具体状态

public class IdleState : IState {public void EnterState(Player player) {Debug.Log("进入站立状态");}public void UpdateState(Player player) {if (player.Speed > 0) {player.SetState(new WalkState());}}
}public class WalkState : IState {public void EnterState(Player player) {Debug.Log("进入行走状态");}public void UpdateState(Player player) {if (player.Speed == 0) {player.SetState(new IdleState());} else if (player.Speed > 5) {player.SetState(new RunState());}}
}public class RunState : IState {public void EnterState(Player player) {Debug.Log("进入跑步状态");}public void UpdateState(Player player) {if (player.Speed <= 5) {player.SetState(new WalkState());}}
}

3. 上下文类

public class Player {public float Speed { get; set; }private IState currentState;public Player() {currentState = new IdleState();currentState.EnterState(this);}public void SetState(IState newState) {currentState = newState;currentState.EnterState(this);}public void Update() {currentState.UpdateState(this);}
}

运行流程

  1. Player 是上下文类,包含当前状态的引用 currentState
  2. IdleStateWalkStateRunState 是具体状态,实现了 IState 接口。
  3. 根据 Speed 值切换状态:
    • Speed == 0:切换到 IdleState
    • 0 < Speed <= 5:切换到 WalkState
    • Speed > 5:切换到 RunState

Unity 中的状态机

Unity Animator 中的状态机

Animator 状态机 是 Unity 提供的用于动画控制的可视化工具。其核心包括:

  1. 状态(State)

    • 每个状态代表一种动画或行为。
    • 例如:
      • Idle:站立状态。
      • Walk:行走状态。
      • Run:跑步状态。
  2. 过渡(Transition)

    • 状态之间通过过渡连接,过渡规则决定状态切换条件。
  3. 参数(Parameters)

    • 用于控制状态切换的输入值,如:
      • Float(如 speed)。
      • Bool(如 isJumping)。
      • Trigger(如 jumpTrigger)。

Animator 的使用步骤

  1. 创建 Animator Controller

    • 在 Unity 中右键 -> Create -> Animator Controller
    • 将 Animator Controller 添加到角色的 Animator 组件中。
  2. 创建动画状态

    • 双击 Animator Controller 打开 Animator 窗口。
    • 右键 -> Create State -> 添加动画状态,将动画片段拖入状态。
  3. 设置参数

    • 在 Animator 的 Parameters 面板中,添加所需的参数(Float、Bool、Trigger 等)。
  4. 添加过渡

    • 在状态之间右键 -> Make Transition,设置条件。
  5. 通过代码控制

    Animator animator;void Start() {animator = GetComponent<Animator>();
    }void Update() {animator.SetFloat("speed", Input.GetAxis("Vertical"));if (Input.GetKeyDown(KeyCode.Space)) {animator.SetBool("isJumping", true);}if (Input.GetMouseButtonDown(0)) {animator.SetTrigger("attackTrigger");}
    }
    

状态模式与Unity中的状态机的关系

Unity中的状态机(如Animator状态机)并非严格的状态模式实现,但它是状态模式的一种具体应用。以下是两者的异同点:

特性状态模式(State Pattern)Unity Animator 状态机
状态实现通过代码实现,每个状态是一个独立的类通过可视化界面实现,每个状态对应一个动画片段
状态切换显式调用代码切换状态基于参数和条件,Animator自动完成状态切换
扩展性添加新状态需要定义新的类,代码管理灵活新状态需要通过界面添加,逻辑复杂时可能难以维护
复杂逻辑适合处理复杂的状态切换和行为定义主要用于控制动画状态,逻辑层次较浅
行为与状态绑定每个状态都可以实现独特的行为状态通常只是动画播放,不直接控制行为

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/500795.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

flux中的缓存

1. cache&#xff0c;onBackpressureBuffer。都是缓存。cache可以将hot流的数据缓存起来。onBackpressureBuffer也是缓存&#xff0c;但是当下游消费者的处理速度比上游生产者慢时&#xff0c;上游生产的数据会被暂时存储在缓冲区中&#xff0c;防止丢失。 2. Flux.range 默认…

linux文件类型和根目录结构

1.1 Linux文件类型 1.2 Linux系统的目录结构 1.2.1 FHS filesystem hierarchy standard 文件系统层级标准&#xff0c;定义了在类 Unix 系统中的目录结构和目录内容&#xff0c;即 让用户了解到已安装软件通常放置于哪个目录下。 Linux 目录结构的特点 使用树形目录结构来…

瑞_Linux中部署配置Java服务并设置开机自启动

文章目录 背景Linux服务配置步骤并设置开机自启动附-Linux服务常用指令 &#x1f64a; 前言&#xff1a;由于博主在工作时&#xff0c;需要将服务部署到 Linux 服务器上运行&#xff0c;每次通过指令启动服务非常麻烦&#xff0c;所以将 jar 包部署的服务设置开机自启动&#x…

算法题(23):只出现一次的数字

初级&#xff1a; 审题&#xff1a; 需要输出只出现了一次的数据&#xff0c;其他数据均出现了两次 思路&#xff1a; 若不限制空间复杂度&#xff1a; 方法一&#xff1a;哈希表 用哈希映射循环一次&#xff0c;把对应数字出现的次数记录到数组里面&#xff0c;然后再遍历一次…

STM32拓展 低功耗案例1:睡眠模式 (register)

需求描述 让MCU进入睡眠模式&#xff0c;然后通过串口发送消息来唤醒MCU退出睡眠模式。观察LED在进入休眠模式后是否仍然开启。 思考 首先睡眠模式&#xff0c;唤醒的条件是中断&#xff0c;外部内部都可以&#xff0c;这里的串口接收中断时内部中断。 拓展&#xff1a;中断…

CSS 学习之 padding 与图形绘制

padding 属性和 background-clip 属性配合&#xff0c;可以在有限的标签下实现一些 CSS 图形绘制效果&#xff0c;我这里举两个小例子&#xff0c;重在展示可行性。 例 1:不使用伪元素&#xff0c;仅一层标签实现大队长的“三道杠”分类图标效果。此效果在移动端比较常见&…

机器学习 学习知识点

机器学习 学习知识点 什么是消融实验&#xff08;Ablation experiment&#xff09;&#xff1f;num_step与batch_size的区别python glob.glob()函数认识python的条件判断之is not、is not None、is Nonetqdm介绍及常用方法softmax 激活函数。type_as(tesnor)Python OpenCV cv2.…

【网络安全 | 漏洞挖掘】硬编码凭据泄露实现支付系统账户接管

未经许可,不得转载。 文章目录 前言在APK中寻找硬编码凭据+账户接管在APP流程中寻找硬编码凭据+账户接管总结前言 硬编码凭据是指直接嵌入应用程序源代码中的敏感信息,例如 API 密钥、密钥、用户名或密码。这些凭据通常为了开发便捷而添加,但往往在发布到生产代码或应用路径…

【数据库系列】Spring Boot 中整合 MyBatis-Plus详细步骤

在 Spring Boot 中整合 MyBatis-Plus 可以按照以下步骤进行&#xff1a; 一、整合步骤 1. 创建 Spring Boot 项目 首先&#xff0c;使用 Spring Initializr&#xff08;https://start.spring.io/&#xff09;创建一个新的 Spring Boot 项目。在创建过程中&#xff0c;选择以…

JVM实战—8.如何分析jstat统计来定位GC

大纲 1.使用jstat了解线上系统的JVM运行状况 2.使用jmap和jhat了解线上系统的对象分布 3.如何分析JVM运行状况并合理优化 4.使用jstat分析模拟的BI系统JVM运行情况 5.使用jstat分析模拟的计算系统JVM运行情况 6.问题汇总 1.使用jstat了解线上系统的JVM运行状况 (1)JVM的…

[人工智能] 结合最新技术:Transformer、CLIP与边缘计算在提高人脸识别准确率中的应用

随着人工智能的快速发展&#xff0c;特别是深度学习和自然语言处理领域的革命性技术&#xff0c;越来越多的前沿技术被应用于人脸识别中。Transformer架构、CLIP模型以及边缘计算的结合&#xff0c;正成为提升人脸识别准确率和应用效能的关键技术路径。特别是在多样化场景下&am…

DataV数据可视化

阿里云 DataV 是一个强大的数据可视化工具&#xff0c;可以帮助用户通过创建丰富的图表、仪表盘、地图和互动视图&#xff0c;将复杂的数据转化为易于理解和分析的可视化信息。DataV主要用于大数据和实时数据的展示&#xff0c;可以帮助企业和个人更直观地理解数据背后的含义&a…

【国产NI替代】基于STM32+FPGA的8振动+4温度(16bits)数据采集板卡解决方案,支持全国产

一、8振动4温度&#xff08;16bits&#xff09;数据采集板卡解决方案 采用STM32H743做为主控芯片&#xff0c;针对工业现场 环境设计的12通道数据采集装置&#xff0c;采集器模 拟信号调理电路采用模块化设计&#xff0c;前通道模 块可配置&#xff0c;可扩展&#xff0c;其…

SpringMVC(一)配置

目录 引入 第一章&#xff1a;Java web的发展历史 一、Model I和Model II 1.Model I开发模式 2.Model II开发模式 二. MVC模式 第二章&#xff1a;SpringMVC的入门案例 搭建SpringMVC的入门程序 1.创建新项目 2.等待加载导入坐标 3.处理xml文件和其他 导入tomcat 运…

数据结构(ing)

学习内容 指针 指针的定义&#xff1a; 指针是一种变量&#xff0c;它的值为另一个变量的地址&#xff0c;即内存地址。 指针在内存中也是要占据位置的。 指针类型&#xff1a; 指针的值用来存储内存地址&#xff0c;指针的类型表示该地址所指向的数据类型并告诉编译器如何解…

Java网络套接字

在Java的开发中&#xff0c;有一个很重要&#xff01;很重要&#xff01;很重要&#xff01;的东西&#xff0c;叫做网络套接字&#xff0c;它被广泛的用来二次开发服务&#xff0c;比如大数据中台的服务链路调用等。 它的实现原理是依靠三次握手来完成通信的建立&#xff0c;…

Mac 安装Mysql启动Mysql以及数据库的常规操作

Mac 安装Mysql启动Mysql以及数据库的常规操作 一、mysql的安装 1、登录官方网站:dev.mysql.com/downloads/mysql/ 二、查看系统架构 uname -m 在MAC中&#xff1a; 如果输出结果是 x86_64&#xff0c;则表示你的系统是 x86-64 架构。 如果输出结果是 arm64&#xff0c;则表示…

OpenCV的人脸检测模型FaceDetectorYN

OpenCV的人脸检测模型FaceDetectorYN 1. 官网地址2. 如何使用2.1.到opencv_zoo下载模型文件和代码2.2. 下载文件展示2.3. 修改了demo支持读取视频文件&#xff0c;默认是图片和摄像头## 2.4 效果展示 1. 官网地址 https://docs.opencv.org/4.x/df/d20/classcv_1_1FaceDetector…

DeepSeek-VL2

《DeepSeek-VL2: Mixture-of-Experts Vision-Language Models for Advanced Multimodal Understanding》是 DeepSeek-AI 团队发布的关于视觉语言模型 DeepSeek-VL2 的论文&#xff0c;以下是对该论文的详细介绍&#xff1a; 研究背景与动机 多模态理解的重要性&#xff1a;在当…

电子应用设计方案82:智能 AI 椅子系统设计

智能 AI 椅子系统设计 一、引言 智能 AI 椅子旨在为用户提供更加舒适、个性化和智能化的坐乘体验&#xff0c;结合了先进的技术和人体工程学原理。 二、系统概述 1. 系统目标 - 自动适应用户的体型和坐姿&#xff0c;提供最佳的支撑和舒适度。 - 实时监测用户的健康数据&…