Home Navmesh
Post
Cancel

Navmesh

新版组件式导航系统

  1. 新版的组件式导航系统,功能比原版导航系统更多,有空可以看看。

Unity - Manual: NavMesh building components

Navigation and Pathfinding

导航系统几大组成 
NavMesh导航网格,与具体的场景关联
NavMesh Agent导航代理,挂载到需要导航功能的角色上
NavMesh Obstacle动态障碍物
NavMesh OffMeshLink导航链接,允许在不连通的区域之间建立链接
  1. 导航网格 Bake 的数据来源为 地形(Terrain)网格 (Mesh),不需要 Collider。
  2. 导航网格 Bake 使用的算法是[[平面多边形的三角剖分算法]],其结果为用很多三角形表示的凸多边形平面。
预定义Agent
  1. 打开 Window -> AI -> Navigation -> Agents,设置代理参数。
定义导航区域
  1. 打开 Window -> AI -> Navigation -> Areas,定义导航区域。
  2. 例如,宁可绕一些远路也不要横穿沼泽,此时地形的Cost(代价)参数就派上用场了。如可以给草原区较低的Cost,而给沼泽和密林区较高的Cost。
  3. A星等寻路算法在计算路径时会充分考虑通过每个区域的Cost,从而选择总Cost相对较小的导航线路。
设置导航区域
  1. 把场景中与导航相关的静态 Terrain 或 Mesh 设置成 Navigation Static,包括地面,斜坡,楼梯,墙体,静态障碍物等。
  2. 打开 Window -> AI -> Navigation -> Object
  3. 选中场景中作为地面的 Terrain 或 Mesh,设置为 Walkable,勾选是否生成导航链接。
  4. 选中障碍物 Mesh,设置为 Not Walkable
  5. 设置其他在 Areas 标签中定义好的 Areas。
Bake导航网格
  1. 打开 Window -> AI -> Navigation -> Bake
  2. 设置好代理参数并Bake!

image-20230205205216275

  1. Bake 好的网格数据保存在场景所在文件夹下的 NavMesh.asset 文件中。
1
2
3
// 采样导航网格上距离目标点指定范围内的一个可行的点
bool succeed = NavMesh.SamplePosition(targetPos, out var hit, patrolRange, 1);
Vector3 wayPoint = hit.position;
Agent和碰撞体
  1. 角色的碰撞体积一般用胶囊体表示,这个胶囊体的半径应该与代理半径一致或更小一些。
  2. 碰撞体半径大于代理半径,就可能出现导航系统认为能通过的窄路却被碰撞体阻挡的情况。
  3. 角色站立时有1.8米,下蹲后可以通过0.9米高的小洞,那么导航参数也应当考虑到角色下蹲移动的情况。
Agent组件配置
  1. 为Agent角色,添加 NavMeshAgent 组件。
  2. 组件参数: image-20230205205240902
Agent常用属性

image-20230205205252597

Agent API 接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 设置目标点
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if ( Physics.Raycast(ray, out RaycastHit hit))
{
    agent.destination = hit.point; 
}

// 获取/设置当前速度
agent.velocity = Vector.Forward;
float v = agent.velocity.sqrMagnitude; // 向量长度的平方,速度快
// 只是单纯比较向量之间的大小的话,建议使用Vector3.sqrMagnitude进行比较

// 是否处于导航链接路径上,使用它判断是否需要播放跳跃动画
agent.isOnOffMeshLink;

// 获取/设置最大速率
agent.speed = 2.5f;

// 使agent停下来/重新活动
agent.isStopped = false/true;

  1. 静态障碍物在 Bake 时就已经处理好,会在 NavMesh 上挖洞,不需要其他处理。
  2. 动态障碍物需要添加 NavMesh Obstacle 组件。
动态障碍物影响导航的方式

image-20230205205303676

  1. 阻碍模式:不勾选 Carve;障碍物对导航网格本身无影响,NavMesh Agent 会利用避障算法尽可能地规避它。优点是没有重新计算导航层的性能开销,性能好;缺点是障碍物较多较大时,效果可能不好。
  2. 阻碍方式适合有一定速度,体积不大的物体。 例如:角色过马路时路上的汽车等运动的小障碍。

  3. 打洞模式:勾选 Carve;障碍物会影响导航网格,在导航网格上“打洞”,Agent计算路径时会避开有洞的位置。
  4. 打洞方式适合静态的,运动频率特别低的物体。 例如:道路被掉落的石块堵死。

  5. 自动打洞模式:在勾选了 Carve Only Stationary 的前提下,当物体移动距离超过了 Move Threshold 的值则取消打洞;当物体的静止时间超过了 Time To Stationary 的值,就可以被看作暂时固定,切换到固定状态时会进行打洞。
  1. 导航链接是在 NavMesh 基础上添加路径或捷径。
  2. 例如:角色不用走楼梯下楼,可以直接从二楼跳下;角色可以直接跨越两个独立的NavMesh,走过 NavMesh 不连通的路径等。
自动生成导航链接
  1. 打开 Window -> AI -> Navigation -> Object,选中场景中要生成导航链接的 Terrain 或 Mesh,勾选 Generate OffMeshLinks。
  2. 打开 Window -> AI -> Navigation -> Bake,设置 Agent 的 Drop Height(最大下落高度),Jump Distance(最远跳跃距离)。
  3. 重新 Bake 导航网格。
手动生成导航链接
  1. 自动生成导航链接很方便,但不易控制,很容易生成大量链接。如果仅在个别地方需要链接,可以手动生成导航链接。
  2. 场景中新建一个空物体,添加 Off Mesh Link 组件,新建两个子物体分别作为链接的起点和终点。
  3. Bi Directional - 是否为双向链接。

导航与动画

  1. 设置 agent.velocity,使用速度的方向和大小来匹配移动动画。
  2. 使用 agent.isOnOffMeshLink,根据角色是否处于导航链接路径上,判断是否需要播放跳跃动画。

注意事项

  1. Agen抖动一般是因为目标不可达,检查一下是否地面以下有Bake的导航网格被覆盖掉了,使用SamplePosition采样一下目标点,再把目标传给Agent
  2. agent.radius = 0; 可以防止agent死亡后还阻挡玩家
  3. [[刚体]] 和 NavMeshAgent 会有冲突, 同时挂载时要把 IsKinematic 勾上,使刚体称为运动学刚体,控制时调用NavMeshAgent的方法。
This post is licensed under CC BY 4.0 by the author.