Unity自学之旅05
Unity自学之旅05
- Unity学习之旅⑤
- 📝 AI基础与敌人行为
- 🥊 AI导航
- 理论知识(基础)
- 开始实践
- 🎃 敌人游戏机制
- 追踪玩家
- 攻击玩家
- 子弹碰撞
- 完善游戏失败条件
- 🤗 总结归纳
Unity学习之旅⑤
📝 AI基础与敌人行为
🥊 AI导航
理论知识(基础)
一、导航系统的基本组件
- NavMesh(导航网格):
- NavMesh 是 Unity 中 AI 导航的基础,它是一个表示可行走区域的网格。它将场景中的可行走表面(如地面、楼梯等)进行三角剖分,形成一个平面的网格,用于代理(Agent)导航。
- 生成 NavMesh 的步骤:
- 首先,需要将场景中的几何体标记为静态(Static),以便 Unity 可以将它们纳入 NavMesh 的计算。
- 然后,打开 Navigation 窗口(Window -> AI -> Navigation),在 Bake 选项卡中调整设置,例如 Agent Radius(代理半径)、Agent Height(代理高度)等,这些设置决定了代理在场景中占用的空间大小和形状。
- 点击 Bake 按钮,Unity 会生成 NavMesh,显示为场景中的蓝色网格。
- NavMeshAgent(导航网格代理):
- 这是附加在游戏对象上的组件,用于让对象在 NavMesh 上移动。
- 主要属性:
- Speed:代理的移动速度。
- Acceleration:代理的加速度。
- Stopping Distance:距离目标多远时停止移动。
- Radius:代理的半径,用于避障和计算可行走区域。
- Height:代理的高度,决定了代理可以通过的最小空间高度。
- NavMeshObstacle(导航网格障碍物):
- 该组件用于表示场景中的动态障碍物。当一个对象附加了
NavMeshObstacle时,它会影响NavMeshAgent的导航路径。 - 可以设置为
Carve模式,这会在 NavMesh 上动态地修改 NavMesh,使代理能够绕开障碍物。
- 该组件用于表示场景中的动态障碍物。当一个对象附加了
二、导航行为和逻辑
- 路径规划:
NavMeshAgent会自动根据 NavMesh 为代理规划从当前位置到目标位置的最短路径。它会考虑障碍物和可行走区域。- 可以使用
agent.remainingDistance来检查代理离目标的剩余距离,使用agent.pathStatus来查看路径的状态,如是否完成、正在计算或被阻塞。
- 避障:
- Unity 的导航系统会自动处理代理之间和代理与障碍物之间的避障。通过设置
NavMeshAgent的属性,如Radius和Avoidance Priority,可以调整避障行为。 - 代理之间会根据彼此的
Avoidance Priority进行避障,较低优先级的代理会主动避让较高优先级的代理。
- Unity 的导航系统会自动处理代理之间和代理与障碍物之间的避障。通过设置
- 动态导航:
- 当场景中的障碍物或目标位置发生变化时,
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学习之旅⑤📝 AI基础与敌人行为🥊 AI导航理论知识(基础)开始实践 🎃 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 🤗 总结归纳 Unity学习之旅⑤ 📝 AI基础与敌…...
linux中关闭服务的开机自启动
引言 systemctl 是 Linux 系统中用于管理 systemd 服务的命令行工具。它可以用来启动、停止、重启服务,管理服务的开机自启动,以及查看服务的状态等。 什么是 systemd? systemd 是现代 Linux 发行版中默认的 初始化系统(init sys…...
Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )
一、文件处理 1.1、文件操作的重要性和应用场景 1.1.1、重要性 数据持久化: 文件是存储数据的一种非常基本且重要的方式。通过文件,我们可 以将程序运行时产生的数据永久保存下来,以便将来使用。 跨平台兼容性: 文件是一种通用…...
ubuntu黑屏问题解决
重启Ubuntu后,系统自动进入tty1,无法进入桌面。想到前几天安装了一些主题之类的,然后今天才重启,可能是这些主题造成冲突或者问题了把。 这里直接重新安装ubuntu-desktop解决: 更新源: sudo apt-get upd…...
Java如何实现反转义
Java如何实现反转义 前提 最近做的一个需求,是热搜词增加换一批的功能。功能做完自测后,交给了测试伙伴,但是测试第二天后就提了一个bug,出现了未知词 levis。第一眼看着像公司售卖的一个品牌-李维斯。然后再扒前人写的代码&…...
动态规划(路径问题)
62. 不同路径 62. 不同路径 - 力扣(LeetCode) 动态规划思想第一步:描述状态~ dp[i][j]:表示走到i,j位置时,一共有多少种方法~ 动态规划思想第二步:状态转移方程~ 动态规划思想第三步…...
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 启动应用,查看结果 2. 编程模型的基本概念3…...
深入 Flutter 和 Compose 的 PlatformView 实现对比,它们是如何接入平台控件
在上一篇《深入 Flutter 和 Compose 在 UI 渲染刷新时 Diff 实现对比》发布之后,收到了大佬的“催稿”,想了解下 Flutter 和 Compose 在 PlatformView 实现上的对比,恰好过去写过不少 Flutter 上对于 PlatformView 的实现,这次恰好…...
C# OpenCV机器视觉:红外体温检测
在一个骄阳似火的夏日,全球却被一场突如其来的疫情阴霾笼罩。阿强所在的小镇,平日里熙熙攘攘的街道变得冷冷清清,人们戴着口罩,行色匆匆,眼神中满是对病毒的恐惧。阿强作为镇上小有名气的科技达人,看着这一…...
FCA-FineDataLink认证
FCA-FineDataLink证书 Part.1:判断题 (总分:18分 得分:16) 第1题 判断题 数据同步只支持写入到已存在表,不支持自动建表(得分:2分 满分:2分) 正确答案:B 你的答案&…...
第19篇:python高级编程进阶:使用Flask进行Web开发
第19篇:python高级编程进阶:使用Flask进行Web开发 内容简介 在第18篇文章中,我们介绍了Web开发的基础知识,并使用Flask框架构建了一个简单的Web应用。本篇文章将深入探讨Flask的高级功能,涵盖模板引擎(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四旋翼飞车虚拟仿真空间发布
虚拟仿真环境作为一个独立的专有软件包提供给我们的客户,用于帮助用户在实际测试之前验证自身的代码,并通过在仿真引擎中添加新的场景来探索新的飞行驾驶功能。 环境要求 由于环境依赖关系,虚拟仿真只能运行在装有Ubuntu 18.04的Intel-64位…...
Jetson nano 安装 PCL 指南
本指南帮助 ARM64 架构的 Jetson Nano 安装 PCL(点云库)。 安装步骤 第一步:安装依赖 在终端中运行以下命令,安装 PCL 所需的依赖: sudo apt-get update sudo apt-get install git build-essential linux-libc-dev s…...
go-zero框架基本配置和错误码封装
文章目录 加载配置信息配置 env加载.env文件配置servicecontext 查询数据生成model文件执行查询操作 错误码封装配置拦截器错误码封装 接上一篇:《go-zero框架快速入门》 加载配置信息 配置 env 在项目根目录下新增 .env 文件,可以配置当前读取哪个环…...
Android中Service在新进程中的启动流程2
目录 1、Service在客户端的启动入口 2、Service启动在AMS的处理 3、Service在新进程中的启动 4、Service与AMS的关系再续 上一篇文章中我们了解了Service在新进程中启动的大致流程,同时认识了与客户端进程交互的接口IApplicationThread以及与AMS交互的接口IActi…...
论文速读|Matrix-SSL:Matrix Information Theory for Self-Supervised Learning.ICML24
论文地址:Matrix Information Theory for Self-Supervised Learning 代码地址:https://github.com/yifanzhang-pro/matrix-ssl bib引用: article{zhang2023matrix,title{Matrix Information Theory for Self-Supervised Learning},author{Zh…...
ubunut22.04安装docker(基于阿里云 Docker 镜像源安装 Docker)
安装 更新包管理器: sudo apt update 安装 Docker 的依赖包 sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release添加阿里云 Docker 镜像源 GPG 密钥: 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…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合
无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
