There are many causes for objects to stutter when being moved in Unity. This guide explains the different options for smooth movement and explains what lerping and deltatime are as well as how to use them! (Very important and useful to learn when developing Unity games)
Possible causes for movement jitter
Not using a rigidbody:
- Script not taking frame rate into consideration when moving an object without a rigidbody.
An object being moved 1 pixel per frame would jump and change speed as the frame rate changes! - Position not being lerped or interpolated.
Lerping will smoothly blend from position a to position b, read the lerping section below for more info!
When using a rigidbody:
- Interpolation not set when using a rigidbody.
Select your rigidbody and set interpolation, explained more below in the rigidbody movement section. - Rigidbody is marked as kinematic.
Kinematic rigidbodies will act as if you’re just setting .position of the rigidbody. - Rigidbody doesn’t have a collider, or using a non-convexed mesh collider.
A rigidbody without a valid collider can have unexpected physics issues. - Script interacting with rigidbody isn’t ran in the FixedUpdate() loop
Make sure any per-update code interacting with the rigidbody is inside the FixedUpdate function so it’s ran per physics update! - Physics timestep is set too high in the time manager
The physics timestep is the amount of seconds between each physics update, if this value is set too high it can result in jittery movement
Less common issues which I’ve seen in the past:
- Scale of the object you’re trying to move is either massively too big or very tiny
Aim to keep your your objects based around a 1, 1, 1 scale - Multiple pieces of code trying to move the same object at once
Try adding some debug logging to make sure the movement code isn’t being called multiple times – if not disable it and make sure no others scripts are moving the object! - Setting the position of an object which already has a rigidbody with gravity
Directly setting the .position of a moving object per frame will create a lot of stuttering.
Adapting movement to the framerate with deltatime
Moving objects based on frame rate is very important for creating smooth movement. Otherwise when the frame rate of the game changes, the speed of the objects will also change!
Unity has a variable named deltaTime (Time.deltaTime) which gives the time in seconds since the last Update() call as well as fixedDeltaTime (Time.fixedDeltaTime) which is the constant time since the last FixedUpdate() (Which is a consistant value changed in the time manager or directly changed via script, but it’s handy to have) (Tip: Using Time.deltaTime inside a FixedUpdate() will give you the fixedDeltaTime value)
Note: Using only deltaTime alone may still give stutter at lower framerates or at higher movement speeds. You will want to use deltaTime movement in combination with either lerping or a interpolated rigidbody! (Both explained in their sections below!)
But wait.. how does the deltaTime help me with slower movement?
Lets say you have a ball moving across the screen at 1 pixel per frame. If the frame rate of the game is 100 then the ball will have moved 100 pixels in 1 second. If the game is running at 10 frames per second (you can never be sure what frame rate you game will be running at on all systems!) then the ball will move 10 pixels in 1 second, meaning it’s moving 10 times slower!
We can use the time since last frame (deltaTime) to instead move the ball by (deltaTime * speed) pixels per frame which will make the ball always travel the same distance over the same amount of time, moving at a consistent speed. This is because as the frame rate is lowered the time since last frame actually increases and visa-versa for lower frame rates.
How does lerping work?
Lerping is where you interpolate a value from start to finish, this basically means to fill in the gap between start and finish gradually. An example is if you’re wanting to lerp from A to Z instead of jumping directly you could jump to everything in between to make the change feel smoother. (A, B, C, D, E… etc)
Unity Lerp Functions
Unity has a several lerp functions for various variable types, but this guide is explaining smooth movement so I’ll be focusing on Vector3.Lerp but referencing Mathf.Lerp for explaining some basics.
Vector3.Lerp takes 3 parameters: Vector3 start position, vector3 end position and a float lerp value. The lerp value is a float between 0 and 1 and determines which ‘in between point’ from start to end should be returned. For example using the Mathf.Lerp function. (which is used for lerping float values) If we called Mathf.Lerp(0f, 10f, 0.5f); it would return 5f as that’s 50% of the way between the start of 0 and end of 10.
Using Lerps
One option for using Vector3.Lerp is to completely move from a starting position to an end position over time. You would create a variable to count over time, increasing it by (Time.deltaTime * countingSpeed) then use it as float lerp value to smoothly generate a vector3 position which moves from start to finish. (You would then set the .position of the transform you wanted to move each time the lerp is updated)
Another way to use Vector3.Lerp is to lerp from the previous position to the wanted position and use deltatime as the lerp value:transform.position = Vector3.Lerp(transform.position, wantedPosition, Time.deltaTime * lerpSpeed);
Rigidbody movement
Rigidbodies are the names of physics objects in Unity. Attach the rigidbody component and you are given several options for gravity, interpolation and collision. (Note: Make sure your rigidbody has a collider roughly matching the mass of your object or you may experience unexpected weird physics)
The interpolation setting on rigidbodies controls movement smoothing, with this disabled movement will appear to stutter, especially on a fast moving rigidbody with a higher timestep value!
Interpolate or extrapolate?
Setting the rigidbody to interpolate will make the rigidbody act similarly to a normal lerp, it’ll lag behind the wanted position more if the rigidbody is moving fast. Extrapolation predicts movement based on the current velocity of the rigidbody which allows it to keep up when the rigidbody is moving fast. However extrapolation can result in a mild ‘rubber banding’ effect where if the rigidbody hits a collider at high speed it may appear to clip inside or through it for one frame until the rigidbody realizes that the collider is there in the next frame.
Moving a rigidbody
Once your rigidbody is setup with interpolation, kinematic is unticked and it has a collider attached (make sure if you’re using a mesh collider it is marked as convex!) you can now move it via a script.
If you just want to directly move it into position with your own Vector3 value then make sure you’re updating the position inside of the FixedUpdate() method which is called every fixed update. (physics update frequency is set by the Fixed Timestep value inside the Time Manager)
To set the position of a rigidbody whilst also using its interpolation settings, call:
myRigidbody.MovePosition(wantedPosition);
Alternatively if you need to force set the position of your rigidbody call:
myRigidbody.position = wantedPosition;
Quick Overview
Time.deltaTime = Time since last frame (aka last Update() call)
Time.fixedDeltaTime = Contant time since last fixed physics update (aka last FixedUpdate() call)
Vector3.Lerp(startPosition, endPosition, lerpValue) = Lerp value is a value between 0 and 1 which acts as a percentage returning a vector which is ‘lerpValue’ percent between startPosition and endPosition
myRigidbody.MovePosition(wantedPosition) = Tell a rigidbody to move into position (Using interpolation to smoothly move to the position based on interpolation settings and only if isKinematic is false)
Fabulous, what a blog it is! This web site provides useful facts to us, keep it up.
Thank you very much for sharing your knowledge! For me it turned out to be the interpolation setting. Learning something new every day!
Overall a very good article, a couple of minor issues, one possibly just my preference but worth pointing out.
Small math error in “But wait.. how does the deltaTime help me with slower movement?”. Going from 60 fps to 10 fps is only 6x slower. Doesn’t effect the meaning, but messes with the analytical side of my brain
Time.fixedDeltaTime would be better described as the constant time between physics updates, set in the physics settings. As written it could be mistakenly believed it is variable like Time.deltaTime.
Thanks, glad you liked it!
Haha whoops I’ve corrected the error, 60 has been changed to 100 to make the example correct whilst keeping the smooth 10x lower for easier understanding.
I’ve also re-worded some of the parts referring to Time.fixedDeltaTime to explain that it’s a constant time value. However note that Time.fixedDeltaTime can still be changed via scripting at runtime as well as from the time manager in the editor so it still basically is just a variable 🙂
thanks a million! It was the FixedUpdate() solution for me.
Useful site, thanks man. been scratching my head about the stuttering thing.
thank you internet
I love u ;P +rep
Thank you Man, you made my day.
The problem for me was the RigidBody2D wasn’t using interpolation.
I don’t know what interpolation is and will learn it now.
Amazing! You have saved me. I thought it was my frame rate problem, but it is my movement problem.
Thanks! Saved me a lot of time!
Thank you , this is very helpful.