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

2024-07-13 Unity AI状态机2 —— 项目介绍

文章目录

  • 1 项目介绍
  • 2 模块介绍
    • 2.1 BaseState
    • 2.2 ...State
      • 2.2.1 PatrolState
      • 2.2.2 ChaseState / AttackState / BackState
    • 2.3 StateMachine
    • 2.4 Monster
  • 3 其他功能
  • 4 类图

项目借鉴 B 站唐老狮 2023年直播内容。 点击前往唐老狮 B 站主页。

1 项目介绍

​ 本项目使用 Unity 2022.3.32f1c1,实现基本的 AI 框架。其中,用 Cube(绿色)代替怪物模型,Cube(红色)代替玩家,即 AI 目标。

image-20240713164018099

​ 项目地址:https://github.com/zheliku/StateMachine_AI。

2 模块介绍

2.1 BaseState

​ 在框架介绍的基础上,添加了两个方法:

  1. DistanceOfXZ(Vector3, Vector3)

    用于计算 xz 平面上的距离(不考虑 y 轴方向)。

  2. DrawGizmos()

    用于辅助绘制范围,在 Scene 窗口中显示。

using UnityEngine;/// <summary>
/// 状态基类
/// </summary>
public abstract class BaseState
{public virtual EAIState AIState { get; } // 状态类型protected StateMachine _stateMachine; // 附属的状态机public BaseState(StateMachine stateMachine) {_stateMachine = stateMachine;}public abstract void OnStateEnter();public abstract void OnStateUpdate();public abstract void OnStateExit();/// <summary>/// 辅助绘制范围,不强制重写/// </summary>public virtual void DrawGizmos() { }/// <summary>/// XZ 平面上的距离/// </summary>protected float DistanceOfXZ(Vector3 pos1, Vector3 pos2) {pos1.y = pos2.y = 0;return Vector3.Distance(pos1, pos2);}
}

2.2 …State

​ 项目实现了 4 种 AI 状态,包括

  • PatrolState(巡逻状态)
  • ChaseState(追逐状态)
  • AttackState(攻击状态)
  • BackState(返回状态)

2.2.1 PatrolState

​ PatrolState 实现较为详细,其将巡逻方式分为 3 种:

public enum EPatrolType
{Stay,       // 原地播放某个动作(睡觉、放哨等)CircleMove, // 圆形范围内随机移动PathMove    // 按照路径移动
}

​ 巡逻数据可以直接在 PatrolState 类中声明。本项目选择封装在 PatrolStateData 中。所有 Data 均继承 ScripteObject 类,可以在 Project 窗口中右键直接创建并配置对应数据。

  • PatrolStateData:所有巡逻种类的共有数据。

  • PatrolStateStayData:原地巡逻的数据。

  • PatrolStateMoveData:移动巡逻的数据。

  • PatrolStateCircleMoveData:圆形范围移动巡逻的数据。

  • PatrolStatePathMoveData:路径移动巡逻的数据。

StateMachine_AI PatrolStateData
  1. Stay:

    原地播放某个动作,因此需要 AI 动作枚举。目前只添加 Sleep 动作。

    public enum EAction
    {Sleep,
    }
    
  2. Move:

    范围内随机移动,分为两种:Circle、Path。区别是获取下一次目标位置的方式不同,因此提取出如下逻辑:

    public class PatrolState : BaseState
    {private PatrolStateData _data; // 巡逻数据.../// <summary>/// 移动/// </summary>private void OnMoveUpdate(IAIObject aiObject, EPatrolType moveType) {var data = (PatrolStateMoveData)_data; // 转化数据..._data.targetPos = moveType switch {EPatrolType.CircleMove => CalCircleTargetPos((PatrolStateCircleMoveData)data),EPatrolType.PathMove   => CalPathTargetPos((PatrolStatePathMoveData)data),_                      => throw new ArgumentOutOfRangeException(nameof(moveType), moveType, null)};...}/// <summary>/// 更新圆形范围目标位置/// </summary>private Vector3 CalCircleTargetPos(PatrolStateCircleMoveData data) { ... }/// <summary>/// 更新路径范围目标位置/// </summary>private Vector3 CalPathTargetPos(PatrolStatePathMoveData data) { ... }...
    }
    

2.2.2 ChaseState / AttackState / BackState

​ 该 3 个状态都遵循以下大致框架:

using UnityEngine;public class ...State : BaseState
{private ...StateData _data;public override EAIState AIState { get => ...; }public AttackState(StateMachine stateMachine) : base(stateMachine) {// 加载数据var data = Resources.Load<...StateData>("StateData/.../...StateData");_data = Object.Instantiate(data);}public override void OnStateEnter() { ... }public override void OnStateUpdate() { ... }public override void OnStateExit() { ... }...
}

2.3 StateMachine

​ AddState()、ChangeState() 和 UpdateState() 逻辑如下:

/// <summary>
/// 添加 AI 状态
/// </summary>
public void AddState(EAIState state) {switch (state) {case EAIState.Patrol:_stateDic.Add(state, new PatrolState(this));break;case EAIState.Back:_stateDic.Add(state, new BackState(this));break;case EAIState.Chase:_stateDic.Add(state, new ChaseState(this));break;case EAIState.Attack:_stateDic.Add(state, new AttackState(this));break;default: throw new ArgumentOutOfRangeException(nameof(state), state, null);}
}/// <summary>
/// 切换状态
/// </summary>
/// <param name="state"></param>
public void ChangeState(EAIState state) {_nowState?.OnStateExit(); // 退出状态if (_stateDic.TryGetValue(state, out BaseState nowState)) { // 进入状态_nowState = nowState;_nowState.OnStateEnter();}
}/// <summary>
/// 更新当前状态
/// </summary>
public void UpdateState() {_nowState?.OnStateUpdate();_nowState?.DrawGizmos(); // 辅助绘图
}

2.4 Monster

​ 怪物类实现了 IAIObject 接口(详见 2024-07-12 Unity AI状态机1 —— 框架介绍),通过 Unity 导航系统中的 NavMeshAgent 实现基本移动。除了 IAIObject 接口,还包含一些自己的数据。

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;public class Monster : MonoBehaviour, IAIObject
{public Transform  targetTransform; // 目标位置public GameObject bullet;          // 子弹public float      attackRange = 3; // 攻击范围private Quaternion _startRotation;  // 记录开始攻击时的角度private Quaternion _targetRotation; // 记录目标角度private float      _rotateTime;     // 旋转计时private NavMeshAgent _navMeshAgent; // 导航代理private StateMachine _aiMachine; // AI 状态机private void Start() {_navMeshAgent = GetComponent<NavMeshAgent>();BornPos       = transform.position;_aiMachine = new StateMachine();_aiMachine.Init(this);// 为 AI 添加巡逻状态_aiMachine.AddState(EAIState.Patrol);_aiMachine.AddState(EAIState.Chase);_aiMachine.AddState(EAIState.Attack);_aiMachine.AddState(EAIState.Back);// 更改初始状态_aiMachine.ChangeState(EAIState.Patrol);}private void Update() {_aiMachine.UpdateState();}#region IAIObject 接口实现...#endregion
}

3 其他功能

​ 为了辅助绘图,为 BaseState 添加了 DrawGizmos() 方法(virtual),子类可以实现该方法,在 Scene 窗口中绘制辅助线。同时,在 BaseState 中添加 DistanceOfXZ() 方法,以便所有状态都可使用。以下是 BaseState 的全部逻辑:

using UnityEngine;/// <summary>
/// 状态基类
/// </summary>
public abstract class BaseState
{public virtual EAIState AIState { get; } // 状态类型protected StateMachine _stateMachine; // 附属的状态机public BaseState(StateMachine stateMachine) {_stateMachine = stateMachine;}public abstract void OnStateEnter();public abstract void OnStateUpdate();public abstract void OnStateExit();/// <summary>/// 辅助绘制范围,不强制重写/// </summary>public virtual void DrawGizmos() { }/// <summary>/// XZ 平面上的距离/// </summary>protected float DistanceOfXZ(Vector3 pos1, Vector3 pos2) { ... }
}

​ 辅助绘图时,使用 Unity Asset Store 中的插件 DrawXXL 实现,例如 ChaseState 中的 DrawGizmos 如下:

public override void DrawGizmos() {var aiObject = _stateMachine.AIObject;// 绘制攻击范围DrawShapes.Circle(aiObject.Transform.position, aiObject.AttackRange, Color.red,Vector3.up, lineWidth: 0.05f);// 绘制脱离范围DrawShapes.Circle(aiObject.Transform.position, _data.chaseDistance, new Color(1, 0.5f, 0),Vector3.up, lineWidth: 0.05f, outlineStyle: DrawBasics.LineStyle.dotted);
}

4 类图

StateMachine_AI 部分类图

相关文章:

2024-07-13 Unity AI状态机2 —— 项目介绍

文章目录 1 项目介绍2 模块介绍2.1 BaseState2.2 ...State2.2.1 PatrolState2.2.2 ChaseState / AttackState / BackState 2.3 StateMachine2.4 Monster 3 其他功能4 类图 项目借鉴 B 站唐老狮 2023年直播内容。 点击前往唐老狮 B 站主页。 1 项目介绍 ​ 本项目使用 Unity 2…...

shell脚本-linux如何在脚本中远程到一台linux机器并执行命令

需求&#xff1a;我们需要从11.0.1.17远程到11.0.1.16上执行命令 实现&#xff1a; 1.让11.0.1.17 可以免密登录到11.0.1.16 [rootlocalhost ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): Created d…...

Spring Data Redis + Redis数据缓存学习笔记

文章目录 1 Redis 入门1.1 简介1.2 Redis服务启动与停止&#xff08;Windows&#xff09;1.2.1 服务启动命令1.2.2 客户端连接命令1.2.3 修改Redis配置文件1.2.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍 3. Redis常用命令3.1 字符串操作命令3.2 哈希操作…...

在项目中,如何使用springboot+vue+springsecurity+redis缓存+Axios+MySQL数据库+mybatis

要在项目中使用springbootvuespringsecurityredis缓存AxiosMySQL数据库mybatis&#xff0c;可以按照以下步骤进行操作&#xff1a; 创建一个Spring Boot项目&#xff0c;并添加所需的依赖。在pom.xml文件中添加Spring Boot、Spring Security、Redis、MySQL和MyBatis的依赖项。 …...

微调 Florence-2 - 微软的尖端视觉语言模型

Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型。该模型极具吸引力&#xff0c;因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色。 Florence 开箱即用支持多种类型的任务&#xff0c;包括: 看图说话、目标检测、OCR 等等。虽然覆盖面…...

【数据结构】二叉树全攻略,从实现到应用详解

​ &#x1f48e;所属专栏&#xff1a;数据结构与算法学习 &#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ ​ &#x1f341;1. 树形结构的介绍 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做…...

微信小程序加载动画文件

最近在做微信小程序的动画&#xff0c;调研了几种方案 PAG 腾讯自家的&#xff0c;分为完整版和lite版&#xff0c;对于矢量动画挺好的&#xff0c;但是位图会有问题 完整版会逐渐卡死&#xff0c;lite虽然不会卡死&#xff0c;但是很模糊&#xff0c;优点是动画文件很的很小。…...

[计算机网络] VPN技术

VPN技术 1. 概述 虚拟专用网络&#xff08;VPN&#xff09;技术利用互联网服务提供商&#xff08;ISP&#xff09;和网络服务提供商&#xff08;NSP&#xff09;的网络基础设备&#xff0c;在公用网络中建立专用的数据通信通道。VPN的主要优点包括节约成本和提供安全保障。 优…...

SQL 中的 EXISTS 子句:探究其用途与应用

目录 EXISTS 子句简介语法 EXISTS 与 NOT EXISTSEXISTS 子句的工作原理实际应用场景场景一&#xff1a;筛选存在关联数据的记录场景二&#xff1a;优化查询性能 EXISTS 与其他 SQL 结构的比较EXISTS vs. JOINEXISTS vs. IN 多重 EXISTS 条件在 UPDATE 语句中使用 EXISTS常见问题…...

OpenSearch分析WAF日志

Web应用防火墙(WAF)是保护web应用程序的重要工具,而分析WAF日志可以帮助我们更好地了解安全威胁并优化防护策略。本文将介绍15个使用OpenSearch分析WAF日志的实用例子,涵盖基础统计、安全分析、性能监控等多个方面。 准备工作 在开始之前,请确保: WAF日志已经被发送到OpenSea…...

【前端】零基础学会编写CSS

一、什么是CSS CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;是一种是一种用来为结构化文档&#xff08;如 HTML 文档&#xff09;添加样式&#xff08;字体、间距和颜色等&#xff09;的计算机语言&#xff0c;能够对网页中元素位置的排版进行像素级别的精…...

Day07-ES集群加密,kibana的RBAC实战,zookeeper集群搭建,zookeeper基本管理及kafka单点部署实战

Day07-ES集群加密&#xff0c;kibana的RBAC实战&#xff0c;zookeeper集群搭建&#xff0c;zookeeper基本管理及kafka单点部署实战 0、昨日内容回顾:1、基于nginx的反向代理控制访问kibana2、配置ES集群TSL认证:3、配置kibana连接ES集群4、配置filebeat连接ES集群5、配置logsta…...

RK3568 V1.4.0 SDK,USB OTG端子不能被电脑识别出adb设备,解决

修改后的/usr/bin/usbdevice: #!/bin/sh # # Usage: # usbdevice [start|update|stop] # # Hookable stages: # usb_<pre|post>_<init|prepare|start|stop|restart>_hook # <usb function>_<pre|post>_<prepare|start|stop>_hook # # Example …...

如何在 Ubuntu 14.04 服务器上使用 Nginx 安装和保护 phpMyAdmin

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 介绍 像 MySQL 这样的关系型数据库管理系统在许多网站和应用程序中都是必不可少的。然而&#xff0c;并非所有用户都习惯通过命令行来管…...

redis存入hash,key=>value和key=>(key=>value)使用Python举例

在 Redis 中&#xff0c;HASH 数据结构&#xff08;也称为 HMAP 或 Hash Map&#xff09;允许你存储键值对集合&#xff0c;其中每个键值对都是字段&#xff08;field&#xff09;和值&#xff08;value&#xff09;的映射。在 Python 中&#xff0c;你可以使用 redis-py 库来与…...

Guava LocalCache源码分析:LocalCache的get、put、expand、refresh、remove、clear、cleanUp

Guava LocalCache源码分析&#xff1a;LocalCache的get、put、expand 前言一、get二、put三、expand 前言 上篇文章&#xff0c;详细描写了Guava LocalCache怎样如ConcurrentHashMap对缓存数据进行了分段存储。本章主要针对LocalCache重要的几个接口进行说明。 一、get CanIg…...

linux-arm ubuntu18.04 qmqtt5.12.6 编译部署

安装 qt 查看qt 版本 &#xff1a; qmake -v 下载对应版本 qmqtt 解压下载的mqtt文件 进入qmqtt xxx/src 目录 在qt 安装目录中创建QtMqtt文件夹&#xff0c; &#xff0d; x86平台qt 默认目录为 /usr/include/x86_64-linux-gnu/qt5 &#xff0d; arm平台qt 默认目录为/us…...

阿里ChatSDK使用,开箱即用聊天框

介绍&#xff1a; 效果&#xff1a;智能助理 ChatSDK&#xff0c;是在ChatUI的基础上&#xff0c;结合阿里云智能客服的最佳实践&#xff0c;沉淀和总结出来的一个开箱即用的&#xff0c;可快速搭建智能对话机器人的框架。它简单易上手&#xff0c;通过简单的配置就能搭建出对…...

LangChain —— Message —— How to trim messages

文章目录 一、概述二、获取最后的 max_tokens 令牌三、获取第一个 max_tokens 令牌四、编写自定义令牌计数器五、连成链六、使用 ChatMessageHistory 一、概述 所有模型都有 有限的 上下文窗口&#xff0c;这意味着它们可以作为输入的 token 数量是有限的。如果你有很长的消息&…...

专升本-1.0.3(英语)-升本209天-星期二

自己要耐得住寂寞&#xff0c;守得住自己的初心&#xff0c;守得住自己的未来&#xff0c;然后不断地真实地面对自己&#xff0c;使自己不断地获得一个真实地成长&#xff0c;说真话办真事&#xff0c;自己总会有一条路了&#xff0c;说真话&#xff0c;办真事的那条路才是最为…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

IT供电系统绝缘监测及故障定位解决方案

随着新能源的快速发展&#xff0c;光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域&#xff0c;IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选&#xff0c;但在长期运行中&#xff0c;例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

华为OD机试-最短木板长度-二分法(A卷,100分)

此题是一个最大化最小值的典型例题&#xff0c; 因为搜索范围是有界的&#xff0c;上界最大木板长度补充的全部木料长度&#xff0c;下界最小木板长度&#xff1b; 即left0,right10^6; 我们可以设置一个候选值x(mid)&#xff0c;将木板的长度全部都补充到x&#xff0c;如果成功…...

springboot 日志类切面,接口成功记录日志,失败不记录

springboot 日志类切面&#xff0c;接口成功记录日志&#xff0c;失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

C# winform教程(二)----checkbox

一、作用 提供一个用户选择或者不选的状态&#xff0c;这是一个可以多选的控件。 二、属性 其实功能大差不差&#xff0c;除了特殊的几个外&#xff0c;与button基本相同&#xff0c;所有说几个独有的 checkbox属性 名称内容含义appearance控件外观可以变成按钮形状checkali…...

DAY 45 超大力王爱学Python

来自超大力王的友情提示&#xff1a;在用tensordoard的时候一定一定要用绝对位置&#xff0c;例如&#xff1a;tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾&#xff1a; tensorboard的发展历史和原理tens…...