FollowerEntity agents do not avoid or yield to each other despite RVO settings

Unity Version: 6000.0.26f1
A* Version: 5.3.4

Hello, I’m currently using RecastGraph, FollowerEntity, and RVO Simulator in my project.

I’m trying to make it so that when one agent moves to a position occupied by another agent, the existing agent would either move aside or get pushed. However, this isn’t happening — agents just stand still and don’t respond to each other at all.

Here’s what I’ve checked so far:

  • FollowerEntity.localAvoidance = true
  • FollowerEntity.locked = false
  • RVO Simulator is active in the scene

Despite these settings, agents completely ignore each other and do not attempt to avoid or yield in any way.

This video demonstrates the issue for clarity:
:point_right: Video

Is there something I’m missing, or any way to enable proper avoidance or displacement behavior between agents?

Any advice or suggestions would be greatly appreciated. Thanks!

Hi

This is actually expected. The FollowerEntity has special code to ensure that if multiple agents try to reach the same destination, they’ll not try to push each other out of the way indefinitely.

You’ll see that if you set the target past the other agent, they will be pushed/move out of the way.

You can disable this behavior by commenting out these lines in the RVOSystem.cs file, but honestly I think the resulting behavior looks worse in pretty much all situations.

1 Like

Thank you for the explanation!

If I don’t comment out the code as you advised,
is it possible to modify the agent’s destination to make it stop,
in case it has reached or nearly reached its target but is being blocked by another agent?

Hi

It should do so automatically. How are you telling the animation system that it should play the walking animation?

Here’s the logic I’m using to control the animation:

  public void SetDestination(Vector3 destination)
  {
    ai.destination = destination;
    player.SetInMove(true); // Play Move Animation

    if (inMoveLoopCoroutine != null) StopCoroutine(inMoveLoopCoroutine);
    inMoveLoopCoroutine = StartCoroutine(InMoveLoop());
  }

  IEnumerator InMoveLoop()
  {
    while (!ai.reachedEndOfPath && IsInMove)
    {
      yield return null;
    }
    player.SetInMove(false); // Stop Move Animation
  }

Hi

The agent will not necessarily have reached the end of its path when it is blocked by another agent. I would recommend using something like this for animations:

playRunningAnimation = ai.velocity.magnitude > 0.1f

You can even expose ai.velocity.magnitude to mecanim, and have transition thresholds based on that (generally nicer to include some hysteresis in the thresholds).

Thank you very much for your response.

However, due to the nature of my game system, I need to specifically determine whether an agent is being blocked by other agents.

Because of that, I’m interested in the logic behind how Reached is evaluated in the RVOSystem:

public enum ReachedEndOfPath {
    /// <summary>The agent has not reached the end of its path yet</summary>
    NotReached,

    /// <summary>
    /// The agent will soon reach the end of the path, or be blocked by other agents such that it cannot get closer.
    /// Typically the agent can only move forward for a fraction of a second before it becomes blocked.
    /// </summary>
    ReachedSoon,

    /// <summary>
    /// The agent has reached the end of the path, or it is blocked by other agents such that it cannot get closer right now.
    /// If multiple agents have roughly the same end of path, they will end up crowding around that point,
    /// and all agents in the crowd will receive this status.
    /// </summary>
    Reached,
}

Could you please explain the conditions or logic that determine these states?

Alternatively, is there a way to check the current Reached status of a specific agent at runtime?

Thank you again for your help!
----Edit-----
After adding some debug logs, I realized that Reached does not actually mean the agent has reached its destination.
So it turns out I don’t need that information after all.
I’ll try to solve it on my own. Thank you!

In the next update, I’ll add FollowerEntity.reachedCrowdedDestination which exposes the ‘Reached’ state mentioned above.

1 Like

That sounds like a very nice and helpful update — thank you for adding it!
Looking forward to trying it out in the next version.