Unity_导航网格
Unity导航网格
1. 导航网格工具概述
1.1 基本概念
- 导航网格(Navigation Mesh):Unity内置的AI寻路系统
- 作用:为游戏中的AI角色提供自动寻路能力
- 特点:可视化编辑、实时预览、性能优化
1.2 四个核心模块
1.2.1 Agents(代理页签)
- 作用:用于配置寻路代理信息
- 功能:定义AI角色的物理属性和移动参数
- 主要设置:
- Agent Types:代理类型(如Humanoid)
- Name:代理名称
- Radius:代理半径(影响寻路精度)
- Height:代理高度(决定可通过的通道高度)
- Step Height:可跨越的台阶高度
- Max Slope:可攀爬的最大坡度
1.2.2 Areas(导航地区页签)
- 作用:配合Object页签使用,定义导航区域类型
- 功能:设置不同区域的寻路消耗和通行规则
- 主要设置:
- Name:区域名字,用于标识不同类型的导航区域
- Cost:寻路消耗,数值越高AI越不愿意走该区域
- 应用场景:区分道路、草地、水域等不同地形类型
1.2.3 Bake(导航数据烘焙页签)
- 作用:生成导航网格数据
- 功能:根据场景几何体和代理设置计算可行走区域
- 核心参数:
- Agent Properties:代理属性设置
- Agent Radius:代理半径(0.5)
- Agent Height:代理高度(2)
- Max Slope:最大坡度(45°)
- Step Height:最小楼梯高度(0.4)
- Generated Off Mesh Links:生成非网格连接
- Drop Height:掉落高度(0)
- Jump Distance:跳跃距离(0)
- Advanced Settings:高级设置
- Voxel Size:立体像素大小(影响精度和性能)
- Min Region Area:最小区域面积(2)
- Height Mesh:高度网格构建开关
- Agent Properties:代理属性设置
1.2.4 Object(场景对象设置页签)
- 作用:配置场景中具体对象的导航属性
- 功能:设置哪些对象参与导航网格生成
- 主要设置:
- Scene Filter:场景过滤器,配合Hierarchy窗口使用
- All:显示场景上所有对象
- Mesh Renderers:显示挂载网格渲染器的对象
- Terrains:显示挂载地形脚本的对象
- Navigation Static:导航静态物体开关
- Generate OffMeshLinks:生成网格连接点开关
- Navigation Area:导航区域选择,配合Areas页签使用
- Scene Filter:场景过滤器,配合Hierarchy窗口使用
1.3 工作流程
┌─────────────────────────────────────────────────────────────┐
│ Unity导航网格工作流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 配置代理 │───▶│ 设置区域 │───▶│ 对象配置 │ │
│ │ Agents │ │ Areas │ │ Object │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 烘焙生成 │◀───│ 预览检查 │◀───│ 应用寻路 │ │
│ │ Bake │ │ Scene View │ │ NavMesh │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
1.4 使用注意事项
- 性能考虑:Voxel Size越小精度越高,但内存占用和烘焙时间会显著增加
- 区域设置:合理设置Navigation Area和Cost值,避免AI选择不合理的路径
- 对象标记:确保需要参与导航的对象都正确标记为Navigation Static
- 烘焙优化:大型场景建议分区域烘焙,提高工作效率
2. 导航网格组件
2.1 组件架构概述
- 核心组件:构成Unity导航系统的功能模块
- 作用:为AI角色提供寻路、避障、路径规划等能力
- 特点:模块化设计、易于配置、性能优化
2.2 主要组件类型
2.2.1 NavMeshAgent(导航网格代理)
- 作用:AI角色的核心寻路组件
- 功能:自动寻路、避障、路径规划
- 主要属性:
- Agent Type:代理类型设置
- Speed:移动速度
- Angular Speed:旋转速度
- Acceleration:加速度
- Stopping Distance:停止距离
- Radius:代理半径
- Height:代理高度
2.2.1.1 基础代码示例
using UnityEngine;
using UnityEngine.AI;public class NavMeshAgentDemo : MonoBehaviour
{private NavMeshAgent agent;public Transform target; // 目标位置void Start(){// 获取或添加NavMeshAgent组件agent = GetComponent<NavMeshAgent>();if (agent == null){agent = gameObject.AddComponent<NavMeshAgent>();}// 基础属性设置agent.speed = 5f; // 移动速度agent.angularSpeed = 120f; // 旋转速度agent.acceleration = 8f; // 加速度agent.stoppingDistance = 1f; // 停止距离agent.radius = 0.5f; // 代理半径agent.height = 2f; // 代理高度}void Update(){// 设置目标位置if (target != null){agent.SetDestination(target.position);}}
}
2.2.1.2 高级功能代码示例
using UnityEngine;
using UnityEngine.AI;public class AdvancedNavMeshAgent : MonoBehaviour
{private NavMeshAgent agent;public Transform[] waypoints; // 路径点数组private int currentWaypoint = 0;void Start(){agent = GetComponent<NavMeshAgent>();SetupAgent();}void SetupAgent(){// 高级属性设置agent.avoidancePriority = 50; // 避障优先级agent.autoTraverseOffMeshLink = true; // 自动通过OffMeshLinkagent.autoRepath = true; // 自动重新寻路agent.pathfindingIterationsPerFrame = 100; // 每帧寻路迭代次数}void Update(){// 巡逻逻辑if (waypoints.Length > 0){if (agent.remainingDistance < 0.5f){currentWaypoint = (currentWaypoint + 1) % waypoints.Length;agent.SetDestination(waypoints[currentWaypoint].position);}}}// 手动寻路到指定位置public void MoveTo(Vector3 destination){if (agent.isOnNavMesh){agent.SetDestination(destination);}}// 检查是否到达目标public bool HasReachedDestination(){return !agent.pathPending && agent.remainingDistance <= agent.stoppingDistance;}// 停止移动public void StopMoving(){agent.isStopped = true;}// 恢复移动public void ResumeMoving(){agent.isStopped = false;}
}
2.2.2 NavMeshObstacle(导航网格障碍物)
- 作用:动态障碍物组件
- 功能:实时更新导航网格,创建动态障碍
- 主要属性:
- Shape:障碍物形状
- Size:障碍物尺寸
- Carving:是否雕刻导航网格
- Movement Threshold:移动阈值
2.2.2.1 动态障碍物组件的用途
- 游戏场景应用:在游戏场景中,经常有这样的功能:
- 场景中有一扇门,如果这扇门没有被破坏,AI角色无法自动寻路到门后的场景
- 只有当门被破坏后,AI角色才能通过到下一个场景
- 像门这样的对象本身不需要进行寻路,所以不需要给它们添加NavMeshAgent脚本
- 在这种情况下,使用"动态障碍物组件"(NavMeshObstacle)来实现这个功能
2.2.2.2 动态障碍物组件的使用方法
- 基本设置:为需要动态阻挡AI的对象添加NavMeshObstacle组件
- 形状配置:根据对象的实际形状设置障碍物的几何形状
- 尺寸调整:调整障碍物的尺寸以准确反映阻挡范围
- 雕刻设置:启用Carving功能,让障碍物能够实时更新导航网格
- 移动阈值:设置Movement Threshold,控制障碍物移动多少距离后才更新导航网格
2.2.2.3 代码示例
using UnityEngine;
using UnityEngine.AI;public class DynamicObstacle : MonoBehaviour
{private NavMeshObstacle obstacle;void Start(){// 获取或添加NavMeshObstacle组件obstacle = GetComponent<NavMeshObstacle>();if (obstacle == null){obstacle = gameObject.AddComponent<NavMeshObstacle>();}// 基础设置obstacle.shape = NavMeshObstacleShape.Box; // 设置为盒子形状obstacle.size = Vector3.one; // 设置尺寸obstacle.carving = true; // 启用雕刻功能obstacle.movementThreshold = 0.1f; // 移动阈值}// 动态启用/禁用障碍物public void SetObstacleActive(bool active){if (obstacle != null){obstacle.carving = active;}}// 动态调整障碍物尺寸public void UpdateObstacleSize(Vector3 newSize){if (obstacle != null){obstacle.size = newSize;}}// 门被破坏时的处理public void OnDoorDestroyed(){// 禁用障碍物,让AI可以通过SetObstacleActive(false);// 或者直接销毁组件if (obstacle != null){Destroy(obstacle);}}
}
2.2.3 NavMeshSurface(导航网格表面)
- 作用:生成和管理导航网格表面
- 功能:动态生成、更新导航网格
- 主要属性:
- Collection Object:收集对象
- Use Geometry:使用几何体类型
- Default Area:默认区域
- Layer Mask:层级遮罩
2.2.4 NavMeshLink(导航网格连接)
- 作用:连接分离的导航网格区域
- 功能:创建跳跃、掉落等特殊移动连接
- 主要属性:
- Start Point:起始点
- End Point:结束点
- Width:连接宽度
- Cost Override:成本覆盖
2.2.4.1 详细属性说明
- Start(起始点):连接点的起始位置,指定为Transform组件
- End(结束点):连接点的结束位置,指定为Transform组件
- Cost Override(覆盖消耗值):
- 负值或0:使用所属Area的寻路消耗
- 正值:Area的寻路消耗 × 正值 = 该连接点的寻路消耗
- 用途:自定义连接点的寻路消耗,解决"步行"和"连接点"都能到达目标,但希望优先选择步行区域的情况
- Bi Directional(双向连接点):
- 启用:可以从Start到End,也可以从End到Start
- 禁用:只能从Start到End单向通行
- Activated(启用连接点):是否启用该连接点,禁用时在自动寻路中无效
- Auto Update Positions(自动更新位置):
- 启用:起始和结束位置变化时,导航网格自动更新
- 禁用:即使位置变化,仍按初始位置计算
- Navigation Area(导航区域):指定连接点所属的导航区域类型,影响哪些代理可以使用以及默认消耗
2.2.4.2 代码示例
using UnityEngine;
using UnityEngine.AI;public class NavMeshLinkController : MonoBehaviour
{public Transform startPoint;public Transform endPoint;public float costOverride = -1f;public bool biDirectional = true;public bool activated = true;public bool autoUpdatePositions = false;private OffMeshLink offMeshLink;void Start(){CreateOffMeshLink();}void CreateOffMeshLink(){// 创建OffMeshLink组件offMeshLink = gameObject.AddComponent<OffMeshLink>();// 设置起始和结束点offMeshLink.startTransform = startPoint;offMeshLink.endTransform = endPoint;// 设置连接点属性offMeshLink.costOverride = costOverride;offMeshLink.biDirectional = biDirectional;offMeshLink.activated = activated;offMeshLink.autoUpdatePositions = autoUpdatePositions;// 设置导航区域(默认为Walkable)offMeshLink.area = 0; // 0 = Walkable}// 动态启用/禁用连接点public void SetLinkActive(bool active){if (offMeshLink != null){offMeshLink.activated = active;}}// 动态设置成本覆盖public void SetCostOverride(float cost){if (offMeshLink != null){offMeshLink.costOverride = cost;}}// 检查连接点是否有效public bool IsLinkValid(){return offMeshLink != null && offMeshLink.activated && offMeshLink.startTransform != null && offMeshLink.endTransform != null;}
}
2.2.4.3 使用场景示例
// 跳跃连接点示例
public class JumpLink : MonoBehaviour
{public Transform jumpStart;public Transform jumpEnd;public float jumpCost = 2f; // 跳跃消耗较高void Start(){var link = gameObject.AddComponent<OffMeshLink>();link.startTransform = jumpStart;link.endTransform = jumpEnd;link.costOverride = jumpCost;link.biDirectional = true;link.activated = true;}
}// 单向连接点示例(如滑梯)
public class SlideLink : MonoBehaviour
{public Transform slideStart;public Transform slideEnd;void Start(){var link = gameObject.AddComponent<OffMeshLink>();link.startTransform = slideStart;link.endTransform = slideEnd;link.costOverride = 0.5f; // 滑梯消耗较低link.biDirectional = false; // 单向滑行link.activated = true;}
}