Navmesh agents to avoid other agents

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?

1 Like

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.

1 Like

put navmesh obstacles on them.

https://docs.unity3d.com/Manual/class-NavMeshObstacle.html

5 Likes

I am using something like this, except I forgot that I got rid of the Move function I am using root motion for that

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.

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.

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.

4 Likes

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.

5 Likes

Any examples doing that or can you setup a small repo?

1 Like

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)

here you go :slight_smile:

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 :slight_smile:

EDIT:
NavMeshPath.GetCornersNonAlloc for a non allocating version

1 Like

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.

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!

1 Like

Hey, I am at work at the moment, but will try and write you a snippet when I am free :slight_smile:

EDIT:

  Public NavMeshPath pathToUse;
    public Queue<Vector3> cornerQueue;
    public Vector3 currentDestination;
    bool hasPath;
    public float currentDistance;
    public float minDistanceArrived;
    Vector3 direction;
    public float moveSpeed;

    void /// <summary>
    /// Start is called on the frame when a script is enabled just before
    /// any of the Update methods is called the first time.
    /// </summary>
    void Start()
    {
        SetupPath(pathToUse);
    }

    // get the corners and add them to a queue for use to use
    void SetupPath(NavMeshPath path)
    {
        cornerQueue = new Queue<Vector3>();
        foreach(Vector3 corner in path.corners)
        {
            cornersList.Enqueue(corner);
        }

        GetNextCorner();
        currentDistance = (transform.position - currentDestination).sqrMagnitude;
        hasPath = true;
    }

    // get the next corner, and set direction
    void GetNextCorner()
    {
        if(cornerQueue.Length > 0)
        {
currentDestination = cornerQueue.Dequeue();
        previousCorner = previousCorner;
        direction = transform.position - currentDestination;
         hasPath = true;
        }
        else
        {
            hasPath = false;
        }
    }

    // move towards the point
    void MoveAlongPath()
    {
        if(hasPath)
        {
            currentDistance = (transform.position - currentDestination).sqrMagnitude;

            if(currentDistance > minDistanceArrived)
            {
            
                transform.position +=  direction  * moveSpeed * Time.deltaTime;
            }
            else
            {
                GetNextCorner();
            }
        }
    }

 
    // Update the agent
    void Update()
    {
        MoveAlongPath();
    }

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 :slight_smile:

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 :slight_smile:

3 Likes

Hi,
There are errors in your code.
Could you help me?

Hey!
I’ve just edited his code for myself, it works:

private NavMeshPath _path;
private bool _hasPath;
private NavMeshAgent _agent;
private Queue<Vector3> _cornerQueue;
private Vector3 _currentDestination;
private Vector3 _direction;
private float _currentDistance;

void OnEnable ()
{
    InitVars();
    CalculateNavMesh();

    SetupPath(_path);   
}

private void CalculateNavMesh()
{
    _agent.CalculatePath(_targetPoint, _path);
}

private void InitVars()
{
    _targetPoint = GameObject.Find("EndPoint").transform.position; // Set target point here
    _agent = GetComponent<NavMeshAgent>();
    _path = new NavMeshPath();
}

void SetupPath(NavMeshPath path)
{
    _cornerQueue = new Queue<Vector3>();
    foreach (var corner in path.corners)
    {
        _cornerQueue.Enqueue(corner);
    }

    GetNextCorner();
    _hasPath = true;
}

private void GetNextCorner()
{
    if (_cornerQueue.Count > 0)
    {
        _currentDestination = _cornerQueue.Dequeue();
        _direction = _currentDestination - transform.position;
        _hasPath = true;
    }
    else
    {
        _hasPath = false;
    }
}

void FixedUpdate()
{
    MoveAlongPath();
}

private void MoveAlongPath()
{
    if (_hasPath)
    {
        _currentDistance = Calc.GetSqrDistLinear(transform.position, _currentDestination);

        if (_currentDistance > 1)
            transform.position += _direction * 0.4f * Time.deltaTime;
        else
            GetNextCorner();
    }
}
2 Likes

Thanks, yeah i was at work so it was written off top of my head without an IDE or looking at API :wink:

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.

1 Like

Glad you managed to get a solution up and running! :slight_smile:

@MadeFromPolygons_1 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?

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

1 Like