Unity-导航寻路系统
什么是导航寻路系统
Unity 中的导航寻路系统是能够让我们在游戏世界当中
让角色能够从一个起点准确的到达另一个终点
并且能够自动避开两个点之间的障碍物选择最近最合理的路径进行前往
Unity 中的导航寻路系统的本质
就是在 A 星寻路算法的基础上进行了拓展和优化
导航网格 (NavMesh) 的生成 — 要想角色能够在场景中自动寻路产生行进路径,那么必须得先有场景地形数据,导航网格生成就是生成用于寻路的地形数据
导航网格寻路组件 (NavMesh Agent)— 寻路组件就是帮助我们根据地形数据计算路径让角色动起来的关键
导航网格连接组件 (Off-Mesh Link)— 当地形中间有断层,想让角色能从一个平面跳向另一个平面,网格连接组件时关键
导航网格动态障碍物组件 (NavMesh Obstacle)— 地形中可能存在的可以移动或动态销毁的障碍物需要挂载的组件
导航网格生成
1.准备地形
2打开导航网格窗口
Window-->AI-->Navigation 打开 Unity 内置的导航网格生成窗口
Object 页签 — 设置参与寻路烘焙的对象
Bake 页签 — 导航数据烘焙页签,设置寻路网格具体信息
Areas 页签 — 导航地区页签,设置对象的寻路消耗
Agents 页签 — 代理页签,设置寻路代理信息
参数相关
Ojbect 场景对象设置页签
Sceme Filter: 场景过滤器,配合Hierarchy窗口使用 All:显示场景上所有对象 MeshRenderers:显示挂载的网格渲染器的对象 Terrains:显示挂载了地形脚本的对象
Navigation Static 导航静态物体开关
Generate OffMeshLinks 生成网格连接点开关
Navigation Area 导航区域选择,配合Areas页签使用
Bake 导航数据烘焙页签
Agent Radius 代理半径 决定了烘焙边缘精确度 控制平台可行走区域和边缘可行走区域
Agent Height 代理高度 决定了烘焙高度精确度 控制拱桥是否可以穿越
Max Slope 最大坡度 斜坡度数 决定了斜坡是否可以行走
Step Height 最小楼梯高度 决定了台阶是否可以行走
Generated off mesh Links 生成非网格连接 两个分开的网格之间连接相关设置
Drop Height 掉落高度 可以从这个高度掉下来
Jump Distance 跳跃距离 决定不同平面上的跳跃距离
Advanced
Manual Voxel Size 手动设置立体像素大小
Voxel Size 开启前者后可以在这里设置立体像素大小 可以控制烘焙的准确度 立体像素大小描述了生成的导航网格表示场景几何体的准确程度
注意:立体像素大小减半会使内存使用量增加4倍,构建时间也增加4倍 一般情况下不需要修改这个值 除非想要极其准确的导航网格
Min Region Area 最小区域面积 当面积小于此处值的导航网格区域会被移除
Height Mesh 高度网格构建开关 主要用来解决楼梯烘焙为斜坡时 希望在楼梯表面的位置准确的放置在楼梯平面上 而不是斜坡上 启用它会增加烘焙时间
Areas 导航地区页签 配合Object页签使用
Name 区域名字
Cost 寻路消耗
Agents 代理页签 用于配置寻路代理信息
导航网格寻路组件
导航网格寻路组件是用来干什么的
寻路组件的本质就是根据烘焙出的寻路网格信息
通过基于 A 星寻路的算法计算出行进路径让我们在该路径上移动起来
寻路组件参数相关
导航网格寻路组件
Nav Mesh Agent(导航网格代理人)
参数相关
Agent Type 代理类型 配合Agents页签使用
Base Offset 基础偏移值,相对对象轴心点的高度偏移
Steering 移动设置
Speed 寻路时的最大移动速度(世界单位/秒)
Angular Speed 寻路时转身的最大旋转速度(度/秒)
Acceleration 最大加速度(世界单位/平方秒)
Stopping Distance 当靠近目标点多少距离时,停止运动
Auto Braking 自动制动(减速) 启用后,当到达目标时将减速,如果存在连续移动(比如巡逻移动)建议不要开启该选项
Obstacle Avoidance 避障设置
Radius 半径,用于计算障碍物和其它寻路对象之间的碰撞
Height 高度,通过头顶障碍物时用于计算高度间隙使用
Quality 障碍躲避品质,越高躲避障碍越准确,但是性能消耗较大,如果不想主动避开其它动态障碍,可以设置为无,则只会解析碰撞
Priority 优先级,0~99, 避障时,数字较小的障碍物表示较高的优先级 优先级低的会忽略避障
Path Finding 路径寻找规则
Auto Traverse OffMesh Link 是否开启自动遍历网格外的其它网格连接 如果要自定义判断,则关闭此功能
Auto Repath 是否开启自动重设路线 如果开启,当到达路径后段时会再次尝试寻路,当没有到达目标的路径时,会生成一条到达与目标位置最近的可达点
Area Mask 寻路时,考虑的区域 如果寻路时不想考虑某些区域,则取消选中 塔防游戏中常见的功能
代码控制
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.AI;public class lesson20 : MonoBehaviour
{private NavMeshAgent nma;// Start is called before the first frame updatevoid Start(){nma = GetComponent<NavMeshAgent>();//自动寻路设置目标点//nma.SetDestination();//停止寻路//nma.isStopped = true;//面板参数相关 速度 加速度 旋转速度//nma.speed//nma.acceleration//nma.angularSpeed//当前是否有路径//bool temp = nma.hasPath;//代理目标点的设置和获取//nma.destination//当前路径//nma.path//路径是否在计算中//if (nma.pathPending) { }//路径状态//nma.pathStatus//是否更新位置//nma.updatePosition = true;//是否更新角度//nma.updateRotation = true;//代理速度//nma.velocity//计算生成路径NavMeshPath path = new NavMeshPath();if (nma.CalculatePath(Vector3.zero, path)){Vector3[] temp = path.corners;//路径上的点}//设置新路径//nma.SetPath();//清除路径//nma.ResetPath();//调整到指定点位置//nma.Warp(Vector3.zero);}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(0)) // 检测鼠标左键点击{RaycastHit hit;// 从摄像机发射射线到鼠标位置if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit)){print(hit.collider.name); // 输出被点击物体的名称nma.SetDestination(hit.point); // 设置寻路目标点}}if (Input.GetKeyDown(KeyCode.Space)){nma.isStopped = true;}if (Input.GetKeyUp(KeyCode.Space)){nma.isStopped = false;}}
}
导航网格外连接组件
网格外连接组件是什么?
我们在烘焙地形数据的时候
可以生成网格外连接
但是它是满足条件的都会生成
而且是要在编辑模式下生成
如果我们只希望两个未连接的平面之间只有有限条连接路径可以跳跃过去
并且运行时可以动态添加
就可以使用网格外连接组件
达到 “指哪打哪” 的效果
网格外连接组件的使用
使用两个对象作为两个平面之间的连接点(起点和终点)
添加 Off Mesh Link 脚本进行关联
设置参数
参数相关
网格外连接组件
Start 起始点
End 结束点
Cost Override 覆盖消耗值 负数或0则使用所属Area区域中的消耗值 如果为正数,则使用Area区域寻路消耗值*正数代表该连接点的寻路消耗 相当于我们可以自定义连接点的寻路消耗 主要用来解决当有"步行"和连接点都可以到达某一个目标时,希望优先选择步行区域,但是步行路径明显更远时修改该值
Bi Directional 是否开启双向连接点 开启后可以从Start到End,反之也可以 如果关闭,则只能Start到End
Activated 是否启用该连接点 如果关闭,则自动寻路时相当于失效
Auto Update Positions 是否自动更新位置 如果启用 当开始和结束位置改变时,导航网格也将更新 如果不启用,即使改变了开始结束位置,也会按照刚开始的位置进行计算
导航网格动态障碍组件
导航网格动态障碍组件用来干啥?
在游戏中常常会有这样的一个功能
场景中有一道门,如果这道门没有被破坏是不能自动导航到门后场景的
只有当这道门被破坏了,才可以通过此处前往下一场景
而类似这样的物体本身是不需要进行寻路的所以没有必要为它添加 NavMeshAgent 脚本
这时就会使用动态障碍组件实现该功能
导航动态障碍物组件的使用
为需要进行动态阻挡的对象添加 NavMeshObstacle 组件
设置相关参数
代码逻辑控制其的移动或者显隐
参数相关
导航网格动态障碍物组件
Shape 动态障碍的形状 Capsule:胶囊 Box:盒装
Carve: 是否开启雕刻功能 开启后,障碍物会在导航网格中挖一个孔,所谓挖孔就是会生成对应的网格信息,认为这篇区域无法前往 如果动态障碍物是固定不动的,建议开启,比如阻碍物门木桶栅栏等等 如果动态障碍物是频繁移动的,建议不开启该功能,比如汽车和玩家
Move Threshold: 移动阈值 当障碍物移动超过该距离时,会认为其为移动状态,会更新移动的孔
Time To Stationary: 障碍物作为静止状态需要等待的时间,单位为秒 当静止时间超过该值会认为真正静止了
Carve Only Stationary: 只有在静止状态时才会计算孔
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;public class lesson20_2 : MonoBehaviour
{private NavMeshAgent agent;// Start is called before the first frame updatevoid Start(){agent = GetComponent<NavMeshAgent>();}// Update is called once per framevoid Update(){if (Input.GetMouseButtonDown(1)){RaycastHit hit;if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit)){agent.SetDestination(hit.point);}}if (Input.GetMouseButtonDown(0)){RaycastHit hit;if (Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hit,1000,1 << LayerMask.NameToLayer("wall"))){hit.collider.gameObject.SetActive(false);}}}
}