NavMesh导航寻路使用
一:NavMesh基本导航寻路
二:OffMesh Link使用
三:网格分层的使用
四:动态更改路线
五:NavMeshObstacle组件使用
一:NavMesh基本导航寻路
1.1 基础使用
导航寻路技术是一种系统内置的强大寻路算法系统,可以方便快捷的开发出各种复杂的应用,被大量使用在各种RPG、射击、动作、冒险游戏中。如果没有这种内置插件,我们需要使用3D数学进行复杂的数学计算,或者使用第三方插件(如A星算法)。
在Unity编辑器中,我们选择菜单栏Window->Navigation,即可打开Navigation面板,如图2-1所示。这个Objcet的面板是对应当前选择的物体的(前提是该物体带网格),旁边的Bake面板是对应全局选项的。上面的All、MeshRenderers、Terrains是对Hirarchy面板里面显示的物品选择的一个筛选过滤。
第一个Navigation Static选项是选择该物体是否用做寻路功能的一部分。只有勾选了这个选项,下面的其他选项才可操作。
Generate OffMeshLinks选项是选择该物体是否根据高度、可跳跃宽度等全局的选项自动生成OffMeshLink,这个会在以后的讲解中详细说明,这次就暂时不讨论。
Navigation Area(旧版叫做Navigation Layer)是对参与寻路功能的地图物体的一个分类,用层来分类,默认有三个层可以选择,当然也可以自己添加层。寻路层就是在2-1的图中的Areas中来设置。
自带寻路Navmesh的三大组件:
1.Nav Mesh Agent:主要挂在寻路物体上
2.Off Mesh Link:实现区域转移功能(例如,有时不一定只是在地面上进行寻路,可能有些高高的平台,平台与地面是不相连的,使用该组件可以跳到平台上)
3.Nav Mesh Obstacle:主要挂在障碍物上。
下面我们通过一个基本的导航寻路案例为大家讲解其具体使用。
(1)新建项目,搭建如下地形。标记场景中所有的不动对象为寻路静态(Navgation Static)
(2)打开Window->Navigation,显示导航寻路窗口。
(3)调整合适的参数,半径,高度等参数都可以修改,点击下方的Bake进行烘焙。
(4)使用场景视图的线框模式查看烘焙的路径。
(5)添加胶囊体,并且添加NavMeshAgent组件。
(6)编写寻路脚本,并且将其挂载到胶囊体之上。
(7)运行程序,点击位置,让胶囊沿着指定的路径行走。
public class PlayerCtr : MonoBehaviour {
[SerializeField]
private NavMeshAgent agent;
// Use this for initialization
void Start () {
void Update () {
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if(Physics.Raycast(ray,out hit)){
//if (hit.collider.name.Equals ("Plane")) {
Vector3 p = hit.point;
Debug.Log (p);
agent.SetDestination (p);
speed 移动速度
Angular Speed 转角速度 ,转身速度 角速度: 最高转速(度/秒)。
Acceleration 加速度,启动时的 最大加速度。
Stopping Distance 停止距离 ,制动距离:制动距离。到目的地的距离小于这个值,代理减速。
Auto Traverse OffMesh Link 自动遍历OffMesh链接:自动移动并关闭OffMeshLinks
Auto Repath 自动重新寻路:如果现有的部分已失效,获得新的路径。
Height 高度:代理的高度(用于调试图形)。
Base offset 基本偏移:碰撞几何体相对于实际几何体垂直的偏移。
Obstacle Avoidance Type 障碍躲避类型 :躲避的质量水平。
NavMesh Walkable 导航网格行走:指定代理可以遍历的导航网格层类型。这个参数很有用,在接下来的实例中可以用到。
1.2 斜坡与跳跃
(1)添加斜坡,设置为NavigationStatic,重新烘焙。如下图所示:
(2)调整参数,重新烘焙查看效果。可以调节半径,高度,最大坡度,阶梯高度。如下图所示:
1.3 掉落功能
(1)选中所有的静态对象,勾选Generate OffMeshLinks,重新烘焙,会自动产生路径。
(2)修改高度和距离,如果两个都是0,哪怕设置了上面的Generate也没有效果。
(3)运行查看效果,将人物放置在高处,点击地板,会按照最优的路径移动。
1.4 跳跃功能
(1)搭建如下界面。选中所有的静态对象,勾选Generate OffMeshLinks
(2)调整JumpDistance,保证大于需要跳跃的距离。进行烘焙即可
(3)挂载脚本,运行游戏,可以看到agent可以在其中进行跳跃。
二:OffMesh Link使用
在前面的讲解之中,如果项目不能有很长的坡,如何让主角走上陡峭的高处呢。这种情况下,我们可以使用Unity的OffMeshLink来解决问题。
(1)搭建一个场景,模拟实现一个梯子的效果。如下图所示:
(2)给梯子增加OffMeshLink组件,并且设置其Start与End参数。不需要重新烘焙。
(3)运行程序,发现原本不相互连通的两个区域现在可以相互连通了。
三:网格分层的使用
Navigation视图下的Areas标签页可以设置层,Object标签页可以为物体指定层,Nav Mesh Agent组件的Area Mask可以指定可行走的层。具有寻路过程中层的过滤功能。
关于areaMask
Built-in 0 对应的areaMask为1
Built-in 1 对应的areaMask为2
Built-in 2 对应的areaMask为4
如此类推,即是areaMask为2的(n-1)次方
当设置areaMask为-1时,表示所有层都能通过
当设置areaMask为0时,表示所有层都不能通过
当设置areaMask为1时,表示只有Built-in 0层能通过
当设置areaMask为2时,表示只有Built-in 1层能通过
当设置areaMask为3时,表示只有Built-in 0和Built-in 1层能通过(3 = 1 + 2)
当设置areaMask为8时,表示只有User 3层能通过
可以通过查看Nav Mesh Agent组件的NavMesh Walkable看到设置areaMask后的结果。通过_agent.areaMask可以打印出寻路代理可行走的层。
(1)搭建如下场景,目的为了让红色的沿着红色的桥通过,蓝色的通过蓝色的桥通过。
(2)在Area窗口添加两个层,分别为 Red和Blue。
(3)分别给P1,P2,P3,P4设置其对应的NavigationArea,P1和P2为Walkable,P3为Red,P4为Blue。
(4)添加两个胶囊体,添加Agent组件。分别设置其材质球为蓝色和红色,挂载脚本。修改AreaMask,蓝色胶囊去除Red Area,红色胶囊去除Blue Area。
(5)烘焙运行,可以发现,代理寻路的时候沿着指定的路线运动。
四:动态更改路线
(1)搭建如下场景,通过点击按钮,让物体沿着指定的Area走路。
(2)在Area窗口添加两个层,分别为 Red和Blue。
(3)添加脚本,将其挂载到相机之上,通过点击按钮修改Area路径。
public class DynamicRoute : MonoBehaviour {
public NavMeshAgent agent;
// Use this for initialization
void Start () {
void OnGUI()
if (GUI.Button(new Rect(0, 0, 100, 50), "走下层"))
agent.walkableMask = 9;
if (GUI.Button(new Rect(0, 100, 100, 50), "走上层"))
agent.walkableMask = 17;
(4)给胶囊添加脚本PlayCtrl,同前面讲述的一样。运行即可。点击按钮不同,物体就会沿着不同的路线行进。
五:NavMeshObstacle组件使用
NavMesh Obstacle组件是导航寻路中的障碍物组件。可以在导航路径中设置特定的关卡,使得项目中的关卡可以按照剧情的需要,按照一定的触发条件进行触发。
(1)新建一个如下图所示的场景。
(2)给主角添加导航代理组件与脚本,使得主角可以顺利通过桥体。
(3)给独木桥添加障碍物组件,通过脚本的方式动态的改变桥体。
public class ObstacleControl : MonoBehaviour {
private NavMeshObstacle _navMeshObs;
// Use this for initialization
void Start () {
_navMeshObs=GetComponent<NavMeshObstacle> ();
// Update is called once per frame
void Update () {
if (Input.GetButtonDown("Fire1")) {
if(_navMeshObs){
_navMeshObs.enabled=false;
GetComponent<MeshRenderer>().material.color=Color.green;
if (Input.GetButtonUp("Fire1")) {
if(_navMeshObs){
_navMeshObs.enabled=true;
GetComponent<MeshRenderer>().material.color=Color.red;
(4)再次运行程序,发现当主角靠近桥的时候,由于受到障碍物的阻挡作用而停止前进。当我们单击鼠标左键时候,障碍物消失,主角可以继续前进。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class PlayerCtr : MonoBehaviour {
private NavMeshAgent agent;
public Animator animator;
// Use this for initialization
void Start () {
agent = GetComponent<NavMeshAgent> ();
animator = GetComponent<Animator> ();
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown(0)) {
//发出射线点
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;//碰撞信息
if (Physics.Raycast(ray,out hit)) {
Vector3 p = hit.point;
Debug.Log (p);
agent.SetDestination (p);
animator.SetBool ("run", true);
if (agent.remainingDistance < 0.1f && agent.hasPath) {
print ("1");