https://docs.unity3d.com/cn/2019.4/Manual/class-NavMeshAgent.html
注意:NavMeshAgent 与 Rigidbody 同时挂在角色身上会引起抖动。
一、搭建一个场景
二、设置不可走区域
三、烘焙不可走区域
点Bake按钮执行烘焙。
四、烘焙可走区域
Unity 2019: Window->AI->Navigation
点Bake按钮执行烘焙。
设置哪些层之间要进行碰撞检测 [Edit]->Project Settings->Physics
五、编写以下脚本并挂到主角对象上。
using UnityEngine; using System.Collections; public class NavMeshAgentTest : MonoBehaviour { public NavMeshAgent agent; Vector3 point; Ray aray; RaycastHit ahit; void Update () { if (Input.GetMouseButtonDown(0)) { aray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(aray, out ahit)) { point = ahit.point; } agent.SetDestination(point); } } }
六、运行测试
鼠标点地面,小球会自动绕过建筑移动到鼠标点击点。
NavMeshAgent组件 | |
属性 | 描述 |
Base offset |
碰撞圆柱体相对于变换轴心点的偏移。 |
Speed |
最大移动速度(以世界单位/秒表示)。 |
Angular Speed |
最大旋转速度(度/秒)。如果要用代码控制转向,需要将此值设置为0或设置NavMeshAgent.updateRotation=false。 |
Acceleration |
最大加速度(以世界单位/平方秒表示)。 |
Stopping Distance |
当靠近目标位置的距离达到此值时,代理将停止。 |
Auto Braking |
启用此属性后,代理在到达目标时将减速。对于巡逻等行为(这种情况下,代理应在多个点之间平滑移动)应禁用此属性。 |
Radius |
代理的半径,用于计算障碍物与基他代理之间的碰撞。 |
Height |
代理通过头顶障碍物时所需的高度间隙。 |
Quality |
障碍躲避质量。如果拥有大量代理,则可以通过降低障碍躲避质量来节省 CPU 时间。如果将躲避设置为无,则只会解析碰撞,而不会尝试主动躲避其他代理和障碍物。 |
Priority |
执行避障时,此代理将忽略优先级较低的代理。该值应在 0–99 范围内,其中较低的数字表示较高的优先级。 |
Auto Traverse Off Mesh Link |
设置为 true 可自动跨越网格外链接 (Off-Mesh Link),即NavMeshAgent到达OffMeshLink端点时会自动瞬移到另一端。如果要使用动画或某种特定方式跨越网格外链接,则应关闭此功能。 |
Auto Repath |
启用此属性后,代理将在到达部分路径末尾时尝试再次寻路。当没有到达目标的路径时,将生成一条部分路径通向与目标最近的可达位置。 |
Area Mask |
描述了代理在寻路时将考虑的区域类型。在准备网格进行导航网格烘焙时,可设置每个网格区域类型。例如,可将楼梯标记为特殊区域类型,并禁止某些角色类型使用楼梯。 |
NavMeshAgent类 | |
属性 | 描述 |
isOnOffMeshLink | 判断NavMeshAgent是否正处于OffMeshLink上面。 |
autoTraverseOffMeshLink | true: 当NavMeshAgent到达OffMeshLink端点时,将自动瞬移到另一端。false: 需要程序员自己处理移动。 |
autoBraking | 启用此属性后,代理在到达目标时将减速。对于巡逻等行为(这种情况下,代理应在多个点之间平滑移动)应禁用此属性。 |
autoRepath | 启用此属性后,代理将在到达部分路径末尾时尝试再次寻路。当没有到达目标的路径时,将生成一条部分路径通向与目标最近的可达位置。 |
hasPath | NavMeshAgent是否已生成了一条路径。 |
pathPending | NavMeshAgent是否正在计算路径。 |
isPathStale | 当前路径是否已过时。 |
pathStatus | 当前路径的状态(完整、部分或无效)。 |
pathEndPosition | 当前路径的终点坐标。 |
isStopped | true: 停止寻路,false:恢复寻路 |
path | 当前路径信息 |
nextOffMeshLinkData | 当前路径下一个OffMeshLink数据信息 |
navMeshOwner | 返回代理当前放置在上面的导航网格的拥有对象 |
walkableMask | 已过时,参见 areaMask |
areaMask | 指定哪些层可行走 |
speed | NavMeshAgent最大移动速度 |
angularSpeed | 最大转向速度。(度/秒) |
acceleration | 最大加速度 。(米/秒平方) |
updatePosition | true: 允许NavMeshAgent自动更新坐标,如果需要手动控制移动,需要关闭这个属性。 |
updateRotation | true: 允许NavMeshAgent自动更新旋转,如果需要手动控制旋转,需要关闭这个属性。 |
updateUpAxis | true: NavMeshAgent与世界坐标系Y轴对齐,false: NavMeshAgent垂直于导航面。 |
radius | 代理半径 |
height | 代理高度 |
obstacleAvoidanceType | 规避品质级别 |
agentTypeID | 代理类型ID |
currentOffMeshLinkData | 当前OffMeshLink数据信息。通常先判断isOnOffMeshLink为true,然后再获取currentOffMeshLinkData。 |
isOnNavMesh | 判断NavMeshAgent是否已绑定到导航层上。 |
baseOffset | NavMeshAgent相对于它的的GameObject垂直偏移量 |
remainingDistance | NavMeshAgent离终点的剩余距离 |
desiredVelocity | 此速度值会受各种条件影响,如躲避动态障碍。 |
steeringTarget | NavMeshAgent当前转向,即目标方位。当updateRotation=false时,可手动使用transform.LookAt(steeringTarget)让角色朝向与行走方向一至。 |
nextPosition | 当updatePosition=false时,可在Update方法中手动设置位置。transform.position=navMeshAgent.nextPosition; |
velocity | 代理当前速度 |
stoppingDistance | 离终点多远停止移动。比如要让玩家导航到某个NPC身旁时,可将此值设置为0.2,从而避免与NPC重叠。 |
destination | 终点坐标。也可以用SetDestination()方法设置终点。 |
avoidancePriority | 规避优先级 |
方法 | 描述 |
void ActivateCurrentOffMeshLink(bool activated) | 启用或禁用当前的网格外链接 |
bool CalculatePath(Vector3 targetPosition, NavMeshPath path) | 计算到指定点的路径并存储路径 |
void CompleteOffMeshLink() | 代理将移动到当前 OffMeshLink 另一端上最近的有效导航网格位置。代理需要在OffMeshLink上,否则调用此函数无任何效果。 |
bool FindClosestEdage(out NavMeshHit hit) | 找到最近的导航网格边缘 |
float GetAreaCost(int areaIndex) |
获取在跨越特定类型的区域时的路径计算成本 |
float GetLayerCost(int layer) | 已过时,使用GetAreaCost()代替。 |
void Move(Vector3 offset) | 手动移动代理(相对移动) |
bool Raycast(Vector3 targetPosition, out NavMeshHit hit) | 检查代理与目标点之间是否有障碍 |
void ResetPath() | 清除当前路径 |
void Resume() | 已过时,用isStopped=false代替 |
bool SamplePathPosition(int areaMask, float maxDistance, out NavMeshHit hit) | 沿着当前路径检查。通过此方法可提前知道前方路段信息。 |
void SetAreaCost(int areaIndex, float areaCost) | 设置遍历指定类型区域的成本。代理被禁用时areaCost会被重置。 |
bool SetDestination(Vector3 target) | 设置终点,并重新计算路径。 |
void SetLayerCost(int layer, float cost) | 已过时,用SetAreaCost()代替。 |
bool SetPath([NotNull] NavMeshPath path) | 为代理分配一条新路径。 |
void Stop(bool stopUpdates) | 已过时,使用isStopped代替 |
void Stop() | 已过时,使用isStopped=true代替 |
bool Warp(Vector3 newPosition) | 将代理移动到指定位置 |
updateUpAxis 说明
问题:解决NavMeshAgent转向缓慢问题
using UnityEngine;
using UnityEngine.AI;
/// <summary>
/// NavMeshAgent的旋转太慢
/// 可用此脚本替换NavMeshAgent的旋转功能
/// 将此脚本挂在和NavMeshAgent同一GameObject上
/// </summary>
public class NavMeshAgentRotation : MonoBehaviour
{
[SerializeField]
private NavMeshAgent navMeshAgent;
public float angularSpeed = 10f;
private Transform mTransform;
private void Awake()
{
mTransform = transform;
if (navMeshAgent == null)
navMeshAgent = this.GetComponent<NavMeshAgent>();
}
void Update()
{
if (navMeshAgent == null)
return;
//代理是否绑定到导航网格
if (!navMeshAgent.isOnNavMesh)
return;
if (navMeshAgent.isStopped || navMeshAgent.pathPending || !navMeshAgent.hasPath)
return;
//当处于斜坡上时,由于NavMeshAgent与动画重力权重(gravityWeight)之间存在冲突,会发生抖动现象。
navMeshAgent.updateRotation = false;
//关闭寻路避免抖动
navMeshAgent.isStopped = navMeshAgent.remainingDistance < 0.1f;
/* 手动控制旋转 */
//当前朝向
Quaternion forward = Quaternion.identity;
forward.SetLookRotation(mTransform.forward);
//目标朝向
Vector3 targetForward = navMeshAgent.steeringTarget - mTransform.position;
Quaternion steering = Quaternion.identity;
steering.SetLookRotation(targetForward);
//旋转插值
Quaternion rotation = Quaternion.Lerp(forward, steering, Time.deltaTime * angularSpeed);
mTransform.rotation = rotation;
}
}