2、NavMesh基础:Unity NavMesh组件介绍、烘焙NavMesh、设置可行走区域
好,咱们正式开始聊寻路。说到Unity里的寻路,绕不开的就是NavMesh。我刚开始用Unity做AI时,第一反应是自己写A*算法,折腾了好几天,结果发现Unity自带的这套系统已经相当成熟了。说白了,NavMesh就是一张“能走的地图”,AI角色在这张图上移动,省心又高效。
2.1 Unity NavMesh组件介绍
Unity的寻路系统核心就三个组件:NavMesh Agent、NavMesh Obstacle、NavMesh Surface。嗯,这里要注意,新版Unity(2018.4之后)把烘焙功能从旧版的Window菜单移到了组件里,很多人刚升级时找不到,我当初也懵了一下。
2.1.1 NavMesh Agent
这个组件挂在需要移动的角色身上。它负责接收目标点,然后沿着NavMesh自动寻路。我个人习惯把Agent看作“自动驾驶模块”——你告诉它去哪,它自己算路径、避障、绕弯。
关键参数我列一下:
| 参数 | 作用 | 我的建议 |
|---|---|---|
| Radius | 角色半径,决定能通过多窄的通道 | 别设太大,否则过门框会卡住 |
| Height | 角色高度,决定能钻多矮的洞 | 和碰撞体高度保持一致 |
| Speed | 移动速度 | 单位/秒,我一般设3-6 |
| Stopping Distance | 离目标多近时停下 | 近战设0.5,远程设2-3 |
| Auto Repath | 路径失效时自动重新计算 | 建议开启,否则角色会傻站着 |
2.1.2 NavMesh Obstacle
这个组件挂在动态障碍物上,比如会移动的箱子、可开关的门。它和Agent的区别在于:Obstacle不自己走路,它只是“挡路”。
我记得有个坑——如果你把Obstacle的Carve选项勾上,它会在NavMesh上“挖洞”,让Agent绕开。但Carve的性能开销不小,场景里超过20个动态障碍物同时Carve,帧率会明显掉。我的经验是:静态障碍物直接烘焙进NavMesh,只有真正会移动的才用Obstacle。
2.1.3 NavMesh Surface
这是新版Unity用来烘焙NavMesh的组件。把它挂在地面上,点击Bake按钮,系统就会自动生成可行走区域。说白了,它就是“画地图”的工具。
参数里有个Agent Radius,这个值决定了NavMesh边缘离墙有多远。设大了,角色贴不了墙;设小了,角色会卡进墙角。我一般设0.3-0.5,具体看你角色的大小。
2.2 烘焙NavMesh
烘焙听起来高大上,其实就是让Unity计算哪些地方能走、哪些不能走。操作很简单,但细节决定成败。
2.2.1 烘焙步骤
- 选中地面或场景中的静态物体,在Inspector里勾上
Navigation Static。 - 给地面挂上
NavMesh Surface组件。 - 点击
Bake按钮,等几秒钟。 - 按
Gizmos开关,查看蓝色区域——那就是能走的地方。
你想想看,如果地面没勾Navigation Static,Unity根本不会把它算进烘焙范围。我刚开始学时就犯过这错,烘焙了半天,NavMesh一片空白,还以为引擎坏了。
2.2.2 常见问题
- 烘焙后地面有空洞: 检查地面是不是有缝隙,或者地面厚度不够。NavMesh要求地面有一定厚度(默认0.2米),薄了会漏。
- 角色走到边缘就掉下去: 检查
Voxel Size,设小一点可以提升边缘精度,但烘焙时间会变长。 - 楼梯上不去: 楼梯的每个台阶都要勾
Navigation Static,并且台阶高度不能超过Agent的Step Height(默认0.75)。
2.3 设置可行走区域
不是所有地面都能走。比如沼泽、岩浆、深水区,这些地方角色应该绕开。Unity通过Area系统来区分不同区域。
2.3.1 Area类型
打开Window -> AI -> Navigation,在Areas选项卡里可以看到默认的三种:
- Walkable: 可行走,默认所有地面都是这个。
- Not Walkable: 不可行走,比如墙壁、悬崖。
- Jump: 可跳跃通过的区域,需要配合Off-Mesh Link使用。
你可以自己添加自定义Area,比如Danger(危险区)、Slow(减速区)。我个人习惯把沼泽设为Slow,然后让Agent经过时减速,而不是完全绕开——这样更真实。
2.3.2 设置方法
- 选中地面物体,在Inspector里找到
Navigation Area下拉菜单。 - 选择你想要的Area类型,比如
Not Walkable。 - 重新烘焙NavMesh,Unity会自动排除这些区域。
举个例子:你有一个喷泉,想让角色绕开。把喷泉的水面设为Not Walkable,烘焙后NavMesh就会在喷泉周围自动生成一个“洞”。
2.3.3 代码控制区域代价
有时候你不想完全禁止行走,只是希望角色“尽量”避开。这时候可以用Area Cost(区域代价)。代价越高,角色越不愿意走。
// 设置沼泽区域的代价为10(默认是1)
NavMesh.SetAreaCost(NavMesh.GetAreaFromName("Swamp"), 10);
// 设置危险区域的代价为50
NavMesh.SetAreaCost(NavMesh.GetAreaFromName("Danger"), 50);
代价越大,路径规划时越倾向于绕路。但注意,如果代价设得太大(比如999),角色可能会绕很远的路,看起来反而不自然。我一般控制在3-10之间,既避开又不至于太夸张。
好了,这一章的内容就这些。记住:烘焙前先检查静态标记,设Area时别忘重新烘焙,代价别设太极端。下一章我们聊Off-Mesh Link,让角色能跳、能爬、能翻墙——那才是寻路系统的进阶玩法。