Jittery movement with rigidbody.velocity and tracking camera

I’ve been trying to solve this issue for a while now, have come across several threads, but haven’t been able to figure out where I’ve messed up. I am procedurally generating a mesh terrain from a heightmap with a mesh collider. I’ve taken it into a separate project of it’s own to be sure nothing else was causing the issue.

My player object in this test project is just a capsule with a rigidbody, capsule collider, and a click to move script. Interpolate is turned on.

    void FixedUpdate()
    {
        if (_target != Vector3.zero)
        {
            Vector3 dir = _target - transform.position;
            float dist = dir.magnitude;
            if (dist < curMoveSpeed * Time.fixedDeltaTime)
            {
                rb.MovePosition(_target);
                dir = Vector3.zero;
                //anim.SetBool("Moving", false);
                _target = Vector3.zero;
            }
            else
            {
                dir /= dist;
                //anim.SetBool("Moving", true);
            }
            rb.velocity = dir * curMoveSpeed;
        }
    }

Also a script on the camera just to follow the target position, also using FixedUpdate.

I’ve tried Update, FixedUpdate, LateUpdate, both for the player and camera movement and individually. I’ve tried fixedDeltaTime, smoothDeltaTime, deltaTime, time… I’ve tried PhysicMaterials with No Friction…

After everything I’ve found and tried, my movement still seems ‘jittery’ to me. As if it moves in bursts of speed, rather than a constant smooth motion… So am hoping someone can help figure out what I’m doing wrong, or maybe suggest a different approach. Am just trying to achieve smooth movement across the surface of a mesh terrain that’s generated on startup. I’ve usually used navigation to handle all of my movement, but can’t in this project, so I feel like I’m probably overlooking something simple.
6938173--815272--jitterymovement.gif
Thanks for any help/suggestions!

6938173--815272--jitterymovement.gif

That does seem weird and jerky… but I also don’t quite follow your logic there. I see you setting its position but also setting its velocity.

Are you going to move it? If so, just only do the .MovePosition() to the new location you compute and leave the velocity at zero, so the physics does not move it.

If not, then only set the velocity towards where you want to go, let the physics do its thing.

Check also for frictions… seems like it might be dragging or snagging on the ground??

Also, to isolate the camera (which I don’t think is a problem), just turn off updating it. I think your object itself is making jerky motions, and the camera is just incidentally following it.

Also, don’t compare floating point (or Vector3s) for equality… they are very rarely precisely equal to each other due to floating point error.

I’ve been moving and changing the code around so much it’s gotten a bit messy, sorry. Also ended up using and pasting an older version where the encapsulation just wasn’t as clear to logically follow.

The movement itself I’ve been doing by setting rigidbody.velocity to direction * speed.

(Edit: I just tried removing the MovePosition entirely and it didn’t change anything. So, was just useless leftovers at this point lol)
the .MovePosition was just to bump it directly into position once they arrived. I did try using only MovePosition before, but I got closer to what I was looking for a lot faster using rb.velocity. Was having issues over/undershooting before.

The only reason I compared to Vector3.zero is because I was setting it directly to stop. So usually I’d agree, but in this case I’m just using it like a bool with a whole lot of yes and only one no, so I didn’t see a problem with that bit, though it may be weird.

For additional context, I’m setting _target to a position I click with a Raycast in Update. Then setting _target to Vector3.zero when the player arrives.

    private void FixedUpdate()
    {
        if (anim && _target != Vector3.zero)
        {
            Vector3 dir = _target - transform.position;
            float dist = dir.magnitude;
            if (dist < curMoveSpeed * Time.deltaTime)
            {
                //rb.MovePosition(_target);
                dir = Vector3.zero;
                _target = Vector3.zero;
            }
            else
            {
                dir /= dist;
                anim.SetBool("Moving", true);
                rb.velocity = dir * curMoveSpeed;
            }
        }

        if (anim && _target == Vector3.zero)
        {
            rb.velocity = Vector3.zero;
            anim.SetBool("Moving", false);
        }
    }

That snippet isn’t from the screenshot, but my main project. I’ve been changing up the same bit of code trying to make this work, but the encapsulation of this one maybe makes it easier to follow what I was trying to do.

I had also tried making a conditional around setting the velocity if I was currently moving or not, but that didn’t seem to help.

Also, I did try putting NoFriction materials on both the ground’s mesh collider and my player’s capsule collider, but didn’t stop the ‘burst of speed’ kinda movement. Am also just glad you thought it looked jittery as well, and I’m not just crazy. So thanks for that. lol

Edit: Also took your advice on eliminating camera, and got another view that makes the bursts of speed much more obvious.
6938302--815464--jitterymovement2.gif

I’m still trying other ways attempting to make this work…

Just redid it to use MovePosition instead, but am still getting same result.

    void FixedUpdate()
    {
        if(_target != Vector3.zero)
        {
            MoveToPos(_target);
        }
    }

    bool MoveToPos(Vector3 targetPos)
    {
        float remaining = Vector3.Distance(transform.position, targetPos);
        if (remaining > 1f)
        {
            Vector3 dir = (targetPos - transform.position).normalized;
            rb.MovePosition(transform.position + (dir * curMoveSpeed * Time.deltaTime));
            return false;
        }
        else
        {
            _target = Vector3.zero;
            return true;
        }
    }

results in this same jittery movement.
6941327--815951--jitterymovement3.gif

Any more ideas? I’m running out.
Still using the script from the post right above this.
Tried disabling my terrain mesh with a mesh collider and instead added a new blank unity terrain with a terrain collider…
Same thing.
6942560--816161--jitterymovement4.gif

What happens if you just replace it with good old MoveToward()?

var step = curMoveSpeed * Time.deltaTime;
var newPos = Vector3.MoveToward( transform.position, targetPos, step);
rb.MovePosition(newPos);

Then at the end of it check distance and return true / false and do that _target setting stuff afterwards?

If that doesn’t work then there’s something else interfering that we haven’t seen yet.

1 Like

Tried pasting it in there and I’m still getting the same jittery movement, unfortunately.
Edit: I even tried commenting out all the extra code I was using, with just your code alone inside FixedUpdate, and still it moved in bursts of speed rather than smoothly.

I’m really stumped at this point and don’t know what could be causing it… The only other info I can think of to say is that I left the fixed timestep alone, but I checked and it’s set to .02. Neither collider has a physic material attached… Even checked to make sure gravity was -9.81 lol…

It’s a very simple project at this point with just the terrain and a terrain collider, and a capsule with a rigidbody (w/ interpolate enabled), capsule collider, and this script attached. Just have the terrain layer set to ground, and checked ground on the script’s LayerMask.

Here’s the script in it’s entirety.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ThirdPersonController : MonoBehaviour
{
    private Rigidbody rb;
    private Vector3 _target;
    public float curMoveSpeed = 5f;

    public LayerMask clickMask;
    private RaycastHit hitInfo;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }
    void Update()
    {  
            if (Input.GetMouseButtonDown(0))
            {
                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

                if (Physics.Raycast(ray.origin, ray.direction, out hitInfo, Mathf.Infinity, clickMask))
                {
                    _target = hitInfo.point;
                }
            }
    }

    void FixedUpdate()
    {
        if(_target != Vector3.zero)
        {
            MoveToPos(_target);
        }
    }

    bool MoveToPos(Vector3 targetPos)
    { 
        float remaining = Vector3.Distance(transform.position, targetPos);
        Debug.Log(remaining);
        if (remaining > 1f)
        {
            var step = curMoveSpeed * Time.deltaTime;
            var newPos = Vector3.MoveTowards(transform.position, targetPos, step);
            rb.MovePosition(newPos);

            //Vector3 dir = (targetPos - transform.position).normalized;
            //rb.MovePosition(transform.position + (dir * curMoveSpeed * Time.deltaTime));

            return false;
        }
        else
        {
            _target = Vector3.zero;
            return true;
        }
 
    }
}

Bump, still looking for a solution.

rb.MovePosition(Vector3.MoveTowards(transform.position, targetPos, curMoveSpeed * Time.deltaTime));

That’s the most recent way I’ve tried doing it. Essentially the same thing, so of course it had the same resulting stuttered movement.

I tried swapping the collider types/shapes around too. Put a box on the capsule, tried both a convex mesh and box collider on a cube, and still. Tried with and without no friction materials. I tried interpolation on, off, and extrapolation. Tried all the collision detection settings- discrete, continuous, etc… Made sure to test in a standalone build as well, to make sure it wasn’t only happening in the editor…

Would really appreciate any more suggestions about things I can try. I’m really running out of ideas of what could be happening.

Just in case… did you check the isKinematic property of the rigidbody ? MovePosition uses Kinematic rigidbodies for a proper use of physics.

It has NOT been checked, no. Before, that meant nothing moved… now when I turn it on, it does move with is Kinematic checked, but it’s still jittery. and also gravity stops having an effect on it. However I didn’t realize that MovePosition worked while is Kinematic was turned on, so while it didn’t solve my stuttered movement and is still just kinda bumpin’ along, I did just learn something new. So, thanks for that, and for giving me something else to try out.

Some remarks:

var step = curMoveSpeed * Time.deltaTime;

Inside FixedUpdate (which calls MoveToPos) you should use Time.fixedDeltaTime.

MoveToPos(_target);
...
bool MoveToPos(Vector3 targetPos)
...
_target = Vector3.zero;

I find it a bit “undesirable” how you mix up member and method parameter. If your _target is valid just let the method move towards it. Then you don’t need to pass it inside your method (thats what class members are for).

if (remaining > 1f)

Why do you stop 1 unit away from your target?

Are you aware that FixedUpdate can be called zero, one or multiple times per frame? Could your jittering be caused by this?

Why is the color of the red thing flickering? Is there something else going on? Do you have multiple objects to move?

I would suggest that you log a frame index inside update and a notification of fixed update happening. Maybe that leads to new conclusions.

From what I understand, deltaTime will automatically return fixedDeltaTime on it’s own when called from FixedUpdate. So I don’t think it matters? But as I said above, I have tried all the options, smooth as well, but it hasn’t help my stuttered movement.

I agree it’s not ideal and has gotten messy. Again, I have been changing and pasting things and ending up with extra bits while trying to make this work.

Reason I threw in the distance check was because it’d reach the destination I clicked, and it would start bobbing up and down trying to reach the position, but the physics would push it back up. So, I just stopped it < 1f as a quick fix. setting _target.y = transform.position.y also got rid of the bobbing.

To be clear, I’ve tried reducing the code to a minimum of just trying to move the object towards the position, while I manually set the position in the editor. It still jittered. While the rest of my code may be a mess, I’ve already tried without all of it to the same results, so the rest is either there for my convenience or was just clutter from pasting while trying to make this work. But rest assured, I promise I will clean it up once I figure out a way to do this that works. =P

The red flickering is from the software I used to make a .gif and trying to keep the filesize down. Just not best quality, but yeah that’s just the .gif

As far as the FixedUpdate / Update timings… I’m aware of how often they are called, yes… Just in saying that fixed update uses the fixed timestep of .02, and update is updating every frame. So depending on your FPS your Updates get called more/less often. Do I claim to have a complete understanding of everything that means? Absolutely not. So, I have no idea if that could be causing it? I’m not even entirely sure what you’re suggesting exactly…

Same with logging a frame index, I’m not sure what that really means… Just debug.log Time.currentFrame in both to see if it’s insightful? That’s what I just tried… can’t say it really told me much. Some frames only Update was called, some FixedUpdate was called once, some several times… I also went to the docs and grabbed the script from the FixedUpdate() page to compare update / fixedupdate calls per second on screen, and made a quick .gif… Perhaps it’ll be more insightful for you than it was me?
6949565--817469--jitterymovement5.gif

Anyways, thanks for giving me some suggestions and things to think about… But unfortunately, am still jittery, and have no idea what to do next.

Well, hell… I guess it was just lag. I feel dumb. So what had happened was…
I restarted my computer and loaded only a standalone build. Smooth movement.
Launched unity and hit play, stuttered movement.
Hit ‘Build and Run’, leaving Unity open, stuttered movement.
Closed Unity, ran only the standalone build, and smooth movement again.
I am an idiot. lol

So, I appreciate the help and suggestions!
But it was just my CPU/GPU crying, I suppose.

As a last question, in case anyone reads this, would it be my GPU that’s the issue here? I am thinking the physics engine uses the GPU to calculate/process stuff? Or would it be my CPU? or some combination? Are there any settings I can look at to optimize the performance a bit, maybe a lower quality for something that would effect this?

I have an Intel Xeon E3 and Geforce GTX 1060 - but I have had some issues with my GPU downclocking itself to an idle speed when I didn’t want it to, so another reason I was assuming that could be what my problem was.

Anyways, know this isn’t general tech support forum, so I will take that issue elsewhere. But in case anyone has a similar problem in the future, consider it’s just lag. lol…
Thanks again.

See this article by Jackson Dunstan about How FixedUpdate Works.
He gets the following log:

FixedUpdate called on frame 1
FixedUpdate called on frame 3
FixedUpdate called on frame 3
FixedUpdate called on frame 3
FixedUpdate called on frame 5

If you had a similar pattern there would be frames where the object is not moved at all and frames where it is moved multiple times. I don’t know if that can produce such a pattern you are experiencing but this would be my best (and only) idea/guess.[/quote]

I made a test with exactly the code you posted above

It seems working as expected

zsf88i

EDIT
It also works the same way without the MoveTowards() (your code)

void FixedUpdate()
    {
        if(_target != Vector3.zero)
        {
            MoveToPos(_target);
        }
    }
    bool MoveToPos(Vector3 targetPos)
    {
        float remaining = Vector3.Distance(transform.position, targetPos);
        if (remaining > 1f)
        {
            Vector3 dir = (targetPos - transform.position).normalized;
            rb.MovePosition(transform.position + (dir * curMoveSpeed * Time.deltaTime));
            return false;
        }
        else
        {
            _target = Vector3.zero;
            return true;
        }
    }
1 Like