Jittery pathfinding movement after switch to RigidBody2D.MovePosition

Hi! Recently switched from using transform.position to RigidBody2D.MovePosition on my pathfinding movement updates. Turns out moving transform.position at runtime on a kinematic RigidBody2D was causing some CPU burn on SyncTransforms calls.

I moved my movement logic over to FixedUpdate, and swapped to RigidBody2D.MovePosition. This largely works, but now my enemies “jitter” backwards a bit at fixed intervals. I think it has to do with the ComputeNewPath calls in a coroutine being out of sync with the Physics update, but I’m not sure. Adding some reduced sample code below, as I could use some help if at all possible!

Here’s a video showing the effect as well. Spawned some quick pets that follow the player, but you’ll note they kind of snap backwards periodically. This does not happen if I directly manipulate the transform. https://youtu.be/JZZM_DGosqQ

ComputeNewPath:

protected virtual IEnumerator ComputeNewPath() {
    while (true) {
        if (IsVisibleOnScreen() && IsRunning() && targetToFollow != null) {
            AcquireTarget();
            Vector3 positionToChase = targetToFollow.transform.position;          
            seeker.StartPath(rigidBody.position, positionToChase + (Vector3)followDeviance, OnPathComplete);
        }
        yield return pathfindDelay;
    }
}

Movement Logic (Called from FixedUpdate):


  rigidBody.MovePosition(Vector2.MoveTowards(transform.position, path.vectorPath[currentWaypoint],
      speed * Time.fixedDeltaTime);


  if (Vector3.Distance(rigidBody.position, path.vectorPath[currentWaypoint]) < NEXT_WAYPOINT_DISTANCE) {
      currentWaypoint++;
      currentWaypoint = Mathf.Min(path.vectorPath.Count - 1, currentWaypoint);
  }

Just wanted to bump this, as it would unlock some major performance improvements for my game

Have you tried adding force instead? updating a rigidbodys position will cause that jumping motion since there is no constant velocity/acceleration with it and it makes it to snap to the position after the last physics update. Also are you using colliders? calling moveposition on a rigidbody will cause any collisions to push that object away/rebound

I think using Vector2.MoveTowards with a ever constantly changing path (path.vectorPath[currentWaypoint]) could potentially lead to that as well. If it was just one static path calculated once a while it might be different but you are chasing a dynamically moving object so I don’t think it will provide smooth movement

What version of the plugin are you using? I don’t think this is directly your issue, but I found this in the changelog:

  • Fixed the AIPath.velocity and RichAI.velocity properties being very jittery (and often completely incorrect) when a rigidbody was attached to the character.

That was in the first 5.0 update. Are you on a version past that?

I’m not sure if adding a force is appropriate here. This is a 2D top-down shmup style game, I want movement to be very tight. Adding forces tends to make movement feel more “natural”, but that’s not the aim here.

I’m on 5.1.1 (adding extra text here to allow this reply)

Hey so why did you change it from transform to rigidbody.moveposition then? Do you absolutely need a rigidbody for your game? Can you try just setting the rigidbody2d.position directly instead of rigidbody2d.moveposition()?

Hey I also found this quote from Aron on the forum, in another thread (AI Path not working with Rigidbody2D? - #2 by aron_granberg)

Hi

AIPath works with a rigidbody, but only by modifying its velocity directly. It does not move using forces. So it will collide with things, but it will not react to other kinds of forces.
To get a movement script that is force-based, you’d have to write your own. See Writing a movement script - A* Pathfinding Project

Maybe this could help with jittering, while staying performant? Let me know what you think of this idea. (EDIT: I see this is in reference to AIPath, not Astar as a whole, but it’s probably worth a try)

Yes, you still need RigidBodies if you want to use Unity’s collision detection. You don’t want to move a transform that has an attached rigidbody, or you’ll spend CPU every cycle on physics calls that sync rigidbodies with transforms.

That’s what I followed, and it caused the jittering.

Did some heavy frame-by-frame debugging here.

The issue seems to stem from calling Seeker.StartPath. If I have an entity simply follow a static computed path, it works fine! If I’m having it follow something dynamically like a player, where it updates its path every third of a second or so, I witness the “snap-back” the frame after the new path is computed.

This seems to occur because the Seeker is actually slightly behind the actual rigid body’s position, and you end up with your first waypoint being old.

As a hack to prove this hypothesis, I can actually set the current waypoint on the path to 1 instead of 0, which removes the jitter entirely.

Still makes me wonder if I’m doing something wrong, though. Seems weird to be out of sync like this.

Ah that makes sense then, because that tutorial linked in my comment was seemingly written with non-physics based unit’s in mind, such as with Unity’s built-in CharacterController.

It looks like you’ve found a workaround that works for you using Rigidbodies, however I did want to point out that you could use colliders on their own, and detect collisions without Rigidbodies. Just wanted to point this out in case it may be helpful information :+1:

I think if this works for you, this is perfectly fine. Let us know if you need any further assistance :slight_smile:

It looks like you’ve found a workaround that works for you using Rigidbodies, however I did want to point out that you could use colliders on their own, and detect collisions without Rigidbodies. Just wanted to point this out in case it may be helpful information

This is only sort of true. Objects without Rigidbodies are static world colliders, essentially. If you want to automatically invoke collision, at least one of the involved parties needs to have a Rigidbody to be part of the simulation. Two objects with no Rigidbody won’t collide unless you’re processing collision events manually.

Oh- my god, sorry, you’re 100% right. Do not do tech support before finishing your coffee, that’s my advice to everyone :slight_smile:

Thats exactly what i said about dynamically changing objects you are following but yes essentially

No, it isn’t. The bug is related to the sync between the callback on Seeker path complete and the physics cycle. Dynamically setting a rigid body position is fine and intended by Unity. The Seeker path callback was causing a rollback, as it occurs on the main thread instead of the physics thread pool.

The Seeker path callback was causing a rollback, as it occurs on the main thread instead of the physics thread pool.

Yeah, makes sense. Good find, actually! Just another thought I had (hopefully the coffee is working this time and my brain is actually on for this one): This may not be useful now, but if something similar to this pops up, but I wonder what ways yield WaitForEndOfFrame could be useful, maybe even in combination with LateUpdate(). I don’t know if this is a solution for movement based code, as anything dependent on checking position would happen before, but just a thought!

Yeah, had been considering that as well. WaitForEndOfFrame will just cause more trouble since the main thread rendering is perpetually out of sync with the Physics pool by design. This is also why moving Rigidbodies via transform.position is bad, Unity is forced to sync transforms, which for me is about ~4ms of time per frame.

LateUpdate is actually an interesting idea to mitigate this as well. It’s essentially the same as incrementing the waypoint, but might be less spaghetti.

1 Like

Sounds like a plan- definitely keep us updated with what you settle on! Would be helpful for me to know :slight_smile: