A* Pathfinding Project

Problem with RVO deltas


Hi Aron,

I’ve been using the RVO system, and I’ve been having great results. I have a little issue though that I can’t figure out.

I’ve got everything coded so that if a moving NPC comes near enough an idle NPC, the idle NPC will try to avoid the moving NPC (like, get out of its way). At the same time, the moving NPC also tries to avoid the idle NPC while on its way to its destination if possible. Moving NPCs get higher priority than idle NPCs.

In other words, they both try to avoid each other whenever possible, idle or moving. Both use the RVO system paired with Unity character controllers. This is the relevant piece of code for the “idle” avoidance:

 if (idle) 
 	_astarRVO.SetTarget(transform.position, speed, maxSpeed);
 	var delta = _astarRVO.CalculateMovementDelta(Time.deltaTime);

edit: this runs on Update()

It works perfectly. My “moving” avoidance works perfectly too.

But for some reason, after they’ve “collided” and succesfully avoided each other, when either of them become idle again, they start “shaking” in unison. The CalculateMovementDelta() function’s deltas start winding down properly after stopping, and then suddenly, in both NPCs, starts returning these exact same little values (but not so little to be related to floating point precision), and the weird thing is the “shake”: each frame, it’s returning the exact same delta but sign flipped. Like, x = 0.0036 this frame, then x = -0.0036 in the next frame.

My NPC movement code, while the same for both NPCs, is separately instanced for each NPC, completely independent from each other.

If you make the NPCs collide again, the same thing will happen. All goes perfectly when avoiding each other, then shakes come on when they become idle and the above code gets run. Different little values each time, but same pattern of back and forth little deltas, flipping signs every frame, and the exact same little delta on both characters who have collided, even if they’ve become idle very far from each other a long time after colliding.

I could “fix” this by setting the minimum movement distance on the character controllers to like, 0.35, but that’s problematic for a lot of reasons.

Any ideas?



Likely what is happening is that you are hitting some kind of resonance frequency. RVO information takes at least 1 frame to be calculated so what could happen is this:

  1. Your agent is at point A, it tells the RVO system that it wants to move to point A. The RVO system this frame tells the agent that it should move to point B (which is very close to the current position). Your character moves to point B.
  2. The next frame the agent tells the RVO system that it wants to move to point B as that’s where it is right now. However the RVO system has updated the movement information, so it tells the agent that it should move to point A, which is the target point that was set during the previous frame.
  3. The next frame everything repeats from step 1 resulting in a shaking behavior.

(depending on the Desired Simulation FPS set on the RVOSimulator component, the above steps may be separated by more than 1 frame)

The way that the built-in movement scripts try to avoid this is to reduce the desired speed significantly when it reaches the destination. In your case you should be calling

_astarRVO.SetTarget(transform.position, 0f, maxSpeed);

Also note that if the ‘lock when not moving’ field on the RVOController is enabled, then the above call will make the RVOController ‘locked’ which means it will not avoid other agents. This may or may not be desired in your scenario so you may want to change the value of that field.


You’re the man! That did it.

This was driving me crazy, I thought the SetTarget() speed arguments were meant to mean “avoid at this speed if possible, or at up to this other speed if that’s not quick enough”, I never would’ve thought about setting the former to zero.

Thanks for the heads up on the lock, it is indeed relevant in my scenario.

Fantastic support on your part as always! So quick, and accurate! Thanks!