Jittery rotation for RVOAgents

I am using the latest A* Pro 4.2.11 for my project.
In my project agents are using RVO for local avoidance, but while chasing player on gridgraph(using AIPath + Kinematic RigidBodies) they sometimes have very weird jittery rotation.

Can i filter/smooth out RVOAgents rotations so as to eliminate this sudden rotation changes.


1 Like


The current beta (see https://www.arongranberg.com/astar/download) has some improved rotation filtering when using RVO. It’s still work in progress though and there are still some cases where I’d like to improve the result.

Thanks for suggestion I tried the latest 4.3.11 on 2019.3f5 and i can confirm it has almost eliminated 90% of the rotation jitters happening before in RVO.
But is it possible to back-port these changes to 4.2.X branch as Unity 2019.3 is still not production ready with many packages still in preview states?

1 Like



I think that rotation filtering code could be backported. The AIPath script has has code for applying that filtering. I can’t remember exactly what part of the code it is since I don’t have access to the code right now, but I think if you open the script up you should be able to find it fairly easily.

I need same fix and i have same jitter problem.

I have also jittering rotating, i am using 2018.3 but cant updagrade to 2019.3, there is a solution for this? Game would be unplayable with this jittering

I also have jittery rotations when using RVO with Rich AI on navmesh grid. Here is an example: https://imgur.com/a/J54WtZN

When I remove RVO controller, it does not do the jaggy movements near its target.

Also, changing the Priority on the RVO controllers changes how jaggy the movements are as well. It looks like it’s fighting itself or something.

In your case the agent is being ordered to walk inside another agent. It tries to avoid it by going to one side, but that causes some jitter as it cannot decide which side.
Possible solutions:

  • Upgrade to the beta version. I think it will be smoother in this case.
  • Use a higher ‘symmetry breaking bias’ on the rvo simulator.
  • Order the agent to walk not inside the other agent, but to a point in front of it. It is trying to attack, so the goal is only to walk up to the enemy, but not inside it. This illustration might be useful too: https://arongranberg.com/astar/docs/iagent.html#SetTarget

Thanks Aron. This will be my approach, can you check it?

  1. Get a path to the original, center of an object.
  2. Reduce the path length backwards by say, 2 units to place it outside of the center of the unit.
  3. Pass this new, reduced path to the seeker.

Any thoughts on how I do #2, if this route at all? If I can do it this way, it will keep me from messing up the pathing by trying to set the transform on the edge of the side of the unit depending on which way my player is facing it from.

Edit: I think you gave an answer here: Shorten a path, endpath condition question

Would XPath and PathEndingCondition work here or should I use the custom Trim code in that link? It would seem to me that I need to trim the path up front so that the player doesn’t get confused on how he approaches the center of the target, whether or not he stops early from PathEndingCondition or not. Right?

Also, what do I feed into:

(List<Vector3> pts, float totalLength)


So far from looking at the code base, it looks like the simplest route forward is adding the trim logic to the AIDestinationSetter’s update:

	void Update () {
		if (target != null && ai != null) ai.destination = target.position;

However, I cannot find where the “destination” property is used in any of the other scripts.

Edit 2: Actually I think I found the heart of what I need in RichPath:
// Initialize new Endpoint = path.vectorPath[path.vectorPath.Count-1];
I could trim that in a dumb fashion by just cutting more points off the end, but I’ll never know how long the points are in the first place and if I have cut off enough or not. So I’ll need to recalculate the path… now where is that happening in the first place…

Edit 3: The class/object design is incredibly difficult to follow, but I believe I traced the path construction back to ABPath.cs from this in Seeker.cs:
public Path StartPath (Vector3 start, Vector3 end) { return StartPath(start, end, null); }

Edit 4: Spent a couple hours drawing out the object/class mapping with methods pointing to each other. I think this is the area I should trim the path, please let me know:
Seeker.cs line 331:

        /// Called when a path has completed.
        /// Will post process it and return it by calling <see cref="tmpPathCallback"/> and <see cref="pathCallback"/>
        /// </summary>
        void OnPathComplete(Path p, bool runModifiers, bool sendCallbacks) {

Edit 5: This can’t be the right spot ^. A new path keeps being calculated mid way through the travel based off the start and end. I must modify the end/destination immediately and then store that for the rest of the path calculations. I must calculate a path at least once though first. Where should I do that?

Edit 6: Still working at this. I edited OnPathComplete to this:

void OnPathComplete(Path p, bool runModifiers, bool sendCallbacks) {
            if (p != null && p != path && sendCallbacks) {

            if (this == null || p == null || p != path)
            Debug.Log("vectorPath Count before trim - " + p.vectorPath.Count);
            p.vectorPath = TrimPath(p.vectorPath, p.GetTotalLength(), 5f);
            Debug.Log("vectorPath Count after trim - " + p.vectorPath.Count);
            //p.vectorPath = null;

It doesn’t work. I mean, it does work as determined by my debug logs and when I set p.vectorPath to null, but my player keeps moving (null = doesn’t move). I can’t figure it out. Is RichAI getting its path waypoints from somewhere else? Why is the trimmed path not being used?

Here is a link to my debug log. Everything is working from that standpoint. The path just doesn’t get updated and the player keeps moving as if it was never trimmed: https://imgur.com/a/vvTyMNJ


Sorry for the late answer @fgbg. As I think you have already moved on to another approach (which I think is better) in another thread I will answer those instead. But let me know if you still want me to explain some of this here.