Currently I’m working on setting up an async task that calculates a path and check it against a couple of limitations (also checked in tasks). I am new to using async, so this might be a bad approach and I would of course always welcome an objectively better method or pointers on what not to do. This also may be a task problem and not the NavMeshAgent problem that I suspect it to be, and if so sorry about the posting in the wrong spot!
Summary of the code:
I have a CharacterNavigationManager class that calls an OnNavigate function when my Input Handler fires a navigation event. The OnNavigate functions calls my CharacterPathFinder.GetPath() and subscribes to an OnGetPathCompleted event to handle the new path.
The issue:
In the method subscribed to OnGetPathCompleted the NavMeshAgent does not want to respond in anyway. I can’t get it to even do a Debug.Log(navMeshAgent) or if null debug log. Am I doing this wrong or is this a known limitation that I wasn’t able to find?
Work around that I’m not really happy with:
If I set a flag I can handle it in an update loop afterwards. I suppose it would also work with a coroutine. But the path working in the Update loop lets me know the path is actually valid.
Abbreviated Code:
public class CharacterNavigationManager : MonoBehaviour
{
//...
private void OnNavigate(Vector3 navDestination)
{
Camera referenceCamera = null;
float? maxPathingDistance = null;
CharacterPathFinder.OnGetPathCompleted -= SetDestination;
if (pathRestrictedByCameraView)
{
referenceCamera = CameraManager.Instance.ActiveCamera;
}
if (pathRestrictedByMaxDistance)
{
maxPathingDistance = this.maxPathingDistance;
}
characterPathFinder.GetPath(navMeshAgent, navDestination, referenceCamera, maxPathingDistance);
CharacterPathFinder.OnGetPathCompleted += SetDestination;
}
private void SetDestination(NavMeshPath navMeshPath)
{
testPath = navMeshPath;
//newPath = true;
var ret = navMeshAgent.SetPath(navMeshPath);
CharacterPathFinder.OnGetPathCompleted -= SetDestination;
}
private void Update()
{
if (newPath == false)
{
return;
}
newPath = false;
navMeshAgent.SetPath(testPath);
}
//...
}
public class CharacterPathFinder
{
//...
public void GetPath(NavMeshAgent navMeshAgent, Vector3 destination, Camera referenceCamera = null, float? maxPathingDistance = null)
{
Task<NavMeshPath> findPathTask = null;
Task_Utilities.RefreshToken(ref pathFindingCancellationToken);
if (referenceCamera == null && maxPathingDistance == null)
{
findPathTask = FindPathAsync(navMeshAgent, destination, pathFindingCancellationToken.Token);
}
else if (referenceCamera != null && maxPathingDistance == null)
{
findPathTask = FindPathAsync(navMeshAgent, destination, referenceCamera, pathFindingCancellationToken.Token);
}
else if (referenceCamera == null && maxPathingDistance != null)
{
findPathTask = FindPathAsync(navMeshAgent, destination, maxPathingDistance.Value, pathFindingCancellationToken.Token);
}
else
{
findPathTask = FindPathAsync(navMeshAgent, destination, referenceCamera, maxPathingDistance.Value, pathFindingCancellationToken.Token);
}
findPathTask.ContinueWith(findPathTask => { OnGetPathCompleted?.Invoke(findPathTask.Result); });
}
#region FindPathAsync(...)
private async Task<NavMeshPath> FindPathAsync(NavMeshAgent navMeshAgent, Vector3 destination, Camera camera, float maxPathingDistance, CancellationToken cancellationToken)
{
NavMeshPath navMeshPath = new NavMeshPath();
navMeshAgent.CalculatePath(destination, navMeshPath);
if (navMeshPath.status == NavMeshPathStatus.PathInvalid)
{
return null;
}
Task<float?> checkPathDistanceTask = CheckPathDistanceAsync(navMeshPath, maxPathingDistance, cancellationToken);
Task<bool> checkPathOnScreenTask = CheckPathOnScreenAsync(navMeshPath, camera, cancellationToken);
while (checkPathDistanceTask.IsCompleted == false)
{
if (cancellationToken.IsCancellationRequested == true)
{
return null;
}
await Task.Yield();
}
while (checkPathOnScreenTask.IsCompleted == false)
{
if (cancellationToken.IsCancellationRequested == true)
{
return null;
}
await Task.Yield();
}
if (checkPathDistanceTask.Result == null || checkPathOnScreenTask.Result == false)
{
return null;
}
return navMeshPath;
}
//...
}