导航寻路系统

17.1 NavMesh 概述

NavMesh(导航网格)是 Unity 内置的寻路系统,将场景烘焙为网格数据,AI 角色可以自动计算路径并移动到目标。

核心组件

组件 作用
NavMesh 场景的导航网格数据
NavMesh Agent 角色的寻路代理
NavMesh Obstacle 动态障碍物
Off-Mesh Link 跳跃/跨越的链接(沟壑、围栏)

17.2 烘焙 NavMesh

设置步骤

  1. 选中场景中可作为地面的物体,Inspector 顶部勾选 Navigation Static
  2. Window → AI → Navigation 打开导航面板
  3. Bake 标签页配置参数:
参数 说明
Agent Radius 代理半径(影响可通行的窄道)
Agent Height 代理高度
Max Slope 最大可爬坡度数
Step Height 最大跨步高度
Min Region Area 最小区域面积(小于此值的区域视为不可达)
  1. 点击 Bake 按钮生成 NavMesh

烘焙后可在 Scene 视图中看到蓝色覆盖层,表示可行走区域。


17.3 NavMeshAgent 组件

添加和配置

给角色添加 NavMeshAgent 组件,配置移动参数:

属性 说明
Speed 移动速度
Angular Speed 旋转速度
Acceleration 加速度
Stopping Distance 停止距离(到达目标点的容忍距离)
Auto Braking 到达目标时自动减速
Obstacle Avoidance 障碍物躲避等级

基础寻路

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class EnemyAI : MonoBehaviour
{
private NavMeshAgent agent;

[SerializeField] private Transform target;
[SerializeField] private float updateInterval = 0.5f;
private float timer;

void Start()
{
agent = GetComponent<NavMeshAgent>();
}

void Update()
{
// 定期更新目标位置(减少计算)
timer += Time.deltaTime;
if (timer >= updateInterval)
{
timer = 0f;
agent.SetDestination(target.position);
}

// 检测是否到达
if (!agent.pathPending && agent.remainingDistance <= agent.stoppingDistance)
{
if (!agent.hasPath || agent.velocity.magnitude < 0.1f)
{
// 到达目标,执行攻击等逻辑
Attack();
}
}
}

private void Attack()
{
Debug.Log("攻击玩家!");
}
}

17.4 寻路状态与路径信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 路径状态
bool isOnNavMesh = agent.isOnNavMesh; // 是否在 NavMesh 上
bool hasPath = agent.hasPath; // 是否有路径
bool isPathStale = agent.isPathStale; // 路径是否已过期(需重新计算)
bool pathPending = agent.pathPending; // 是否正在计算路径
NavMeshPathStatus pathStatus = agent.pathStatus; // 路径状态

// 路径信息
float remainingDistance = agent.remainingDistance; // 剩余距离
float stoppingDistance = agent.stoppingDistance;
Vector3 desiredVelocity = agent.desiredVelocity; // 期望速度方向
Vector3 nextPosition = agent.nextPosition; // 下一步位置

// 手动控制
agent.isStopped = true; // 停止移动
agent.ResetPath(); // 重置路径
agent.Warp(newPos); // 瞬间移动到新位置(不触发寻路)

// 路径可视化
NavMeshPath path = new NavMeshPath();
if (NavMesh.CalculatePath(startPos, endPos, NavMesh.AllAreas, path))
{
for (int i = 0; i < path.corners.Length - 1; i++)
{
Debug.DrawLine(path.corners[i], path.corners[i + 1], Color.green, 1f);
}
}

17.5 动态障碍物

NavMeshObstacle 组件让移动物体影响寻路:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class MovingObstacle : MonoBehaviour
{
private NavMeshObstacle obstacle;

void Start()
{
obstacle = GetComponent<NavMeshObstacle>();
obstacle.carving = true; // 在 NavMesh 上刻出空洞
}

void Update()
{
// 移动障碍物
transform.position = new Vector3(
Mathf.Sin(Time.time) * 5f,
0,
transform.position.z
);

// 当障碍物移动时,NavMesh 自动更新空洞位置
}
}

carving = true 会持续在运行时的 NavMesh 中更新空洞,性能消耗随障碍物数量增加。


Off-Mesh Link 用于连接 NavMesh 上不连续的区域(跳跃、爬梯子)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 创建:选中 GameObject → Component → Navigation → Off-Mesh Link
// 设置 Start 和 End 位置,以及 Bi Directional(是否双向)

void Start()
{
agent.autoTraverseOffMeshLink = true; // 自动跨越 Off-Mesh Link
}

// 自定义 Off-Mesh Link 行为
void Update()
{
if (agent.isOnOffMeshLink)
{
StartCoroutine(TraverseLink());
}
}

IEnumerator TraverseLink()
{
OffMeshLinkData data = agent.currentOffMeshLinkData;
Vector3 startPos = agent.transform.position;
Vector3 endPos = data.endPos + Vector3.up * 1f;
float elapsed = 0f;
float duration = 1f;

while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
agent.transform.position = Vector3.Lerp(startPos, endPos, t);
yield return null;
}

agent.CompleteOffMeshLink(); // 完成跨越
}

17.7 本章小结

  • NavMesh 通过烘焙生成可行走区域,搭配 NavMeshAgent 实现 AI 寻路
  • SetDestination 是核心 API,设置目标位置
  • NavMeshObstacle 让动态物体影响寻路
  • Off-Mesh Link 连接 NavMesh 不连续区域
  • 合理的区域遮罩(Area Mask)控制角色的可通行区域

练习题

  1. 烘焙一个简单的场景,让一个角色 AI 自动走到鼠标点击位置
  2. 实现”巡逻”逻辑:AI 在多个路点之间循环移动
  3. 添加一个可推动的箱子(NavMeshObstacle),观察 AI 避让效果
  4. 在场景中设置两个不同区域层(如地面和水面),让 AI 避开水面
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
Unity3D开发基础教程 系列
第 17/20 篇
分享: