一般情况下,只有主角是需要自动寻路的,其他玩家和怪物位置都是服务器转发过来的。除了主角身上有 NavMeshAgent,其他玩家和怪物对象可以不依赖 NavMeshAgent了,不用自主寻路,服务器直接下发目标点 (走线段),减少性能消耗。
判断是否其他玩家或怪物对象可以直接到达目标点,使用NavMesh.Raycast判断,其他玩家或怪物对象与目标点之间存在障碍物,如果存在,使用NavMesh.CalculatePath重新规划路径。
using UnityEngine;
using UnityEngine.AI;
public class NavMeshCalculatPath : MonoBehaviour
{
public Transform m_TargetTrans;
private NavMeshAgent m_NavMeshAgent;
private NavMeshPath m_NavMeshPath;
private Vector3 m_SourcePos;
private Vector3 m_TargetPos;
private float m_Distance;
private Vector3[] m_WayPoint = new Vector3[30];
private int m_AreaMask;
private bool m_ExcuteOne = false;
private bool m_Finished = false;
private NavMeshHit m_NavMeshHit;
private float m_ArrivedDistance = 0.1f;
void Start()
{
m_SourcePos = transform.position;
m_TargetPos = m_TargetTrans.position;
int area = NavMesh.GetAreaFromName("Walkable");
m_AreaMask = 1 << area;
m_NavMeshPath = new NavMeshPath();
// 初始化NavMeshAgent
m_NavMeshAgent = GetComponent<NavMeshAgent>();
// 设置目标点
m_NavMeshAgent.destination = m_TargetPos;
// 如果当前路径无效,尝试获得一个新的路径
m_NavMeshAgent.autoRepath = true;
// 自动刹车,不开启可能会在目标点附近来回晃动
m_NavMeshAgent.autoBraking = true;
// 规避半径
m_NavMeshAgent.radius = 0.6f;
// 规避的质量水平,设定越高,权衡规避障碍的精度越高
m_NavMeshAgent.obstacleAvoidanceType = ObstacleAvoidanceType.NoObstacleAvoidance;
// 加速度
m_NavMeshAgent.acceleration = 10000;
// 转弯角速度
m_NavMeshAgent.angularSpeed = 2000;
// 根据配置来设定速度
m_NavMeshAgent.speed = 3.5f;
// 一般实际开发中,方向需要服务器控制,需要设置为false
m_NavMeshAgent.updateRotation = true;
// 距离目标位置的停止距离
m_NavMeshAgent.stoppingDistance = 0.01f;
}
void Update()
{
if (m_Finished)
{
return;
}
// m_NavMeshAgent.pathPending 当前路径正在计算
// m_NavMeshAgent.remainingDistance 当前代理位置和目标位置的距离
if (!m_NavMeshAgent.pathPending && m_NavMeshAgent.remainingDistance < m_ArrivedDistance)
{
Debug.Log("到达目标点");
m_Finished = true;
}
if (m_ExcuteOne)
{
return;
}
// 如果在当前位置和目标点之间,存在阻碍
if (NavMesh.Raycast(m_SourcePos, m_TargetPos, out m_NavMeshHit, m_AreaMask))
{
// 重新规划路径
if (NavMesh.CalculatePath(m_SourcePos, m_TargetPos, m_AreaMask, m_NavMeshPath))
{
if (m_NavMeshPath.status == NavMeshPathStatus.PathComplete)
{
// 获得路径点的数量
int wayPointLength = m_NavMeshPath.GetCornersNonAlloc(m_WayPoint);
// 如果路径点的数量超过了数组的长度,那么重新分配
if (wayPointLength > m_WayPoint.Length)
{
m_WayPoint = new Vector3[wayPointLength];
m_NavMeshPath.GetCornersNonAlloc(m_WayPoint);
}
Debug.Log("wayPointLength: " + wayPointLength);
for (int i = 0; i < wayPointLength; i++)
{
Debug.Log("m_WayPoint: " + m_WayPoint[i]);
}
// 清空所有路径点
m_NavMeshPath.ClearCorners();
m_ExcuteOne = true;
}
}
}
}
}
有个简单的Unity例子,可以查看寻路的结果。
NavMeshCaluatePath.unitypackage
链接:https://pan.baidu.com/s/14yj2ofc03YfiQqTey8t8Eg
提取码:lb7y