How to smooth character movement that is jittery

Hi everyone,

I’ve done a bunch of searching for an answer, and can’t seem to find anything that has helped. In a nutshell, my character’s movement is jagged/jittery and I’m trying to smooth it out. However, there is a slight wrinkle compared to other answers I’ve researched: the character is currently being moved in 2 ways: 1) with a transform.Translate using a speed variable in the local z direction, and 2) when the user presses a button, I am calling rigidbody.AddForce in the y direction (resulting in a jump). Both of these forms of movement are occurring in the Update function in my character controller script. The character is a prefab, instantiated at run-time. The character moves smoothly in the z direction, but when it jumps or falls in the y direction the movement appears jagged and not smooth (sort of like a sawtooth, up/forward/up/forward/up/forward really fast… appears to be each frame from my guess).

At first, I thought the issue was my camera follow script, which uses a Vector3.Lerp to follow the character. However, when I disable the camera follow script so the camera doesn’t move, the character’s movement still appears jittery/jagged when moving up or down (same as when the camera follow script is enabled).

Any ideas how to fix? I was thinking of using a Lerp to move the character, but unsure how to determine what my target position would be. Maybe there’s a better way. I’ve also tried using interpolate/extrapolate on the character’s rigidbody, but this did not change anything.

-pete

“jitter” problems are tough to debug without a video demonstrating the issue, as there are many different things that can cause jitter. I have two leading theories for what you describes:

a) Your physics is operating at a slower framerate than your game. In Edit → Project Settings → Time, what is your fixed timestep?

b) Your transform.Translate and the physics engine are interacting badly. Choose either physics or manually moving the transform, and stick with it. (Note that you can directly set the Z element of the velocity vector and probably accomplish the same thing you’re trying to.

In either case, having the camera move every frame to follow a character that might not be moving every frame (e.g. is being move with physics) is definitely a source of apparent jitter, even if it’s not your only source. If your camera moves by lerping towards the character, do that lerping in FixedUpdate.

2 Likes

Thanks for the advice, StarManta. QuickTime keeps crashing, so my video isn’t working yet - although now that I’m looking really closely at the issue, it appears that the player is jittery on all movement, even in the forward direction, when the camera follow is disabled. Especially jittery in the up/down though.

a) My fixed timestep is 0.02, I haven’t changed it.
b) I was originally using only physics to move the character (AddForce: VelocityChange), but it resulted in a bumpy forward movement across the floor (which is a cube prefab), so I switched the forward movement to the transform.Translate and the bumpiness went away. Maybe I need to change the up jump movement into a transform.Translate?

-pete

That’s a viable solution. If the only physics you need is jumping up then falling down by gravity, physics is reeeeally simple to roll yourself - add (velocitydeltaTime) to position, then add (gravitydeltaTime) to velocity, every frame; for keeping on the ground, when y < someValue, y = someValue and velocity = 0.

Going the physics-only route: if you want to use physics in a case like this, I’d suggest setting rigidbody.velocity directly, rather than AddForce. The bumpy movement might be contributed to by the physics material of your cube and/or the shape of it. You might try creating a physics material with no friction, or replacing your cube collider with a sphere (the actual shape of the thing be damned) (make sure you set the constraints on it so that it doesn’t rotate if you do this).

Finally got QuickTime to work. Here’s the short clip of the jittery movement. It’s more pronounced in the video than in reality, but represents what is happening.

I will try the physics only route, using StarManta’s suggestions about setting rigidbody.velocity directly, and post an update in a while.

I did something wrong in setting this up… not sure how to solve with rigidbody.velocity. Here’s my revised player movement code:

voidFixedUpdate()
{
//move player forward or left, depending on rotation
if (rotatedLeft == false)
rb.velocity = newVector3 (0, 0, zSpeed);
else
rb.velocity = newVector3 (-zSpeed, 0, 0);

//player jump
if (jumpInputReceived == true) {
rb.velocity = newVector3(0, jumpYVelocity, 0);
jumpInputReceived = false;
}

}

It seems that the full vertical movement of the jump is not happening before the next FixedUpdate begins moving the player forward again. Since the player forward movement (rb.velocity = new Vector3(0,0,zSpeed)) has 0 in the Y direction, the jump only occurs for the 0.02 timestep until FixedUpdate fires again, I’m guessing. So the jump is too short-lived to be a full jump.

Any ideas how to solve this? Also, my code formatting sucks when I post - sorry (I’ll figure out how to fix).

If “rotatedLeft”, as the name suggests, supposed to rotate this thing? What’s your logic here - what’s the intended behavior? Let’s go back to the drawing board a little bit.

As for the immediate problem, every time you set the velocity in the top part, you’re overruling the jump from the previous frame. If you want to change the X or Z velocity without affecting the Y velocity, do something like this:

rb.velocity = new Vector3(someNewValue, rb.velocity.y, someOtherNewValue);

And the inverse of that for when you jump.

Oh man thank you, my problem was just running a Camera Lerp in LateUpdate(). I guess this is because Lerp shouldn’t be frame dependent yeah? Even though it is practice to move the camera only after the target object has moved. But in this case it is the exception.

So normally doing camera movement in LateUpdate is exactly what you want to do. But the combination of smooth camera movement + character movement in FixedUpdate (or physics) is an edge case. The reason it’s weird is because FixedUpdate can run an inconsistent number of times for each game frame, and with smooth camera movement, the movement is different when the target has moved a differing amount between game frames. This specific combination is really the only situation where you want to do camera movement anywhere but LateUpdate.

1 Like

Just gonna mention here that they recommend calling MovePosition in the FixedUpdate function in the Unity documentation. Here’s the link.

thanks

Use AddForce() instead of MovePosition(). MovePosition() is an instant teleport so it can cause problems.
Use Slerp() for smooth movements, but Slerp() must be in Update() or LateUpdate() depending on your character. Slerp() does not seem to work well with FixedUpdate().