ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Unity 2D游戏智能寻路实战:NavMeshPlus配置与避坑指南

2026/8/6 22:44:33 拓冰建站 浏览量
Unity 2D游戏智能寻路实战:NavMeshPlus配置与避坑指南

1. 项目概述:为什么2D游戏也需要智能寻路?

在Unity里做2D游戏,尤其是俯视角的RPG、塔防或者策略游戏,角色移动是个绕不开的坎。很多新手朋友一开始可能会用Transform.Translate或者Vector2.MoveTowards,写个简单的直线移动,对付固定路径还行。但一旦场景复杂起来,有障碍物、有动态变化的通道,角色要是还像个没头苍蝇一样撞墙,那游戏体验可就大打折扣了。

这就是智能寻路要解决的问题。它能让你的游戏角色像真人一样,自己找到从A点到B点的最优(或可行)路径,自动绕开障碍。在3D游戏里,Unity自带的NavMesh(导航网格)系统是标配,功能强大。但到了2D世界,官方并没有提供原生的2D NavMesh解决方案。直接拿3D的NavMesh来用?也不是不行,但你需要把2D的Sprite强行放到3D空间里,处理Z轴、碰撞体朝向等问题,非常别扭,而且性能开销和配置复杂度都上去了。

所以,社区里的大神们就开发了NavMeshPlus。这是一个专门为Unity 2D项目打造的导航网格系统,它继承了Unity NavMesh的核心思想,但完全在2D的坐标系下工作。你可以把它理解为“2D版的NavMesh”。它的目标很明确:让你能用类似3D NavMesh的流程和工作流,轻松为你的2D精灵实现智能寻路。

我最近在一个2D俯视角的生存建造项目里深度用了一把NavMeshPlus,从踩坑到跑通,感触颇深。这篇文章,我就把自己从零配置、到让怪物智能追击玩家、再到处理动态障碍物的完整过程,以及那些官方文档里没写的“坑”和技巧,毫无保留地分享出来。无论你是刚接触2D寻路的新手,还是正在寻找更优雅2D导航方案的老手,这篇教程都能给你一套可直接“抄作业”的配置流程和实战心法。

2. 核心思路与工具选型:为什么是NavMeshPlus?

在决定使用NavMeshPlus之前,我们得先理清2D寻路的几种常见方案,以及它们各自的优劣。这样你才能明白,为什么在特定场景下,NavMeshPlus是更优解。

2.1 常见2D寻路方案对比

  1. A寻路算法*:

    • 原理:基于网格(Grid)或点阵(Waypoint)的经典算法,通过评估每个节点的代价来寻找最短路径。
    • 优点:极度灵活,路径精确,社区资源丰富(如A* Pathfinding Project插件)。
    • 缺点:需要预先生成网格或布置路点,对于大型、开放或地形复杂的2D场景,网格数据量可能很大。动态更新障碍(如玩家建造的墙)需要实时更新网格,有一定性能开销。配置和调优相对复杂。
  2. Raycast 或 Physics2D.Raycast 探测

    • 原理:朝目标方向发射射线,检测碰撞,遇到障碍则尝试调整方向。
    • 优点:实现简单,适合行为非常简单的AI(如只朝玩家直线移动,碰壁后随机转向)。
    • 缺点:无法处理复杂地形,极易卡在角落或U型障碍里,寻路结果不智能,更像是“碰壁反应”而非“路径规划”。
  3. Unity 3D NavMesh 降维使用

    • 原理:将2D平面视为3D的XZ平面或XY平面,为3D物体(即使它只是个薄片)生成导航网格。
    • 优点:可以直接使用Unity成熟、高效的NavMesh系统,包括动态障碍物(NavMeshObstacle)。
    • 缺点:工作流不原生,需要处理3D碰撞体、3D代理(NavMeshAgent),在纯2D项目中显得格格不入,容易引发坐标系混乱和渲染层级问题。
  4. NavMeshPlus

    • 原理:专为2D设计,在2D碰撞体(如BoxCollider2D,PolygonCollider2D)的基础上,生成2D空间的导航网格。使用NavMeshAgent2D组件进行移动。
    • 优点
      • 工作流原生:完全在2D坐标系下工作,与SpriteRendererCollider2D等组件无缝衔接,概念清晰。
      • 性能与功能平衡:继承了NavMesh的快速路径查询和本地规避(Local Avoidance)潜力,对于大多数2D游戏来说性能足够。
      • 动态更新支持:通过NavMeshModifier等组件,可以相对高效地处理场景中动态变化的可行走区域。
      • 社区驱动,持续维护:作为Unity官方“Experimental”仓库下的项目,有一定的质量保证和社区支持。

注意:NavMeshPlus目前(撰写本文时)仍处于“实验性(Experimental)”阶段,这意味着它的API在未来的版本中可能会有变动。但对于大多数稳定开发的2D项目来说,其核心功能已经非常可靠。建议从GitHub仓库下载发布版(Release),而非直接克隆开发分支,以获得更高稳定性。

2.2 NavMeshPlus 核心组件一览

在开始配置前,我们先快速认识一下NavMeshPlus里的几个关键组件,这有助于理解后续的配置流程:

  • NavMeshSurface2D:这是大脑。你需要把它挂载在场景中的一个空物体上(通常命名为“Navigation”或“NavMeshSurface”)。它的职责是收集场景中标记了特定层的2D碰撞体,并根据这些碰撞体的形状,烘焙(Bake)生成整个场景的导航网格数据。
  • NavMeshAgent2D:这是执行者。你需要把它挂载在需要智能移动的游戏对象上(比如你的玩家角色或敌人)。它包含了速度、加速度、转向速度、停止距离等参数,负责根据NavMeshSurface2D生成的网格来计算路径并控制对象移动。
  • NavMeshModifier/NavMeshModifierVolume2D:这是规则制定者。它们可以附加在场景中的物体上,用来局部修改导航网格的生成规则。比如,你可以用一个NavMeshModifier让某个平台只能被“飞行”类型的Agent行走,或者用NavMeshModifierVolume2D定义一个区域,禁止任何Agent进入。

理清了这些,我们的配置目标就很明确了:首先用NavMeshSurface2D根据场景地形烘焙出“可行走的地图”,然后为角色添加NavMeshAgent2D并编写脚本让它去目标点,最后利用NavMeshModifier来处理一些特殊规则。

3. 环境准备与项目导入

工欲善其事,必先利其器。在开始烘焙导航网格之前,我们需要先把NavMeshPlus正确地导入到你的Unity项目中。

3.1 获取NavMeshPlus

官方推荐的方式是通过Unity的Package Manager从Git仓库添加。这是最规范、便于后续更新的方法。

  1. 打开你的Unity项目(建议使用2020.3 LTS或更新版本,兼容性更好)。
  2. 在顶部菜单栏,选择Window > Package Manager
  3. 在Package Manager窗口左上角,点击“+”按钮,选择“Add package from git URL...”
  4. 在弹出的输入框中,粘贴NavMeshPlus的Git仓库地址:https://github.com/h8man/NavMeshPlus.git
  5. 点击“Add”按钮。Unity会开始下载并导入这个包。这个过程可能需要一点时间,取决于你的网络。

实操心得:有时直接从Git URL添加可能会因为网络问题失败。备选方案是去它的GitHub发布页面(https://github.com/h8man/NavMeshPlus/releases)下载最新的.unitypackage文件,然后像导入普通资源包一样双击导入。我个人更推荐Git URL方式,因为它能更好地与Package Manager集成,未来检查更新更方便。

导入成功后,你可以在Package Manager的列表里看到“NavMesh Plus (Experimental)”。同时,在你的项目窗口中,应该能看到一个“Packages”目录,里面包含了NavMeshPlus的代码和示例。

3.2 基础场景搭建

为了演示,我们创建一个最简单的测试场景。你可以跟着做,也可以在你的项目场景中直接操作。

  1. 创建地形:在场景中创建一些2D精灵(Sprite)作为地面和障碍物。例如:
    • 创建一个名为“Ground”的Sprite,缩放成一个大的矩形,作为主地面。
    • 创建几个名为“Wall”或“Obstacle”的Sprite,缩放成矩形或任意形状,散落在“Ground”上作为障碍物。
  2. 添加碰撞体:这是最关键的一步!NavMeshPlus是依靠2D碰撞体来识别边界和生成导航网格的。
    • 为“Ground”添加一个BoxCollider2D组件。这定义了“可行走区域”的范围。
    • 为每一个“Obstacle”添加BoxCollider2DPolygonCollider2D组件。这定义了“障碍物”的范围。
  3. 创建角色:创建一个简单的圆形或方形Sprite,命名为“Player”或“Agent”。暂时不用为它添加任何移动脚本。

现在你的场景应该包含:一个有碰撞体的地面,几个有碰撞体的障碍物,和一个没有脚本的角色。层级视图(Hierarchy)大概类似这样:

- Ground (带有Sprite Renderer和BoxCollider2D) - Obstacle_1 (带有Sprite Renderer和BoxCollider2D) - Obstacle_2 - Player (带有Sprite Renderer,暂无其他组件)

4. 核心配置:烘焙你的第一张2D导航网格

有了场景和导入的包,接下来就是最核心的步骤——烘焙导航网格。这个过程和在3D里用NavMesh Surface几乎一样直观。

4.1 创建并配置NavMeshSurface2D

  1. 在层级视图(Hierarchy)中右键,选择Create Empty,将新建的空物体命名为“Navigation”或“NavMeshSurface”。

  2. 选中这个空物体,在检查器(Inspector)中点击Add Component

  3. 在组件搜索框中输入“NavMeshSurface2D”,并添加该组件。

  4. 现在我们来配置这个NavMeshSurface2D组件。你会看到如下几个关键参数:

    • Agent Type:代理类型。这定义了一组导航属性(如高度、半径、坡度等)。对于纯2D,我们通常使用默认的“Humanoid”即可,或者点击“...”新建一个类型,主要关注“Agent Radius”(代理半径)和“Height”(高度,在2D中意义不大,但需要大于0)。
    • Collect Objects:收集对象。决定从哪些物体收集几何体。通常选择“Volume”或“All”。对于2D场景,我强烈推荐使用“Volume”,因为它允许你通过一个2D碰撞体来精确划定需要烘焙的区域,性能更好,控制更精准。
    • Size:当“Collect Objects”为“Volume”时,这个参数出现。它定义了收集区域的矩形大小。你可以手动输入数值,或者更方便的是:
      1. 点击组件上的“Add Component”按钮。
      2. 添加一个BoxCollider2D组件到“Navigation”这个游戏对象上。
      3. 回到NavMeshSurface2D组件,你会发现“Size”参数旁边出现了一个小圆圈图标。点击它,然后选择我们刚添加的BoxCollider2D组件。这样,NavMeshSurface2D就会自动使用这个BoxCollider2D的形状和大小作为烘焙区域。
      4. 调整这个BoxCollider2D的大小,让它完全覆盖你的“Ground”地面,但不要过大以免包含无用的空白区域。
    • Layer Mask:层掩码。这是极其重要的过滤器!它决定了NavMeshSurface2D会收集哪些层(Layer)上的物体的碰撞体来生成导航网格。
    • Use Geometry:使用几何体。选择使用物体的“Physics Colliders”(物理碰撞体)来生成网格。对于2D,就选这个。
    • Default Area:默认区域。表示生成网格的区域类型。通常就是“Walkable”(可行走)。

4.2 设置图层(Layer)与烘焙

NavMeshPlus通过图层来区分“可行走地面”和“障碍物”。这是一种清晰高效的管理方式。

  1. 创建图层:打开Unity的图层设置(Edit > Project Settings > Tags and Layers)。在“Layers”列表里,找到用户层(User Layers 8-31),定义两个新图层,例如:
    • Walkable(用于地面)
    • Obstacle(用于障碍物)
  2. 分配图层
    • 将“Ground”对象的图层设置为“Walkable”。
    • 将所有“Obstacle”对象的图层设置为“Obstacle”。
  3. 配置Layer Mask:回到“Navigation”对象上的NavMeshSurface2D组件。找到“Layer Mask”参数。这里需要仔细设置
    • 我们的目标是:收集“Walkable”层上的碰撞体作为“可行走区域”,同时收集“Obstacle”层上的碰撞体作为“需要被挖空(障碍)的区域”。
    • 因此,在“Layer Mask”中,你需要同时勾选“Walkable”和“Obstacle”。是的,两个都选。NavMeshSurface2D会收集这两个层上的所有碰撞体几何信息,但在生成网格时,它会将“Walkable”层上的区域标记为可行走,而“Obstacle”层上的区域则会被排除(挖空)。
  4. 首次烘焙:确保“Navigation”对象被选中,在NavMeshSurface2D组件底部,找到并点击“Bake”按钮。

如果一切配置正确,你将在场景视图中看到蓝色的导航网格覆盖了“Ground”区域,并且在“Obstacle”物体所在的位置出现了蓝色的“空洞”。这表示导航网格已经成功生成,角色可以在蓝色区域行走,并自动避开那些空洞(障碍物)。

踩坑记录:最常见的烘焙失败就是一片空白,看不到蓝色网格。请按以下顺序排查:

  1. 检查Layer Mask:确保勾选了包含地面碰撞体的图层(如“Walkable”)。
  2. 检查Collect Objects模式:如果用了“Volume”,确保附加的BoxCollider2D大小和位置正确覆盖了地面。
  3. 检查碰撞体:确保“Ground”和“Obstacle”对象上确实有Collider2D组件,并且没有勾选“Is Trigger”(除非你希望触发器也被视为障碍,这通常不是默认行为)。
  4. 检查代理半径:如果“Agent Radius”设置得太大,而你的通道很窄,可能会导致整个区域都无法行走,从而不生成网格。可以尝试调小代理半径(如从0.5调到0.1)再重新烘焙。

5. 让角色动起来:配置NavMeshAgent2D与基础移动脚本

导航网格烘焙好了,相当于地图已经绘制完成。接下来,我们需要给角色配备一个“导航仪”和“司机”,也就是NavMeshAgent2D组件和移动脚本。

5.1 添加并配置NavMeshAgent2D

  1. 选中你的“Player”角色对象。
  2. 在检查器中,点击Add Component,搜索并添加“NavMeshAgent2D”组件。
  3. 配置NavMeshAgent2D的关键参数。这些参数直接影响角色的移动行为:
    • Agent Type:必须和NavMeshSurface2D烘焙时使用的Agent Type一致(通常是默认的“Humanoid”)。
    • Speed:最大移动速度。
    • Angular Speed:转向速度(度/秒)。在2D中,这控制角色转向目标方向时的旋转速度。对于即时战略(RTS)风格的单位,可以设高一些(如720);对于需要平滑转身的角色,可以设低一些(如180)。
    • Acceleration:加速度。值越大,达到最大速度越快。
    • Stopping Distance:停止距离。当角色距离目标点多远时开始减速并停止。设为0会尝试精确走到目标点中心,有时可能导致在目标点附近轻微抖动。根据角色大小,设置一个小的正值(如0.05)通常更平滑。
    • Auto Braking:自动制动。勾选后,当角色接近目的地时会自动减速。通常建议勾选。
    • Radius:代理半径。这个参数至关重要!它必须小于或等于NavMeshSurface2D烘焙时所用Agent Type中定义的“Agent Radius”。如果角色的半径大于烘焙网格时允许的半径,它将无法在狭窄的通道中寻路。通常保持默认值(0.5)即可,但需要与烘焙设置匹配。
    • Priority:优先级。当多个Agent试图通过同一狭窄通道时,优先级高的会优先通过。用于群体移动时的避让逻辑。

5.2 编写基础移动脚本

NavMeshAgent2D组件提供了寻路能力,但它需要你通过代码来下达“去哪里”的指令。我们创建一个简单的脚本来测试。

  1. 在“Player”对象上创建一个新的C#脚本,命名为PlayerController2DSimpleAgentController
  2. 打开脚本,编写如下基础代码:
using UnityEngine; using NavMeshPlus.Components; // 注意命名空间! public class SimpleAgentController : MonoBehaviour { private NavMeshAgent2D agent; private Camera mainCamera; void Start() { // 获取组件引用 agent = GetComponent<NavMeshAgent2D>(); if (agent == null) { Debug.LogError("NavMeshAgent2D component not found on " + gameObject.name); } mainCamera = Camera.main; } void Update() { // 示例1:点击移动(常用于RTS、ARPG) if (Input.GetMouseButtonDown(0)) // 左键点击 { // 将鼠标屏幕坐标转换为世界坐标 Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition); // 设置代理的目标位置 agent.SetDestination(mouseWorldPos); } // 示例2:持续追踪目标(常用于敌人AI) // 如果你有一个公开的Transform变量target,可以这样写: // if (target != null) // { // agent.SetDestination(target.position); // } } // 一个公共方法,方便其他脚本调用,让角色移动到指定位置 public void MoveToPosition(Vector2 targetPosition) { if (agent != null && agent.isActiveAndEnabled) { agent.SetDestination(targetPosition); } } }
  1. 将脚本挂载到“Player”对象上。
  2. 运行游戏。现在,在Game视图中点击鼠标左键,你的角色就应该能自动寻路,绕过障碍物,移动到点击的位置了!

实操心得agent.SetDestination()是核心方法。调用它后,NavMeshAgent2D会在后台自动计算路径并控制角色移动。你不需要在Update中手动修改Transform.position。角色的移动、转向、加减速都由Agent组件根据你设置的参数(Speed, Angular Speed等)自动处理,这极大地简化了移动逻辑代码。

6. 高级功能与实战技巧

基础寻路跑通后,我们来看看NavMeshPlus一些更高级的用法和实战中必然会遇到的问题。

6.1 处理动态障碍物:NavMeshModifier与实时更新

静态障碍物在烘焙时就已经处理好了。但如果你的游戏里有玩家可以建造/拆除的墙、可以开关的门、或者可以移动的箱子,这些动态障碍物怎么办?

方案一:使用NavMeshModifier标记动态物体

这是处理简单动态障碍的推荐方法。你不需要每次障碍物变化都重新烘焙整个网格(那很耗性能),而是让Agent在寻路时动态避开这些物体。

  1. 创建一个会动态出现/消失的障碍物,比如一个“Box_Dynamic”。
  2. 为其添加BoxCollider2D
  3. 再添加一个NavMeshModifier组件(注意不是NavMeshModifierVolume2D)。
  4. NavMeshModifier组件中:
    • 勾选“Override Area”
    • 在“Area”下拉菜单中,选择“Not Walkable”。这告诉导航系统,这个物体占据的区域是不可行走的。
    • 确保“Affects Agent Type”包含了你的Agent类型(如Humanoid)。
  5. 现在,无论这个物体是开始时禁用后来启用,还是在游戏过程中移动,只要它处于激活状态且碰撞体开启,NavMeshAgent2D在计算路径时就会尝试绕开它。

方案二:使用NavMeshObstacle2D(如果未来版本支持)

在3D NavMesh中,NavMeshObstacle组件是处理动态障碍物的标准方式,它能创建更精确的规避形状。NavMeshPlus的实验版本可能包含或不完全支持类似的NavMeshObstacle2D。如果可用,它的用法类似:添加到动态物体上,设置形状和大小,Agent会自动避开。

方案三:手动更新NavMeshSurface(适用于大面积地形变化)

如果是一大片区域的地形发生了永久性改变(比如桥梁被炸毁),那么可能需要部分或全部重新烘焙导航网格。

  1. 获取你的NavMeshSurface2D实例。
  2. 调用其BuildNavMesh()UpdateNavMesh()方法(具体方法名需查看当前API)。这个方法可能会比较耗时,不建议每帧调用。

避坑指南:对于频繁移动的障碍物(比如来回巡逻的敌人),不建议将其直接设为导航障碍,因为这会导致所有其他Agent的路径频繁重新计算,性能开销大。更常见的做法是:移动的敌人本身也是一个NavMeshAgent2D,它们之间通过Agent的“避让”功能(基于半径和优先级)来相互避开,而不是把彼此当作静态障碍物纳入网格计算。

6.2 多区域与区域代价:实现复杂地形

想象一下,你的游戏里有草地、沼泽、公路。在草地上走正常速度,在沼泽里走得很慢,在公路上走得很快。这可以通过NavMesh的“区域(Area)”和“代价(Cost)”来实现。

  1. 定义区域:在Unity菜单栏,打开Window > AI > Navigation(这是Unity标准导航窗口,NavMeshPlus的部分设置与之共享)。在“Areas”标签页,你可以看到默认的区域列表(Walkable, Not Walkable, Jump等)。你可以点击“+”创建自定义区域,例如“Grass”, “Swamp”, “Road”。
  2. 为区域设置代价:每个区域都有一个“Cost”值。默认Walkable的Cost是1。你可以将“Swamp”的Cost设为3(意味着走过沼泽的距离相当于走3倍长的平地),将“Road”的Cost设为0.5(走得更快)。
  3. 在场景中标记区域
    • 对于使用“Volume”模式烘焙的NavMeshSurface2D,你可以在场景中放置带有NavMeshModifierVolume2D组件的物体。
    • 创建一个空物体,添加NavMeshModifierVolume2D组件。
    • 设置其BoxCollider2D的大小和位置,覆盖你想要标记的区域(比如一片沼泽地)。
    • 在组件中,勾选“Override Area”,并从下拉列表中选择你创建的“Swamp”区域。
  4. 重新烘焙:修改区域后,需要重新点击NavMeshSurface2D上的“Bake”按钮。烘焙后,你可以在场景视图中通过导航窗口的“Area”颜色覆盖图来查看不同区域(需在Navigation窗口的“Bake”页签下勾选“Show NavMesh”并在下拉框选择“Area”)。
  5. Agent感知代价NavMeshAgent2D在寻路时会自动计算路径的总代价,并倾向于选择总代价最低的路径。所以,即使从A到B,穿过沼泽是直线距离更短,但如果绕远走公路的总代价(距离*成本)更低,Agent可能会选择绕路。

6.3 常见问题排查与性能优化

问题1:角色在目标点附近抖动或打转

  • 原因:通常是因为“Stopping Distance”设置过小(为0),而Agent的“Radius”和“Speed”较高,导致它无法精确停在一点,不断微调位置。
  • 解决:适当增加“Stopping Distance”(如0.1到0.3)。或者,在脚本中,当Agent非常接近目标时(agent.remainingDistance < 0.1f),手动将agent.isStopped设为true来停止Agent。

问题2:角色卡在角落或两个障碍物之间

  • 原因:可能是烘焙时“Agent Radius”设置过小,导致生成的网格通道比Agent的实际物理半径还窄。也可能是障碍物的碰撞体之间有微小的缝隙。
  • 解决
    1. 检查烘焙用的“Agent Radius”是否小于或等于角色的NavMeshAgent2D.radius
    2. 在烘焙前,确保障碍物碰撞体之间没有可能导致Agent卡住的、比Agent直径更窄的缝隙。可以适当让障碍物碰撞体稍微重叠,或者使用NavMeshModifierVolume2D来定义一个明确的不可行走区域覆盖缝隙。
    3. 考虑启用或调整Agent的“Auto Traverse Off Mesh Link”和“Obstacle Avoidance”相关属性(如果NavMeshPlus版本支持),但2D中简单的本地避障可能不如3D成熟。

问题3:烘焙后,某些应该能走的地方没有蓝色网格

  • 原因:除了之前提到的Layer Mask和碰撞体问题,还可能是“烘焙区域”没有完全覆盖该地方。
  • 解决:检查NavMeshSurface2D上用于定义“Volume”的BoxCollider2D是否足够大。确保“Use Geometry”选项正确。

性能优化建议:

  • 分层烘焙:如果你的场景非常大,可以考虑使用多个NavMeshSurface2D,每个负责一个区域(如一个房间、一个楼层),然后通过脚本来激活/停用它们。这比烘焙一个巨大的网格更高效。
  • 简化碰撞体:导航网格的复杂度直接取决于用于烘焙的碰撞体网格的复杂度。对于不规则形状的障碍物,使用PolygonCollider2D时,尽量用最少的点来勾勒形状。避免使用高精度的碰撞体来烘焙导航。
  • 控制动态更新:尽量避免在运行时频繁调用完整的BuildNavMesh()。对于动态障碍,优先使用NavMeshModifier

7. 实战案例:构建一个简单的2D塔防敌人寻路

让我们把上面的知识串联起来,实现一个塔防游戏中敌人从出生点走向终点的经典寻路。

  1. 场景设置

    • 创建一个有曲折路径的2D地图(例如,一条用Sprite铺成的路,两边是障碍)。
    • 路径的起点放一个空物体,命名为“SpawnPoint”。
    • 路径的终点放一个空物体,命名为“EndPoint”(可以附加一个带有Collider2D的触发器来检测敌人到达)。
    • 为整个可行走的“路径”地面设置“Walkable”层,并为两旁的障碍物设置“Obstacle”层。
    • 使用NavMeshSurface2D(Volume模式)烘焙出路径的导航网格。
  2. 敌人预制体(EnemyPrefab)

    • 创建一个敌人精灵。
    • 添加NavMeshAgent2D组件,配置速度、加速度等。
    • 添加一个C#脚本EnemyAI
  3. 敌人AI脚本

using UnityEngine; using NavMeshPlus.Components; public class EnemyAI : MonoBehaviour { private NavMeshAgent2D agent; public Transform target; // 在Inspector中拖入EndPoint void Start() { agent = GetComponent<NavMeshAgent2D>(); if (target != null) { agent.SetDestination(target.position); } else { // 如果没有指定目标,可以尝试按标签查找 GameObject endPoint = GameObject.FindGameObjectWithTag("EndPoint"); if (endPoint != null) target = endPoint.transform; } } void Update() { // 可选:实时更新目标位置,如果目标是移动的 // if (target != null) agent.SetDestination(target.position); // 检测是否到达终点(通过距离判断) if (target != null && agent.remainingDistance <= agent.stoppingDistance) { // 敌人到达终点,触发扣血等逻辑 Debug.Log(gameObject.name + " reached the end!"); Destroy(gameObject); // 或触发其他事件 } } // 提供一个方法,可以在生成敌人时动态设置目标 public void SetTarget(Transform newTarget) { target = newTarget; if (agent != null) agent.SetDestination(target.position); } }
  1. 生成敌人:在“SpawnPoint”位置,写一个生成器脚本,定时实例化EnemyPrefab,并调用其SetTarget方法,将“EndPoint”的Transform传递过去。

运行游戏,敌人就会自动沿着你烘焙好的导航网格路径,从出生点智能地走向终点,完美绕过所有障碍。你可以通过修改烘焙区域、调整Agent参数(让某些敌人走得更慢但血量厚)来创造不同的敌人类型。

通过这个完整的流程,你应该已经掌握了使用NavMeshPlus为Unity 2D游戏添加智能寻路的核心技能。从工具导入、场景配置、网格烘焙,到Agent控制、动态障碍处理和高级区域功能,这套工作流能够应对绝大多数2D游戏的寻路需求。记住,关键是多动手尝试,根据自己游戏的具体情况调整参数,遇到问题时,回头检查图层、碰撞体和烘焙设置这三个最常出错的环节。