Unity自学之旅05

server/2025/2/1 2:20:47/

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 时,游戏暂停,出现 “你输了” 按钮。在游戏管理器脚本中根据玩家生命值控制按钮的显示和游戏时间的暂停。

http://www.ppmy.cn/server/163944.html

相关文章

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(绘图设备封装)

目录 图像层的底层抽象——绘图设备抽象 如何抽象一个绘图设备&#xff1f; 桥接绘图设备&#xff0c;特化为OLED设备 题外话&#xff1a;设备的属性&#xff0c;与设计一个相似函数化简的通用办法 使用函数指针来操作设备 总结一下 图像层的底层抽象——绘图设备抽象 在…

【落羽的落羽 数据结构篇】算法复杂度

文章目录 一、数据结构和算法简介二、算法复杂度1. 时间复杂度2. 空间复杂度 一、数据结构和算法简介 数据结构是计算机存储、组织数据的方式&#xff0c;指相互之间存在一种或多种特定关系的数据元素的集合。没有一种单一的数据结构对所有用途都有用&#xff0c;所以我们要学…

2025年数学建模美赛 A题分析(3)楼梯使用方向偏好模型

2025年数学建模美赛 A题分析&#xff08;1&#xff09;Testing Time: The Constant Wear On Stairs 2025年数学建模美赛 A题分析&#xff08;2&#xff09;楼梯磨损分析模型 2025年数学建模美赛 A题分析&#xff08;3&#xff09;楼梯使用方向偏好模型 2025年数学建模美赛 A题分…

剑指 Offer II 008. 和大于等于 target 的最短子数组

comments: true edit_url: https://github.com/doocs/leetcode/edit/main/lcof2/%E5%89%91%E6%8C%87%20Offer%20II%20008.%20%E5%92%8C%E5%A4%A7%E4%BA%8E%E7%AD%89%E4%BA%8E%20target%20%E7%9A%84%E6%9C%80%E7%9F%AD%E5%AD%90%E6%95%B0%E7%BB%84/README.md 剑指 Offer II 008.…

EWM 变更库存类型

目录 1 简介 2 配置 3 业务操作 1 简介 一般情况下 EWM 标准收货流程是 ROD(Ready on Dock) --> AFS(Avaiable for Sale),对应 AG 001 --> AG 002,对应库存类型 F1 --> F2。 因业务需要反向进行的时候,AFS --> ROD,AG 002 --> AG 001,库存类型 F2…

单片机串口打印printf函数显示内容(固件库开发)

1.hal_usart.c 文件 #include <stdio.h> #include "hal_usart.h" #include "stm32F10x.h"//**要根据 使用的是哪个串口 对应修改 串口号 eg&#xff1a;USART1** void USART_PUTC(char ch) {/* 等待数据寄存器为空 */while((USART1->SR & …

docker中运行的MySQL怎么修改密码

1&#xff0c;进入MySQL容器 docker exec -it 容器名 bash 我运行了 docker ps命令查看。正在运行的容器名称。可以看到MySQL的我起名为db docker exec -it db bash 这样就成功的进入到容器中了。 2&#xff0c;登录MySQL中 mysql -u 用户名 -p 回车 密码 mysql -u root -p roo…

Deepseek r1模型对医疗大模型的发展有什么影响?

1. 强化学习技术的突破与创新 DeepSeek R1 是一款基于纯强化学习&#xff08;RL&#xff09;训练的开源推理模型&#xff0c;其核心在于通过环境反馈而非人工标注数据来优化模型行为。这种方法不仅降低了对标注数据的依赖&#xff0c;还显著提升了模型的推理能力。例如&#x…