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

Unity自学之旅05

Unity自学之旅05

  • Unity学习之旅⑤
  • 📝 AI基础与敌人行为
    • 🥊 AI导航
      • 理论知识(基础)
      • 开始实践
    • 🎃 敌人游戏机制
      • 追踪玩家
      • 攻击玩家
      • 子弹碰撞
      • 完善游戏失败条件
  • 🤗 总结归纳

Unity学习之旅⑤

📝 AI基础与敌人行为

🥊 AI导航

理论知识(基础)

一、导航系统的基本组件

  1. NavMesh(导航网格)
    • NavMesh 是 Unity 中 AI 导航的基础,它是一个表示可行走区域的网格。它将场景中的可行走表面(如地面、楼梯等)进行三角剖分,形成一个平面的网格,用于代理(Agent)导航。
    • 生成 NavMesh 的步骤:
      • 首先,需要将场景中的几何体标记为静态(Static),以便 Unity 可以将它们纳入 NavMesh 的计算。
      • 然后,打开 Navigation 窗口(Window -> AI -> Navigation),在 Bake 选项卡中调整设置,例如 Agent Radius(代理半径)、Agent Height(代理高度)等,这些设置决定了代理在场景中占用的空间大小和形状。
      • 点击 Bake 按钮,Unity 会生成 NavMesh,显示为场景中的蓝色网格。
  2. NavMeshAgent(导航网格代理)
    • 这是附加在游戏对象上的组件,用于让对象在 NavMesh 上移动。
    • 主要属性:
      • Speed:代理的移动速度。
      • Acceleration:代理的加速度。
      • Stopping Distance:距离目标多远时停止移动。
      • Radius:代理的半径,用于避障和计算可行走区域。
      • Height:代理的高度,决定了代理可以通过的最小空间高度。
  3. NavMeshObstacle(导航网格障碍物)
    • 该组件用于表示场景中的动态障碍物。当一个对象附加了 NavMeshObstacle 时,它会影响 NavMeshAgent 的导航路径。
    • 可以设置为 Carve 模式,这会在 NavMesh 上动态地修改 NavMesh,使代理能够绕开障碍物。

二、导航行为和逻辑

  1. 路径规划
    • NavMeshAgent 会自动根据 NavMesh 为代理规划从当前位置到目标位置的最短路径。它会考虑障碍物和可行走区域。
    • 可以使用 agent.remainingDistance 来检查代理离目标的剩余距离,使用 agent.pathStatus 来查看路径的状态,如是否完成、正在计算或被阻塞。
  2. 避障
    • Unity 的导航系统会自动处理代理之间和代理与障碍物之间的避障。通过设置 NavMeshAgent 的属性,如 RadiusAvoidance Priority,可以调整避障行为。
    • 代理之间会根据彼此的 Avoidance Priority 进行避障,较低优先级的代理会主动避让较高优先级的代理。
  3. 动态导航
    • 当场景中的障碍物或目标位置发生变化时,NavMeshAgent 会自动重新计算路径。
    • 例如,如果要在游戏运行时改变目标位置,可以调用 agent.SetDestination(newDestination); ,其中 newDestination 是一个 Vector3 类型的新位置。

开始实践

window→package manager 选择 Unity Registry 然后搜索 AI Navigation

在这里插入图片描述

window→ai→navigation(obsolete) ,这里是因为我所使用的Unity版本那个AI Navigation static 已经弃用了,我更改了一种使用方式。

在这里插入图片描述

选择Environment,然后为点击Inspector中的Static,接着将Environment的对象及其子对象都设置为Navigation Static.

在这里插入图片描述

点击Bake→bake

在这里插入图片描述

为Enemy添加NavMeshAgent,让敌人可以在NavMesh上面行走。

在这里插入图片描述

绘制几个路径点,用于敌人的自动巡逻。

在这里插入图片描述

在这里插入图片描述

引用巡逻点,编辑EnemyBehavior脚本

   // 巡逻点的transformpublic Transform PatrolRoute;// 四个巡逻点的transform集合public List<Transform> Locations;void Start(){// 脚本运行时,初始化巡逻路径InitializePatrolRoute();}void InitializePatrolRoute(){foreach (Transform t in PatrolRoute){Locations.Add(t);}}

在这里插入图片描述

让Enemy跟着巡逻点动起来,在此编辑脚本

// ... 
// 默认第一个索引为0,即先走第一个巡逻点
private int _locationIndex = 0;// NavMeshAgent的引用
private NavMeshAgent _agent;void Start()
{// 获取Enemy对象上的NavMeshAgent组件的引用_agent = GetComponent<NavMeshAgent>();  // 脚本运行时,初始化巡逻路径InitializePatrolRoute(); MoveToNextPatrolLocation();
}// 移动到下一个巡逻点
void MoveToNextPatrolLocation()
{_agent.destination = Locations[_locationIndex].position;
}
//....

在这里插入图片描述

现在只会移动到第一个巡逻点,然后我们的目的是,在每个巡逻点,循环往复的进行移动,这个时候就需要在Update()中搞点事情了。

void Update()
{// 检测当前对象与目标位置距离if(_agent.remainingDistance < 0.2f && !_agent.pathPending){MoveToNextPatrolLocation();}    
}// 移动到下一个巡逻点void MoveToNextPatrolLocation(){if(Locations.Count == 0) return;_agent.destination = Locations[_locationIndex].position;// 索引循环往复_locationIndex = (_locationIndex + 1) % Locations.Count;    }

在这里插入图片描述

🎃 敌人游戏机制

敌人按照巡逻路线进行巡逻,当与玩家碰撞后,减少玩家生命值,然后敌人回到初始位置,玩家也可以攻击敌人,减少其生命值。

追踪玩家

当玩家进入敌人警戒范围时,敌人会直接奔向玩家。

 // 玩家的Transform引用public Transform Player;void Start(){// ...// 获取Player对象的引用Player = GameObject.Find("Player").transform;}// ...// 碰撞触发器void OnTriggerEnter(Collider other){if(other.name == "Player"){// 玩家进入到警戒范围后,敌人奔向玩家_agent.destination = Player.position;Debug.Log("玩家进入警戒范围");}    }

攻击玩家

攻击玩家的逻辑很简单,当玩家与敌人发生碰撞时,玩家减少生命值,并且在GUI上显示

修改玩家的Playerbehavior脚本(敌人脚本也可以,因为碰撞是相互的)

// gameManager的引用,因为HP,收集道具数量都在该处存放
private GameBehavior _gameManager;void Start(){// 将当前player的刚体组件获取并设置_rb = GetComponent<Rigidbody>();// 获取当前角色的胶囊碰撞体_col = GetComponent<CapsuleCollider>();_gameManager = GameObject.Find("Game_Manager").GetComponent<GameBehavior>();}// 发生碰撞时void OnCollisionEnter(Collision collision){// 如果与敌人碰撞则HP-1if (collision.gameObject.name == "Enemy"){_gameManager.HP -= 1;}}

在这里插入图片描述

这里的话需要注意一个问题,就是敌人身上的碰撞体为碰撞触发器,勾选了Is Trigger,然后直接通过Player的OnCollisionEnter()并不会触发,需要给敌人再加入一个碰撞体就可以了。

在这里插入图片描述

子弹碰撞

为Player添加反击手段,逻辑就是敌人有三滴血,当子弹射击三次并且击中敌人后,敌人自动销毁。

编辑敌人Enemy的游戏脚本

// 敌人的HP=3
private int _lives = 3;
public int EnemyLives
{get { return _lives; }set{_lives = value;if (_lives <= 0){Destroy(this.gameObject);Debug.Log("敌人死亡");}}
}void OnCollisionEnter(Collision collision)
{// 当子弹碰撞到敌人时if(collision.gameObject.name == "Bullet(Clone)"){EnemyLives -= 1;Debug.Log("遭受子弹射击");}
}

在这里插入图片描述

完善游戏失败条件

逻辑是,生命值为0时,游戏暂停,出现一个按钮说:你输了。

先绘制一个Button按钮,和之前的一样,默认禁用即可,当生命值为0时,在脚本内调用。

在这里插入图片描述

编辑GameManager的脚本

public Button LossButton;
private int _playerHp = 10;
public int HP
{get { return _playerHp; }set{//...if (_playerHp <= 0){ProgressText.text = "You want another life with that?";LossButton.gameObject.SetActive(true);Time.timeScale = 0f;}else{ProgressText.text = "Ouch... that's got hurt.";}Debug.LogFormat("HP:{0}", _playerHp);}
}

在这里插入图片描述

🤗 总结归纳

本文主要介绍了在 Unity 中实现 AI 导航以及构建敌人游戏机制的方法。包括导航系统的基本组件、导航行为和逻辑,以及敌人的巡逻、追踪玩家、攻击玩家、被子弹击中和完善游戏失败条件等功能。

重要亮点

  • 导航系统基本组件:Unity 中 AI 导航的基础是 NavMesh,它将场景中的可行走表面进行三角剖分形成网格。NavMeshAgent 是附加在游戏对象上用于在 NavMesh 上移动的组件,NavMeshObstacle 用于表示动态障碍物。
  • 导航行为和逻辑:NavMeshAgent 能自动规划从当前位置到目标位置的最短路径,处理避障和动态导航。例如,当场景中的障碍物或目标位置变化时,会自动重新计算路径。
  • 敌人巡逻机制:通过为敌人添加 NavMeshAgent,设置巡逻点,编写脚本实现敌人在巡逻点之间循环往复移动。
  • 追踪玩家:当玩家进入敌人警戒范围时,敌人会奔向玩家。通过在敌人脚本中检测玩家进入碰撞触发器,设置敌人的目标位置为玩家位置。
  • 攻击玩家:当玩家与敌人发生碰撞时,玩家减少生命值。在玩家脚本和敌人脚本中分别处理碰撞事件。
  • 完善游戏失败条件:当玩家生命值为 0 时,游戏暂停,出现 “你输了” 按钮。在游戏管理器脚本中根据玩家生命值控制按钮的显示和游戏时间的暂停。

相关文章:

Unity自学之旅05

Unity自学之旅05 Unity学习之旅⑤&#x1f4dd; AI基础与敌人行为&#x1f94a; AI导航理论知识&#xff08;基础&#xff09;开始实践 &#x1f383; 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 &#x1f917; 总结归纳 Unity学习之旅⑤ &#x1f4dd; AI基础与敌…...

linux中关闭服务的开机自启动

引言 systemctl 是 Linux 系统中用于管理 systemd 服务的命令行工具。它可以用来启动、停止、重启服务&#xff0c;管理服务的开机自启动&#xff0c;以及查看服务的状态等。 什么是 systemd&#xff1f; systemd 是现代 Linux 发行版中默认的 初始化系统&#xff08;init sys…...

Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )

一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化&#xff1a; 文件是存储数据的一种非常基本且重要的方式。通过文件&#xff0c;我们可 以将程序运行时产生的数据永久保存下来&#xff0c;以便将来使用。 跨平台兼容性&#xff1a; 文件是一种通用…...

ubuntu黑屏问题解决

重启Ubuntu后&#xff0c;系统自动进入tty1&#xff0c;无法进入桌面。想到前几天安装了一些主题之类的&#xff0c;然后今天才重启&#xff0c;可能是这些主题造成冲突或者问题了把。 这里直接重新安装ubuntu-desktop解决&#xff1a; 更新源&#xff1a; sudo apt-get upd…...

Java如何实现反转义

Java如何实现反转义 前提 最近做的一个需求&#xff0c;是热搜词增加换一批的功能。功能做完自测后&#xff0c;交给了测试伙伴&#xff0c;但是测试第二天后就提了一个bug&#xff0c;出现了未知词 levis。第一眼看着像公司售卖的一个品牌-李维斯。然后再扒前人写的代码&…...

动态规划(路径问题)

62. 不同路径 62. 不同路径 - 力扣&#xff08;LeetCode&#xff09; 动态规划思想第一步&#xff1a;描述状态~ dp[i][j]&#xff1a;表示走到i&#xff0c;j位置时&#xff0c;一共有多少种方法~ 动态规划思想第二步&#xff1a;状态转移方程~ 动态规划思想第三步&#xf…...

python http调用视觉模型moondream

目录 一、什么是moondream 二、资源地址 三、封装了http进行接口请求 四、代码解析 解释 可能的改进 一、什么是moondream Moondream 是一个针对视觉生成任务的深度学习模型,专注于图像理解和生成,包括图像标注(captioning)、问题回答(Visual Question Answering,…...

Spark Streaming编程基础

文章目录 1. 流式词频统计1.1 Spark Streaming编程步骤1.2 流式词频统计项目1.2.1 创建项目1.2.2 添加项目依赖1.2.3 修改源目录1.2.4 添加scala-sdk库1.2.5 创建日志属性文件 1.3 创建词频统计对象1.4 利用nc发送数据1.5 启动应用&#xff0c;查看结果 2. 编程模型的基本概念3…...

深入 Flutter 和 Compose 的 PlatformView 实现对比,它们是如何接入平台控件

在上一篇《深入 Flutter 和 Compose 在 UI 渲染刷新时 Diff 实现对比》发布之后&#xff0c;收到了大佬的“催稿”&#xff0c;想了解下 Flutter 和 Compose 在 PlatformView 实现上的对比&#xff0c;恰好过去写过不少 Flutter 上对于 PlatformView 的实现&#xff0c;这次恰好…...

C# OpenCV机器视觉:红外体温检测

在一个骄阳似火的夏日&#xff0c;全球却被一场突如其来的疫情阴霾笼罩。阿强所在的小镇&#xff0c;平日里熙熙攘攘的街道变得冷冷清清&#xff0c;人们戴着口罩&#xff0c;行色匆匆&#xff0c;眼神中满是对病毒的恐惧。阿强作为镇上小有名气的科技达人&#xff0c;看着这一…...

FCA-FineDataLink认证

FCA-FineDataLink证书 Part.1&#xff1a;判断题 &#xff08;总分&#xff1a;18分 得分&#xff1a;16&#xff09; 第1题 判断题 数据同步只支持写入到已存在表&#xff0c;不支持自动建表(得分&#xff1a;2分 满分&#xff1a;2分) 正确答案&#xff1a;B 你的答案&…...

第19篇:python高级编程进阶:使用Flask进行Web开发

第19篇&#xff1a;python高级编程进阶&#xff1a;使用Flask进行Web开发 内容简介 在第18篇文章中&#xff0c;我们介绍了Web开发的基础知识&#xff0c;并使用Flask框架构建了一个简单的Web应用。本篇文章将深入探讨Flask的高级功能&#xff0c;涵盖模板引擎&#xff08;Ji…...

js截取video视频某一帧为图片

1.代码如下 <template><div class"box"><div class"video-box"><video controls ref"videoRef" preload"true"src"https://qt-minio.ictshop.com.cn:9000/resource-management/2025/01/08/7b96ac9d957c45a…...

[云讷科技]Kerloud Falcon四旋翼飞车虚拟仿真空间发布

虚拟仿真环境作为一个独立的专有软件包提供给我们的客户&#xff0c;用于帮助用户在实际测试之前验证自身的代码&#xff0c;并通过在仿真引擎中添加新的场景来探索新的飞行驾驶功能。 环境要求 由于环境依赖关系&#xff0c;虚拟仿真只能运行在装有Ubuntu 18.04的Intel-64位…...

Jetson nano 安装 PCL 指南

本指南帮助 ARM64 架构的 Jetson Nano 安装 PCL&#xff08;点云库&#xff09;。 安装步骤 第一步&#xff1a;安装依赖 在终端中运行以下命令&#xff0c;安装 PCL 所需的依赖&#xff1a; sudo apt-get update sudo apt-get install git build-essential linux-libc-dev s…...

go-zero框架基本配置和错误码封装

文章目录 加载配置信息配置 env加载.env文件配置servicecontext 查询数据生成model文件执行查询操作 错误码封装配置拦截器错误码封装 接上一篇&#xff1a;《go-zero框架快速入门》 加载配置信息 配置 env 在项目根目录下新增 .env 文件&#xff0c;可以配置当前读取哪个环…...

Android中Service在新进程中的启动流程2

目录 1、Service在客户端的启动入口 2、Service启动在AMS的处理 3、Service在新进程中的启动 4、Service与AMS的关系再续 上一篇文章中我们了解了Service在新进程中启动的大致流程&#xff0c;同时认识了与客户端进程交互的接口IApplicationThread以及与AMS交互的接口IActi…...

论文速读|Matrix-SSL:Matrix Information Theory for Self-Supervised Learning.ICML24

论文地址&#xff1a;Matrix Information Theory for Self-Supervised Learning 代码地址&#xff1a;https://github.com/yifanzhang-pro/matrix-ssl bib引用&#xff1a; article{zhang2023matrix,title{Matrix Information Theory for Self-Supervised Learning},author{Zh…...

ubunut22.04安装docker(基于阿里云 Docker 镜像源安装 Docker)

安装 更新包管理器&#xff1a; sudo apt update 安装 Docker 的依赖包 sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release添加阿里云 Docker 镜像源 GPG 密钥&#xff1a; curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gp…...

k8s namespace绑定节点

k8s namespace绑定节点 1. apiserver 启用准入控制 PodNodeSelector2. namespace 添加注解 scheduler.alpha.kubernetes.io/node-selector3. label node 1. apiserver 启用准入控制 PodNodeSelector vim /etc/kubernetes/manifests/kube-apiserver.yaml spec:containers:- co…...

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇&#xff0c;在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下&#xff1a; 【Note】&#xff1a;如果你已经完成安装等操作&#xff0c;可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作&#xff0c;重…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...