Search Unity

NavMeshAgent stuck on local maximum when trying to find a long path

Discussion in 'Navigation' started by Xine27, Feb 19, 2021.

  1. Xine27

    Xine27

    Joined:
    Feb 20, 2019
    Posts:
    11
    Hi all,

    I have been using NavMeshAgents to steer units in our game for some time now, but have just run into an interesting problem with a (rather large) new map that ended up with a roughly U-shaped NavMesh:

    When ordering units to move from one end of the U to the other, they will beeline for their destination point (so not following the U), and get stuck on the edge of the NavMesh that is closest to their destination point. Here, they will stay with their path pending for something between 10 and 20 seconds, before they set themselves the exact same partial path again (which means they are already on the endpoint of their new path, which triggers some logic in my game).

    Of course I could try writing something to work around this, but considering this seems to be a pretty straightforward issue, I am wondering if there is an alternative I haven't thought of.

    A related question: is there a way to check if a point "on a navMesh" is connected to the navMesh the current agent is on? If I call CalculatePath, it ends up returning a partial path and getting stuck in the same way as described above instead of returning an invalid path (However, in the latter case I can check if the CalculatePath function returns a partial path with a remaining distance of less than infinity, which seems to indicate an invalid path).

    Both of these may be an issue of the path being considered partial when it should just be invalid (because it is too far to be considered and because the destination cant be reached respectively) - but I appreciate any insights.

    Thank you very much for any help!
     
  2. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    They should walk around the U if their path is valid (NavMeshPathStatus.PathComplete). If it's partial/invalid then the destination must be on some kind of island.

    NavMesh.SamplePosition is the way to check if a point is on a navmesh. Then you would do CalculatePath to check if it's complete.

    Code (csharp):
    1. if (NavMesh.SamplePosition(hit.point, out NavMeshHit nmHit, maxDistance: 1f, NavMesh.AllAreas))
    2. {
    3.    var testPath = new NavMeshPath();
    4.    _agent.CalculatePath(nmHit.position, testPath);
    5.  
    6.    // If reachable, use it
    7.    if (testPath.status == NavMeshPathStatus.PathComplete)
    8.    {
    9.        _agent.SetDestination(nmHit.position); // or SetPath(testPath);
    10.    }
    11. }
    12.  
     
  3. Xine27

    Xine27

    Joined:
    Feb 20, 2019
    Posts:
    11
    Hi Stardog,

    Thank you for your reply! Let me break this down into two parts:

    1: The U shape. I am telling my units to move with "setDestination", so that might be the issue here. However, the destination is not on an island, and if I order them to walk to the same destination via 2 or 3 "waypoints", they reach it without an issue. Note here as well, that setting a destination far away (say in the bend of the U shape) makes them walk there, and the readout of path.status is "partial" for the longest time, before it switches to "complete" upon getting closer to the destination. This may be different for CalculatePath, but considering CalculatePath doesnt seem to be asynchronous, I am reticent to use it for such a long path (especially when ordering a whole group of units and considering that setDestination seems to take over 10 seconds to "time out"). I will run your CalculatePath code for testing though and see what that returns.

    2: The island problem. I am using both SamplePosition (which usually works, but as you stated, can be on an island), as well as CalculatePath. CalculatePath did not work for me as long as I kept the NavMeshArea set to "All" (even though I am only using the "Walkable" NavMeshArea). On experimenting a bit more, it seems that setting the mask to "Walkable" is now returning the right results, i.e. returns an "invalid" path when the sample position is on an island. The problem previously being, of course, that I could not differentiate between the "partial" path described in 1 above and the "partial" path I received from CalculatePath when the destination was on an island.

    So let's consider part 2 solved (and I hope this helps someone else), but unfortunately, part 1 is still at issue for me.

    Any thoughts?
     
  4. Xine27

    Xine27

    Joined:
    Feb 20, 2019
    Posts:
    11
    Following up on the above, the result is exactly the same for the suggested SamplePosition -> CalculatePath -> SetPath route as it was for SetDestination. If ordered from one end of the U to the other (A to B), the path was "partial", and the unit did not follow the U shape, but got stuck trying to beeline for the destination. If I ordered the unit to go to the "middle" of the U first (M), the path was still partial to start with, but resolved to be "complete" once the unit got close enough to destination M. When given the directive to go from M to B, the unit also managed to follow that, with an initial "partial" path, then a complete one when it got close enough.

    To recap: A - B doesnt work (likely because the heuristics are off for which direction to head for)
    but: A - M - B does work, likely because it can reassess its path as it gets closer.

    Seems to me like it got stuck on a local maximum of its heuristics, which I'm not sure how to avoid (other than building some kind of system that breaks down which area connects to which)... Something I would assume to already be a part of the NavMesh system.
     
    Hydraulic_Dragon likes this.
  5. miki9009

    miki9009

    Joined:
    Aug 20, 2015
    Posts:
    2
    I have the same issue. It is exacty as @Xine27 described. The path seems to be too long and NavmeshAgent cannot calculate path. Any ideas how to solve that? Seems like a NavMesh bug.
     
  6. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    I've noticed when a path is over ~300-500 units it can become partial. They often stop on the corner of a Tile when told to follow the partial path.
     
    Last edited: Aug 31, 2023
  7. Kas_

    Kas_

    Joined:
    Dec 27, 2017
    Posts:
    72
    Running into this issue. Any resolution?