Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Navmesh agents to avoid other agents

Discussion in 'Navigation' started by skinwalker, Oct 16, 2017.

  1. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    Hey,

    I have read a lot of threads on this topic, but didn't find a solution. I am using the NM agent to draw the path and the Character Controller to move with NPC (using the Move method), but the nav mesh agents are not avoiding other nav mesh agents, do you have any idea how to do that?
     
  2. francois85

    francois85

    Joined:
    Aug 11, 2015
    Posts:
    1,344
    I myself have been trying to find an answer to this question.

    How exactly are you using the Move method?

    A solution I currently have but want to abandon is a custom A* path finding setup. Basically it exposes the f and h costs and allow you to modify it during update. So as my agents move across my nav grid they alter the h and f cost in a given radius. The player agent will then adjust its path according per frame to try and avoid other agents.

    A similar solution with Unity’s nav would be to modify the nave mesh cost with a volume modifier attaches to the other agent and then re bake/ re path per frame. ( I’m a noob at unity navigation so this suggests might not be possible or very expensive)

    Let me know if you find a solution and I’ll let you know what I find. My custom solution is extremely difficult to implement and to maintain hence why I’m looking for something off the shelf.
     
    Levi-Burton likes this.
  3. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
  4. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    I am using something like this, except I forgot that I got rid of the Move function I am using root motion for that

    https://forum.unity.com/threads/using-a-navmeshagent-with-a-charactercontroller.466902/

    My solution for now is to implement a custom AI Behaviour, since my game is open world and there isn't a big chance 2 of the NPCs to walk in the same direction, I just stop one of the NPCs if that happens and disable the navmesh agent and enable navmesh obstacle (Set to carve, only on static = false), the walking NPC avoids the static one and after 3-4 seconds I disable the NM obstacle and enable the NM agent then continue it's walking routine. It's not the best solution, especially for games where you have lots of NPCs in a small area.

    If you have lots of NPCs you can have a charactermanager class that handles figuring out where in proximity other characters are to each other, sadly I don't have the code for that it's just a suggestion a friend of mine uses in his game with lots of NPC walking in a small area.

    I also don't know if the NM agents built in avoidance isn't working for me, because of the character controller or because it's not working at all. My player has a navmesh obstacle component attached and the same NPC avoids the player, but won't avoid other NPCs that only have NM agent.
     
  5. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    THis is very specific to this developers game, i would not recommend OP uses this method. Just use NM obstacles on your agents and itll sort your problem out.
     
  6. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    You can't have NM obstacle and NM agent active at the same time. Adding NavMeshObstacles to my scene I had weird things with agents walking in circles or just walking into a wall over and over.
     
    Ignacii likes this.
  7. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    Yes but your not using the agent constantly every frame are you? Very inefficient.

    Just use the agent to get a path, store that path, calculate any direction changes along that path.

    Now move the agent along it with the navmesh agent TURNED OFF. and turn the obtacle on.

    Effectively you only use the agent for 1 frame at a time.

    I do this even when not using obstacles as NM agents are very heavy.

    C# job system coming soon will rectify this.

    Also try calculating the directional turns in the path asynchronously for better performance.

    EDIT: to make more clear, effectively you just use the agent to calculate pathing. But you actually do all the moving, and facing direction yourself using the precalculated path. Using this method you can have 10000+ dynamic agents.
     
    LUCID-Rob and esbenrb like this.
  8. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    Any examples doing that or can you setup a small repo?
     
    MadeFromPolygons likes this.
  9. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    I'm at work at the moment but i can definately setup a small public bitbucket repo when I get home.

    The code for working out turns along a path is generic and can be found on a variety of places, unity specific and not. I think there is even one on the unity wiki (if the wiki is not down again)
     
  10. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    here you go :)

    https://docs.unity3d.com/ScriptReference/AI.NavMeshPath-corners.html

    use that code to work out where all the turns are. Then use basic direction vector math to get direction to first "waypoint" (corner) and then each time you get to the next corner, change direction.

    Very very very simply once you think about it, and means you can turn off the agents except at path generation.

    If your still struggling ill put a repo up this evening when im home :)

    EDIT:
    NavMeshPath.GetCornersNonAlloc for a non allocating version
     
  11. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    Any idea about the performance on large terrains and multiple NPCs? I've heard bad things about having an obstacle that has Carve and is not set to carve only on stationary, basically its always making holes in the navmesh as it's moving.
     
  12. Modus_Pwnens

    Modus_Pwnens

    Joined:
    Oct 24, 2017
    Posts:
    4
    If you are still looking at this Daemonhahn, I would very much like an example of how to implement this. I understand conceptually, but I am too new to Unity to have a good idea of how to go about an implementation. Thanks!
     
    MadeFromPolygons likes this.
  13. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    Hey, I am at work at the moment, but will try and write you a snippet when I am free :)

    EDIT:

    Code (CSharp):
    1.   Public NavMeshPath pathToUse;
    2.     public Queue<Vector3> cornerQueue;
    3.     public Vector3 currentDestination;
    4.     bool hasPath;
    5.     public float currentDistance;
    6.     public float minDistanceArrived;
    7.     Vector3 direction;
    8.     public float moveSpeed;
    9.  
    10.     void /// <summary>
    11.     /// Start is called on the frame when a script is enabled just before
    12.     /// any of the Update methods is called the first time.
    13.     /// </summary>
    14.     void Start()
    15.     {
    16.         SetupPath(pathToUse);
    17.     }
    18.  
    19.     // get the corners and add them to a queue for use to use
    20.     void SetupPath(NavMeshPath path)
    21.     {
    22.         cornerQueue = new Queue<Vector3>();
    23.         foreach(Vector3 corner in path.corners)
    24.         {
    25.             cornersList.Enqueue(corner);
    26.         }
    27.  
    28.         GetNextCorner();
    29.         currentDistance = (transform.position - currentDestination).sqrMagnitude;
    30.         hasPath = true;
    31.     }
    32.  
    33.     // get the next corner, and set direction
    34.     void GetNextCorner()
    35.     {
    36.         if(cornerQueue.Length > 0)
    37.         {
    38. currentDestination = cornerQueue.Dequeue();
    39.         previousCorner = previousCorner;
    40.         direction = transform.position - currentDestination;
    41.          hasPath = true;
    42.         }
    43.         else
    44.         {
    45.             hasPath = false;
    46.         }
    47.     }
    48.  
    49.     // move towards the point
    50.     void MoveAlongPath()
    51.     {
    52.         if(hasPath)
    53.         {
    54.             currentDistance = (transform.position - currentDestination).sqrMagnitude;
    55.  
    56.             if(currentDistance > minDistanceArrived)
    57.             {
    58.            
    59.                 transform.position +=  direction  * moveSpeed * Time.deltaTime;
    60.             }
    61.             else
    62.             {
    63.                 GetNextCorner();
    64.             }
    65.         }
    66.     }
    67.  
    68.  
    69.     // Update the agent
    70.     void Update()
    71.     {
    72.         MoveAlongPath();
    73.     }
    That code is entirely untested but should work with little ammendments!

    You set a minimum arrived distance to set how far a agent goes until it stops. You also need to set the movespeed and provide a navmesh path, but that will do the basics of what I was saying!

    EDIT2: So what ive written will work out the path and move a navmesh agent along a path. Then all you need to do is either raycast from each agent towards their current destination and if these rays hit each other you know that agents will collide!

    Or you could go through that queue (or use a list instead) of waypoints (corners) and fire rays Along each one (or place colliders) and then if theres collisions you know the paths intersect. theres literally so many ways to check intersections between lines, which when you boil it down is what your doing at this stage :)

    That should get you started, message me if you still cant work out the rest.

    EDIT3:
    you could also use the physics api to do casting/ overlap checks, https://docs.unity3d.com/ScriptReference/Physics.html

    EDIT4: https://answers.unity.com/questions/1356936/navmeshpathcornerslength-is-always-0.html this shows a api call that will let you calculate the path without using an actual agent too :)
     
    Last edited: Nov 6, 2017
    StanK_ and obsilp like this.
  14. w4der

    w4der

    Joined:
    Sep 17, 2011
    Posts:
    15
    Hi,
    There are errors in your code.
    Could you help me?
     
  15. StanK_

    StanK_

    Joined:
    Dec 5, 2017
    Posts:
    6
    Hey!
    I've just edited his code for myself, it works:

    Code (CSharp):
    1. private NavMeshPath _path;
    2. private bool _hasPath;
    3. private NavMeshAgent _agent;
    4. private Queue<Vector3> _cornerQueue;
    5. private Vector3 _currentDestination;
    6. private Vector3 _direction;
    7. private float _currentDistance;
    8.  
    9. void OnEnable ()
    10. {
    11.     InitVars();
    12.     CalculateNavMesh();
    13.  
    14.     SetupPath(_path);  
    15. }
    16.  
    17. private void CalculateNavMesh()
    18. {
    19.     _agent.CalculatePath(_targetPoint, _path);
    20. }
    21.  
    22. private void InitVars()
    23. {
    24.     _targetPoint = GameObject.Find("EndPoint").transform.position; // Set target point here
    25.     _agent = GetComponent<NavMeshAgent>();
    26.     _path = new NavMeshPath();
    27. }
    28.  
    29. void SetupPath(NavMeshPath path)
    30. {
    31.     _cornerQueue = new Queue<Vector3>();
    32.     foreach (var corner in path.corners)
    33.     {
    34.         _cornerQueue.Enqueue(corner);
    35.     }
    36.  
    37.     GetNextCorner();
    38.     _hasPath = true;
    39. }
    40.  
    41. private void GetNextCorner()
    42. {
    43.     if (_cornerQueue.Count > 0)
    44.     {
    45.         _currentDestination = _cornerQueue.Dequeue();
    46.         _direction = _currentDestination - transform.position;
    47.         _hasPath = true;
    48.     }
    49.     else
    50.     {
    51.         _hasPath = false;
    52.     }
    53. }
    54.  
    55. void FixedUpdate()
    56. {
    57.     MoveAlongPath();
    58. }
    59.  
    60. private void MoveAlongPath()
    61. {
    62.     if (_hasPath)
    63.     {
    64.         _currentDistance = Calc.GetSqrDistLinear(transform.position, _currentDestination);
    65.  
    66.         if (_currentDistance > 1)
    67.             transform.position += _direction * 0.4f * Time.deltaTime;
    68.         else
    69.             GetNextCorner();
    70.     }
    71. }
     
    CrandellWS and MadeFromPolygons like this.
  16. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    Thanks, yeah i was at work so it was written off top of my head without an IDE or looking at API ;)
     
  17. Modus_Pwnens

    Modus_Pwnens

    Joined:
    Oct 24, 2017
    Posts:
    4

    LOL. Thank you very much for the thorough reply. It has been a while since I posted this question. I actually ended up deep diving into pathing and wrote my own navigation system using A* plus boid flocking.
     
    MadeFromPolygons likes this.
  18. MadeFromPolygons

    MadeFromPolygons

    Joined:
    Oct 5, 2013
    Posts:
    2,545
    Glad you managed to get a solution up and running! :)
     
  19. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    866
    @GameDevCouple_I Isn't the idea of having NavMeshObstacles on agents dangerous when it comes to raycasting on the navmesh? You're going to create a lot of holes throughout the navmesh and the raycasts you will then do to find valid positions on the navmesh will be incorrect, right?
     
  20. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    192
    Don't do necromancy)))

    https://docs.unity3d.com/Manual/nav-MixingComponents.html

    NavMesh Agent and NavMesh Obstacle
    • Do not mix well!
      • Enabling both will make the agent trying to avoid itself
      • If carving is enabled in addition, the agent tries to constantly remap to the edge of the carved hole, even more erroneous behavior ensues
    • Make sure only one of them are active at any given time
      • Deceased state, you may turn off the agent and turn on the obstacle to force other agents to avoid it
      • Alternatively you can use priorities to make certain agents to be avoided more
     
  21. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    866
    I don't see how that answers my question. Are you saying you think it's correct that it's dangerous? If so, that still doesn't answer the question of how to make agents avoid each other.
    In the 2018 documentation it already said that they don't mix well together, but it might not be true in the specific case GameDevCouple_I mentioned.
     
  22. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    You need to have only one on at a time, otherwise the agent will be trying to avoid itself (since the obstacle is on the same gameobject). This will cause weird behavior.
     
  23. DwinTeimlon

    DwinTeimlon

    Joined:
    Feb 25, 2016
    Posts:
    197
    Moving/Charging:
    Switch off
    NavMeshObstacle

    Switch on
    NavmeshAgent 


    Fighting/Idling:
    Switch on
    NavMeshObstacle

    Switch off
    NavmeshAgent 


    This article is somewhat old and the tutorial screenshots don't work anymore, but it describes exactly whay you need to know.
    https://www.gamedev.net/articles/pr...-avoidance-for-rpgrts-games-using-unity-r3703
     
    FeastSC2 likes this.
  24. skinwalker

    skinwalker

    Joined:
    Apr 10, 2015
    Posts:
    422
    Thats good unless 2 characters are moving then they wont avoid themselves, thats the problem with unity there is no easy way to do it. I recommend buying A* and using the RVOController to save yourself weeks or months of headache.
     
    FeastSC2 likes this.
  25. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    866
    That's true.
    But have you tried using NavMesh.CalculatePath()? This way you don't even need to have a NavMeshAgent on your unit. You could keep the NavMeshObstacle toggled on at all times. That's what GameDevCouple_I suggests to this issue.

    I'm just not sure what the implications of not using a NavMeshAgent are.

     
  26. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    192
    Agent have more feature than Calculate path. He has obstacle and agent avoidance, following and returning to path with appropriate handling.


    On the other hand, you can implement it. Unfortunately Agent is native component and does not have API
     
  27. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    626
    Maybe I am missing something, but Unity NavMesh Agents do avoid each other without any obstacles on them? And you can decide who avoids who using priority.

    Maybe I misunderstood what this thread is about, but what A* RVO component does is basically what Unity already does (although a bit nicer).
     
  28. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411

    Hi, I have similar problem, but using navmesh obstacle causes other bigger gameplay problems I want to avoid; such that I want some units to be able to collide and others not.

    Thus I was thinking would it be possible to instantiate a (non-walkable area beneath my unit at desired time to avoid other units from approaching that unit of interest) at "run time" and make those specific units use (area Mask)?



    Also, if that is possible, how would I reverse the change at run-time?
     
    Last edited: Dec 10, 2019
  29. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    626
    I would try to solve this using priority instead of editing the navmesh surface at runtime.
     
  30. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    @vhman,

    in my experience, this will stop the pushing, but it doesn't avoid the bumping. Normally when you bump you add force to that unit and nudges it also. however if the unit you bump into has higher priority, you still bump into it and can get stuck trying to pass it, but you do not nudge it.

    the question is, how to avoid it, or make a cleaner path that goes around and completely avoids the point of interest without using navmesh-Obstacle?
     
  31. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411


    I made a video to show you the problem, Also; ignore what happens after 4:10 in the video, that happend because the priority of all units changed to the same value (as part of my game mechanic)

     
  32. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    626
    Isnt this the exact same scenario as above? i.e when they start to attack just add an obstacle to them and the agents behind will go around?
     
  33. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    192
    As message addressed to me, I will take a try to respond.

    Essentially you want Repathing, so that path changes dynamically in a response to moved agent, and not Avoidance, that is like a bubble you cannot penetrate.
    upload_2019-12-10_16-59-6.png
    For repathing you need to change navigation mesh dynamically, and obviously the only API we have is obstacle carving. But be aware that if Agent is carved Obstacle, it would think its not on navmesh. So there is no way to do it without some janky coding. Maybe you can fill the hole under you in moment of CalculatePath().

    I'm also not aware of A*RVO details. So no comments

    After I saw video:
    What you want is RTS movement:
    https://www.gamasutra.com/blogs/Dru..._Pathfinding__Movement_in_RTS_Style_Games.php
     
    DungDajHjep likes this.
  34. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    @vhman,

    Thank you for reply.

    I completely agree, and thats exactly what I want, however its just not working. (it kinda works when all the units are running, but not when some units have already reached their waypoint (as you saw in the video).

    and if this is not an option "say I want a tank to always cut through those units"?

    This part wont be a problem to me because I will only activate this when my units reach their destination, or even a specific activation time after they have reached their destination. But the problem that still remains, is what if I want a tank to still cut through those units?

    Thank you for this Link, I will try to study it, however, I really want to use navmesh/navagent, and I would hate to completely recreate the navmesh/navagent system from scratch. Despite my account creation day, I am a noob, and really only started programming less than 3 months ago give or take.
     
  35. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411

    yes, and if my game would have had only one type of unit, that would have worked, but I wouldn't want my tank to go around that group of infantry, I would want my tank to cut through as a result of higher priority, and that will no longer be possible if I was to use an "obstacle". As an obstacle will treat all units the same
     
  36. vhman

    vhman

    Joined:
    Aug 13, 2018
    Posts:
    192
    You can have NavMesh bake and all its static classes, like point cast and etc. But "RTS like group movement" will require do it from scratch, or use RTS asset, or even other RTS game engine. Agent are not RTS group friendly.
     
  37. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    I wish Unity, would give more flexibility and more options when it comes to the navmeshAgent. but I think I have a solution! the problem is when the units reach their destination, what if I fake navemesh Movements of higher priority on those locations?

    nvm, I dont think thats possible, and probably very taxing even if it is possible
     
  38. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    626
    I know that the RVO controller in the A* project can do exactly this. Will cost you 100$ tho.
     
  39. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411

    can you provide me a link to this asset please, thank you

    Nvm found it, thanks anyway
     
    Last edited: Dec 10, 2019
  40. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    I have a similar problem. My game (zombies), tend to bump into each other and push each other, in stead of trying to go around them.

    I do turn on the Navmesh obstacle when they are stationary, but I want faster zombies to walk AROUND slower ones, instead of just plowing through them.
     
  41. mrCharli3

    mrCharli3

    Joined:
    Mar 22, 2017
    Posts:
    626
    If you want pushing you cant make them obstacles.
    Set priority based on speed.
     
  42. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    Yes, I’m doing that but a higher priority (10), still pushes a lower priority (50), if they are in the way.

    They never go around them.
     
  43. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    Are you saying that you don’t see that issue at all?

    if not, then I will have to re-examine my movement code as I’m setting the NavMeshAgent.speed to match the animation rootmotion speed to prevent foot sliding.

    I previously was setting navmeshagent.velocity, but changed it to speed when I read in the docs that setting the velocity directly disables avoidance between agents. Maybe I’m still having this issue?
     
  44. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    higher Priority is intended to push away lower priority, Lower Priority Cant push higher Priority and equal priority can both push each other.

    Also Have noticed that Equal priority only avoids each other if both agents are moving.
    and Lower priority moves out of the way of higher priority only if both are moving.

    Thats just based on my experiance
     
  45. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    I just created a quick script that check avoidance of other Navmesh agent when using avoidance priority.

    There is zero effort for slower and less priority agents to move out of the way. Giving the fast agent a higher priority only allows it to plow thru (push them out the way) the lower priority ones.

    I’m guessing the only way to get them to avoid each other totally is to put a Navmesh obstacle on them and use my own code to move them instead of the Navmesh agent.

    I would love to see a simple example of avoidance in action....I don’t see it.
     
  46. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    you can increase the navmesh cost underneath the unit that you want to be avoided, though I am still working on how to do that myself.
     
  47. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    You can’t do that at runtime. Navmesh areas need to be baked in at edit time.
     
  48. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    JungsangE likes this.
  49. FiveFingerStudios

    FiveFingerStudios

    Joined:
    Apr 22, 2016
    Posts:
    404
    Maybe I should have been more clear. You can bake them during runtime, but its not performant, so it couldn't be used for real time avoidance. That's more for scenes that are created or altered procedurally,

    For what you suggested, (re-baking the navmesh to change the navmesh cost under an agent), would be way too costly and would not run fast enough for moving agents that are trying to avoid each other.
     
  50. Mortalanimal

    Mortalanimal

    Joined:
    Jun 7, 2014
    Posts:
    411
    why is it that we can make dynamic NavMeshObstacle with carve on stationary units and its relatively performant from what I have heard, but altering the local navmesh cost be taxing?

    Anyway, I have seem to have found a temporary solution for this problem, add the following to your NavMeshAgents.

    Note: the lower the value the better avoidance quality, but it also becomes more taxing, I think I can further Increase this quality by reducing the VoxelSize, but I cant seem to figure out how to do that, ofc that also makes it more taxing.



    Code (CSharp):
    1. void Start()
    2.     {
    3.        
    4.         NavMesh.avoidancePredictionTime = 0.5f;
    5.  
    6.     }
     
unityunity