This project demonstrates how to use Godot's get_physics_interpolation_fraction() function to achieve smooth rigidbody motion no matter the physics tick rate (and its fluctuations) by decoupling visual representation from physics representation. With this project you can explore what happens when the physics tick rate and the render rate differ dramatically.
In Godot, and game platforms in general, smooth physics-body motion is achieved when the physics tick equals or exceeds the rendering rate (FPS) or when visual bodies are decoupled from their rigidbody representations.
We cannot reliably achieve the first goal, which leaves the second. Once you decouple a Rigidbody's visual representation from its physics simulation, you can update the visual body in _process and the physics body in _physics_process.
Learn about the magic ingredient here. This function tells us "the fraction through the current physics tick we are at the time of rendering the frame" e.g. [ Start_0.0 ... Physics Tick progress = 0.72 ... End_1.0 ] so, for the current rendered frame we are about three-quarters of the way through a physics tick. If we have movement code in _physics_process, it's not going to catch up until some future rendered frame, and when it does catch up it's going to teleport to the new location.
If we know how far until the next physics tick, we can lerp our positions during _process/idle and avoid any teleportation/stuttering when the physics tick falls below the FPS. This comes at a small cost: living in the past ever so slightly. We cannot lerp from the current position to an unknown future position -- actually, we can if we choose to make an educated guess of varying uncertainty, but here we want guaranteed smooth motion with no corrections so we'll stick with known, precise positions. We can only lerp from an object's prior last-known position (where it was before it got here) to its current known position (here!) while we wait for the latest physics tick to finish and return all object new positions.
Load the project, export a build and run it. If you run the project within the Editor it probably won't be as smooth.
The character controller and the blue balls use physics_fraction-decoupled rigidbodies, where their visual bodies update in _process, i.e. every rendered frame. The yellow balls are regular rigidbodies whose movement updates entirely inside _physics_process at the physics tick rate.
-
Balls
- Yellow balls
- These are plain rigidbodies that update their position during _physics_process. As the physics tick rate drops below the FPS, movement becomes more of a slideshow.
- Blue balls
- These balls got dipped in the magic sauce. Instead of combining rigidbody with a visual body (mesh), the blue balls are constructed with decoupled rigidbodies and visual bodies. With each rendered frame, the visual body lerps toward the last known physics position of its companion rigidbody according to how far through the current physics tick we are.
- Notice the yellow corona. That is a child rigidbody used to indicate where the physics server thinks the ball should be for that physics tick. As the physics tick rate falls you will see the yellow corona leading the blue visual body more and more. And yet the blue visual body will continue to move smoothly due to updating/lerping in _process/idle.
- Ball boost (left-CTRL)
- Give each ball some random acceleration. Hammer the boost key to really get those balls flying.
- Yellow balls
-
Player controller
- This also uses decoupled visual/physics objects to achieve smooth motion.
- Jump (spacebar)
- Might as well jump (jump). Go ahead and jump. Jump jump jump jump.
- You can wall-climb too.
- Infinite jump (home key /toggle)
-
FPS/Physics tick
- Cycle FPS (PGDOWN)
- Downshifts the FPS from 60 to 45, 30, 20, 10, 5 then back to 60.
- Key inputs will be slow to respond under 20 fps.
- Cycle Physics (PGUP)
- Downshifts the physics tick from 60 to 45, 30, 20, 10, 5 then back to 60.
- Cycle FPS (PGDOWN)
-
Make it rain (insert)
- How many cubes until your FPS drops? When you do hit that limit, try dropping the physics tick from 60 to 20 and observe how your FPS recovers due to the physics simulation running a third as often.
- Reddit discussion
- Devmar discovers the magic sauce - Youtube link