3、导航系统基础:NavMesh的生成与调试、导航代理配置、动态障碍物与导航链接
好,咱们今天聊聊导航系统。说实话,这是AI能“动起来”的第一步。没有导航,你的AI就是个睁眼瞎,连门都找不到。
我刚开始做AI时,总觉得导航嘛,不就是寻路算法吗?后来发现,真正让AI在复杂场景里走得像个人,靠的是导航系统这套基础设施。今天咱们就把NavMesh、NavAgent、动态障碍物和导航链接这几个核心概念讲透。
3.1 NavMesh的生成与调试
NavMesh,说白了就是一张“能走的地图”。它把场景中所有可行走的表面,抽象成一个个多边形。AI在这张图上寻路,比在原始几何体上快得多。
3.1.1 生成NavMesh
在Unreal里生成NavMesh很简单,但想生成得好,得懂几个关键参数。
// 在编辑器中操作:
// 1. 放置一个 NavMeshBoundsVolume
// 2. 调整它的大小,覆盖你的关卡
// 3. 按 P 键显示预览
// 4. 在 World Settings 中调整 Agent Radius / Agent Height
我个人习惯,先把BoundsVolume拉大一圈,覆盖所有可能行走的区域。然后按P键,看看生成的网格长什么样。
关键参数表:
| 参数 | 说明 | 我的建议值 |
|---|---|---|
| Agent Radius | 代理的半径,决定了能通过的最小缝隙 | 人形AI用 40-50 |
| Agent Height | 代理的高度,决定了能通过的最低高度 | 人形AI用 180-200 |
| Cell Size | 网格精度,越小越精细 | 默认10,室内场景可以降到5 |
| Max Slope | 最大可走坡度 | 45度,太陡的坡AI会卡住 |
嗯,这里要注意:Agent Radius 和 Cell Size 的关系。Cell Size 如果大于 Agent Radius,AI可能找不到路。我曾经遇到过,AI死活过不了一个门,后来发现是Cell Size设太大了,门缝被忽略了。
3.1.2 调试NavMesh
按P键显示NavMesh后,你看到的蓝色区域就是可行走区域。但光看颜色不够,我教你几个调试技巧。
- 显示路径:选中AI,按 ` 键打开控制台,输入 `ShowDebug AI`,就能看到AI当前的目标路径。
- 查看导航数据:在细节面板里,把 `NavData` 的 `DrawDebug` 打开,能看到每个多边形的边界。
- 手动测试寻路:在场景里放一个 `NavLinkProxy`,手动测试两点之间能不能走通。
我的调试习惯:
我会在场景里放几个“测试点”,让AI从A走到B。如果AI绕路了,或者卡住了,我就打开 `ShowDebug AI` 看路径点。很多时候,问题出在NavMesh的边界上——比如楼梯的边缘没生成好。
3.2 导航代理配置
NavMesh生成好了,接下来得告诉AI怎么用。这就是NavAgent的活了。
说白了,NavAgent就是AI的“身体参数”。它决定了AI能走多快、能转多快、能不能跳、能不能爬楼梯。
3.2.1 配置NavAgent
在AI角色的 `CharacterMovementComponent` 里,找到 `NavAgent` 相关的设置。
// 在蓝图中设置:
// 1. 打开你的AI角色蓝图
// 2. 找到 CharacterMovement 组件
// 3. 设置以下参数:
// 移动参数
Max Walk Speed: 600.0 // 走路速度
Max Acceleration: 2048.0 // 加速度
Braking Deceleration: 2048.0 // 刹车减速度
// 转向参数
Rotation Rate: (0.0, 0.0, 540.0) // 每秒转540度
bUseControllerDesiredRotation: true // 使用控制器旋转
// 导航参数
Agent Radius: 42.0
Agent Height: 192.0
Nav Agent Step Height: 50.0 // 能跨过的台阶高度
我个人建议,Agent Radius 和 Agent Height 一定要和NavMesh生成时保持一致。否则会出现“AI能走,但NavMesh说不能走”的尴尬情况。
我曾经踩过的坑:
有一次,我把AI的Agent Radius设成了40,但NavMesh生成时用的是50。结果AI在场景里到处乱撞,明明有路,它就是不走。查了半天,发现是参数不一致。从那以后,我都是把这两个参数做成同一个变量,统一管理。
3.2.2 多代理类型
如果你的游戏里有不同体型的AI(比如小兵和BOSS),你需要为它们分别生成NavMesh。
- 小兵:Agent Radius 30,Agent Height 150,能钻小洞
- BOSS:Agent Radius 100,Agent Height 300,只能走大路
- 飞行单位:不需要NavMesh,用简单的直线移动
在 `Project Settings > Navigation System` 里,可以添加多个 `Agent Types`。每个类型对应一张独立的NavMesh。
3.3 动态障碍物与导航链接
静态的NavMesh只能处理固定场景。但游戏里,门会开、箱子会移动、桥会断。这时候就需要动态障碍物和导航链接了。
3.3.1 动态障碍物
动态障碍物,说白了就是“会动的阻挡物”。比如一个箱子,被推走后,AI应该能走过去了。
在Unreal里,实现动态障碍物有两种方式:
- 使用 `NavModifierVolume`:在场景里放一个Volume,当它移动时,NavMesh会自动更新。
- 使用 `NavLinkComponent`:在动态物体上挂一个NavLink,告诉AI“这里可以走”或“这里不能走”。
// 在C++中动态更新NavMesh:
// 当障碍物移动时,调用以下函数
void AMyDynamicObstacle::OnMoved()
{
// 通知导航系统重新计算这块区域
UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent(GetWorld());
if (NavSys)
{
// 更新障碍物周围的NavMesh
NavSys->UpdateNavOctreeElement(this);
// 或者强制重建整个NavMesh
// NavSys->Build();
}
}
我的经验:
动态障碍物不要频繁更新NavMesh,性能扛不住。我一般只在障碍物停止移动后,才触发一次更新。比如箱子被推到位了,再更新。如果箱子一直在动,那就用 `NavLinkComponent` 临时标记为不可通行。
3.3.2 导航链接
导航链接,就是“连接两个NavMesh区域的桥梁”。比如楼梯、跳台、传送门。
在Unreal里,用 `NavLinkProxy` 来实现。你只需要指定两个点:起点和终点。AI走到起点时,会自动“跳”到终点。
// 在蓝图中设置NavLinkProxy:
// 1. 放置一个 NavLinkProxy 到场景中
// 2. 设置 Start Point 和 End Point
// 3. 设置 Link Direction(单向/双向)
// 4. 设置 Smart Link(是否智能链接)
// 在C++中自定义导航链接行为:
void AMyNavLinkProxy::OnSmartLinkReached(AActor* PathFollowingAgent, const FVector& Destination)
{
// 这里可以写自定义的移动逻辑
// 比如:播放跳跃动画,然后传送到终点
// 通知AI继续移动
UAIBlueprintHelperLibrary::SimpleMoveToActor(PathFollowingAgent, Destination);
}
嗯,这里要注意:Smart Link 和普通 Link 的区别。普通Link是瞬间传送,AI会直接出现在终点。Smart Link则允许你控制移动过程,比如播放一个跳跃动画。
导航链接的常见用途:
- 楼梯:用NavLink连接楼梯的每一级台阶
- 跳台:AI从A点跳到B点
- 传送门:AI穿过门,瞬间传送到另一个区域
- 电梯:AI进入电梯,电梯上升后,AI从新位置出来
3.4 实战:让AI绕过动态障碍物
咱们来个小实战。假设场景里有一个巡逻的AI,中间有一扇门。门打开时,AI能通过;门关闭时,AI绕路。
// 门的蓝图逻辑:
// 1. 门打开时,移除NavModifierVolume
// 2. 门关闭时,添加NavModifierVolume
void AMyDoor::OpenDoor()
{
// 移除阻挡
if (NavModifier)
{
NavModifier->DestroyComponent();
}
// 播放开门动画
PlayDoorAnimation(true);
}
void AMyDoor::CloseDoor()
{
// 添加阻挡
if (!NavModifier)
{
NavModifier = NewObject(this);
NavModifier->RegisterComponent();
}
// 播放关门动画
PlayDoorAnimation(false);
}
AI那边不用做任何修改。NavMesh会自动更新,AI会重新计算路径。如果门关了,AI会走另一条路。
性能警告:
频繁更新NavMesh会导致卡顿。我建议:
- 门开关时,延迟0.5秒再更新NavMesh
- 如果场景里有很多动态障碍物,考虑使用 `NavLinkComponent` 代替 `NavModifierVolume`
- 对于不重要的障碍物,直接让AI忽略它,用碰撞检测来处理
好了,导航系统的基础就这些。说白了,NavMesh是地图,NavAgent是身体参数,动态障碍物和导航链接是“变通”的手段。把这几个东西搞明白了,你的AI就能在复杂场景里自由行走了。
下一章,咱们聊聊行为树——让AI“思考”起来。