Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to smooth character movement that is jittery

Discussion in 'Scripting' started by petediddy, Apr 29, 2015.

  1. petediddy

    petediddy

    Joined:
    Mar 17, 2015
    Posts:
    19
    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
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    "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.
     
    boyanbotev and JosephUnity like this.
  3. petediddy

    petediddy

    Joined:
    Mar 17, 2015
    Posts:
    19
    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
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    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 (velocity*deltaTime) to position, then add (gravity*deltaTime) 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).
     
  5. petediddy

    petediddy

    Joined:
    Mar 17, 2015
    Posts:
    19
    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.
     
  6. petediddy

    petediddy

    Joined:
    Mar 17, 2015
    Posts:
    19
    I did something wrong in setting this up... not sure how to solve with rigidbody.velocity. Here's my revised player movement code:
    Code (csharp):
    1.  
    2. voidFixedUpdate()
    3. {
    4. //move player forward or left, depending on rotation
    5. if (rotatedLeft == false)
    6. rb.velocity = newVector3 (0, 0, zSpeed);
    7. else
    8. rb.velocity = newVector3 (-zSpeed, 0, 0);
    9.  
    10. //player jump
    11. if (jumpInputReceived == true) {
    12. rb.velocity = newVector3(0, jumpYVelocity, 0);
    13. jumpInputReceived = false;
    14. }
    15.  
    16. }
    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).
     
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    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:
    Code (csharp):
    1.  
    2. rb.velocity = new Vector3(someNewValue, rb.velocity.y, someOtherNewValue);
    3.  
    And the inverse of that for when you jump.
     
  8. JosephUnity

    JosephUnity

    Joined:
    Oct 4, 2019
    Posts:
    1
    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.
     
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,773
    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.
     
  10. Deleted User

    Deleted User

    Guest

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

    Srivishwanath_Rajavelu

    Joined:
    Jul 17, 2020
    Posts:
    1
  12. Leohd

    Leohd

    Joined:
    Feb 7, 2017
    Posts:
    32
    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().