Fixed timestep interpolation gdscript addon for Godot 3.2 (and later versions)
If you were wondering how to use that new function Engine.get_physics_interpolation_fraction()
in 3.2, feel free to use this as is, or to get ideas from for your own version.
If you find bugs / have suggestions, please add an issue to the issue tracker and I will look into it! :)
The smoothing addon adds 2 new nodes to Godot, 'Smoothing' (for 3d) and 'Smoothing2d' (for 2d). They allow for fixed timestep interpolation without writing any code. See here for an explanation of fixed timestep interpolation:
https://www.gamedev.net/blogs/entry/2265460-fixing-your-timestep-and-evaluating-godot/
https://www.youtube.com/watch?v=lWhHBAcH4sM
This repository contains the addon (in the addons folder) and an example demo project.
To use the addon in your own project:
- Create a new project in Godot or use an existing project.
- Copy the 'addons' folder from this repository to your Godot project folder.
- Go to 'Project Settings' plugins tab.
- Find the smoothing plugin and set status to 'Active'.
In a game you would usually choose to create a Node2D, Spatial, RigidBody, Kinematic body etc node for a game object, which is affected by physics and / or AI and / or player input. This I will refer to as the PHYSICS REP (representation).
The visual respresentation of this object (VISUAL REP) is often simply a child of this node, such as a MeshInstance, or Sprite. That way it inherits the transform of the parent physics rep. When you move the physics rep, the transform propagates to the child node, the visual rep, and it renders in the same place as the physics rep. In some games the visual rep can even be the same node as the physics rep (particularly when there is no actual physics).
Usually transforms propagate from a parent to child. Fixed timestep interpolation works slightly differently - the VisualRep indirectly follows the transform of the PhysicsRep, rather than being directly affected by it.
In your gameplay programming, 99% of the time you would usually be mostly concerned with the position and rotation of the physics rep. Aside a few things like visual effects, the visual rep will follow the physics rep, and you don't need to worry about it. This also means that providing you drive your gameplay using _physics_process
rather than _process
, your gameplay will run the same no matter what machine you run it on! Fantastic.
The smoothing nodes automatically call set_as_toplevel()
on _ready()
. This ensures that they only follow the selected target, rather than having their transform controlled directly by their parent. The default target to follow will however be the parent node, if a Target
has not been assigned in the inspector.
- You would usually in a game choose to create a Spatial, RigidBody, Kinematic body etc node for your physics rep, and have a visual representation (e.g. a MeshInstance) as a child of this node.
- Do this as normal so that you can see the object moving in the game.
- Add the new 'Smoothing' node to the scene, as a child of your physics rep.
- Drag the visual representation from being a child of the physics rep, to being a child of the Smoothing node.
- That is mainly it! Just run the game and now hopefully the visual representation will follow the gameobject, but now with interpolation. You can test this is working by running at a low physics tick rate (physics_fps in project settings->physics).
The procedure for 2D is pretty much the same as with 3D except you would be using a node derived from Node2D as the physics rep (target) and the 'Smoothing2D' node should be used instead of 'Smoothing'.
Additionally the smoothing node has the ability to follow targets that are not parent nodes. You can do this by assigning a Target
in the inspector panel for the Smoothing node.
There is one special case when using smoothing nodes - the case when you want a target to instantaneously move from one location to another (for instance respawning a player, or at level start) where you do not want interpolation from the previous position. In this special case, you should move the target node (by setting the translation or position), and then call the 'teleport' function in the Smoothing node. This ensures that interpolation will be switched off temporarily for the move.
Make sure to call teleport
AFTER moving the target node, rather than before.
As well as choosing the Target, in the inspector for the Smoothing nodes there are a set of flags.
- enabled - chooses whether the smoothing node is active
- translate - interpolation will be done for the position
- basis - interpolation will be done for rotation and scale
- slerp - this will do quaternion slerping instead of the simpler basis lerping. Note that this only works with no scaling applied to the target.
- enabled - as above
- translate - as above
- rotate - interpolation of the node angle
- scale - interpolation of the node scale (x and y)
- global in - will read the global transform of the target instead of local
- global out - will set the global transform of the smoothing node instead of local
(in most cases local transform will be the best choice)
- Processing will also be turned off automatically for the smoothing nodes if they are hidden (either directly or through a parent).
- You can also set the target for the smoothing node from script, using the
set_target
function and passing a NodePath argument (e.g.mynode.get_path()
). - The best way to debug / develop smoothing is to set physics ticks per second (
ProjectSettings->Physics->Common->Physics_FPS
) to a low value (e.g. 10). Once you have it working you can set it back up to high value if desired. - If you encounter problems smoothing a
Camera2D
node, try setting theProcessMode
toIdle
instead ofPhysics
. - In order to prevent an unneeded extra delay of one tick, it is important that smoothing nodes are processed AFTER target nodes. This should now be automatically taken care as the addon internally uses
process_priority
to achieve this. Previously we required smoothing nodes to be placed lower in the scene tree than the target. This should hopefully no longer be the case.
There is no need for JitterFix (Project Settings->Physics->Common->Physics Jitter Fix
) when using fixed timestep interpolation, indeed it may interfere with getting a good result. The addon now enforces this by setting Engine.set_physics_jitter_fix
to 0 as smoothing nodes are created.
Lawnjelly, Calinou
This addon is also available as a c++ module (slight differences), see: https://github.com/lawnjelly/godot-smooth