DwinTeimlon post didn’t have the code for GetNavMeshPosition so I have added what I used. Also this part NavMesh.CalculatePath(startPos, targetPos, _filter, m_navMeshPath); should be _filter.areaMask or the path seems to not care about area cost.
bool GetNavMeshPosition(Vector3 _position, int _areaMask, float _maxDistance, out Vector3 _navMeshPosition)
{
NavMeshHit hit;
// Sample points around the input position to find the nearest valid NavMesh point
if (NavMesh.SamplePosition(_position, out hit, _maxDistance, _areaMask))
{
_navMeshPosition = hit.position;
return true;
}
_navMeshPosition = Vector3.zero; // Or some default value
return false;
}
int CalculatePath(Vector3 _start, Vector3 _target, NavMeshQueryFilter _filter, Vector3[] _path, int _startIndex = 0, int _numTries = 0)
{
Vector3[] m_pathCorners = new Vector3[MAX_CORNERS];
NavMeshPath m_navMeshPath = new NavMeshPath(); // You need to initialize this NavMeshPath
if (_numTries > MAX_TRIES || _startIndex >= m_pathCorners.Length)
return -1;
var startPosOk = GetNavMeshPosition(_start, _filter.areaMask, MAX_PATH_DISTANCE, out Vector3 startPos);
var endPosOk = GetNavMeshPosition(_target, _filter.areaMask, MAX_PATH_DISTANCE, out Vector3 targetPos);
if (!startPosOk || !endPosOk)
return -1;
NavMesh.CalculatePath(startPos, targetPos, _filter.areaMask, m_navMeshPath);
switch (m_navMeshPath.status)
{
case NavMeshPathStatus.PathPartial:
{
var numCorners = m_navMeshPath.GetCornersNonAlloc(m_pathCorners);
Array.Copy(m_pathCorners, 0, _path, _startIndex, numCorners);
var lastPos = m_navMeshPath.corners[m_navMeshPath.corners.Length - 1];
if (Mathf.Abs(lastPos.x - targetPos.x) < 0.5f && Mathf.Abs(lastPos.z - targetPos.z) < 0.5f)
return _startIndex + numCorners;
return CalculatePath(lastPos, _target, _filter, _path, _startIndex + numCorners, ++_numTries);
}
case NavMeshPathStatus.PathComplete:
{
var numCorners = m_navMeshPath.GetCornersNonAlloc(m_pathCorners);
Array.Copy(m_pathCorners, 0, _path, _startIndex, numCorners);
return _startIndex + numCorners;
}
default:
return -1;
}
}
Then how I used it to draw a line render for a long distance.
private IEnumerator DrawpathtoCheckpoint()
{
WaitForSeconds Wait = new WaitForSeconds(PathUpdateSpeed);
bool destinationReached = false;
while (nearestOBJ != null && !destinationReached)
{
totalDistance = 0;
NavMeshQueryFilter filter = new NavMeshQueryFilter();
filter.areaMask = NavMesh.GetAreaFromName("Road") | NavMesh.GetAreaFromName("Terrain");
Vector3[] pathCorners = new Vector3[MAX_CORNERS];
//using the code from DwinTeimlon
int pathCornerCount = CalculatePath(Player.position, nearestOBJ.transform.position, filter, pathCorners);
if (pathCornerCount > 0)
{
Path.positionCount = pathCornerCount;
for (int i = 0; i < pathCornerCount; i++)
{
Path.SetPosition(i, pathCorners[i] + Vector3.up * PathHeightOffset);
if (i > 0)
{
totalDistance += Vector3.Distance(pathCorners[i - 1], pathCorners[i]);
}
}
if (Vector3.Distance(pathCorners[pathCornerCount - 1], nearestOBJ.transform.position) <= 0.1f)
{
destinationReached = true;
// Set the destination to the last point on the calculated path
Vector3 lastPoint = pathCorners[pathCornerCount - 1];
nearestOBJ.transform.position = lastPoint;
}
// Display the total distance
distanceToGoal.text = totalDistance.ToString("F1") + "M";
}
else
{
Debug.LogError($"Unable to calculate a path on the NavMesh between {Player.position} and {nearestOBJ.transform.position}.");
}
yield return Wait;
}
}