diff --git a/tutorials/math/interpolation.rst b/tutorials/math/interpolation.rst index bddc26481ce8..f3deb759de5d 100644 --- a/tutorials/math/interpolation.rst +++ b/tutorials/math/interpolation.rst @@ -109,7 +109,11 @@ And again, it will produce the following motion: Smoothing motion ---------------- -Interpolation can be used to smooth movement, rotation, etc. Here is an example of a circle following the mouse using smoothed motion: +Interpolation can be used to smoothly follow a moving target value, such as a +position or a rotation. Each frame, ``lerp()`` moves the current value towards +the target value by a fixed percentage of the remaining difference between the values. +The current value will smoothly move towards the target, slowing down as it gets +closer. Here is an example of a circle following the mouse using interpolation smoothing: .. tabs:: .. code-tab:: gdscript GDScript @@ -138,4 +142,48 @@ Here is how it looks: .. image:: img/interpolation_follow.gif -This is useful for smoothing camera movement, allies following you (ensuring they stay within a certain range), and many other common game patterns. +This is useful for smoothing camera movement, for allies following the player +(ensuring they stay within a certain range), and for many other common game patterns. + +.. note:: + Despite using ``delta``, the formula used above is framerate-dependent, because + the ``weight`` parameter of ``lerp()`` represents a *percentage* of the remaining + difference in values, not an *absolute amount to change*. In ``_physics_process()``, + this is usually fine because physics is expected to maintain a constant framerate, + and therefore ``delta`` is expected to remain constant. For example, with an FPS + of ``60`` and a ``FOLLOW_SPEED`` of ``4.0``, ``delta`` will be ``1/60`` or ``0.0166``, + and ``FOLLOW_SPEED * delta`` will be a constant value of ``0.0666``. + + For a framerate-independent version of interpolation smoothing that can be used + in ``process()``, use the following formula instead: + + .. tabs:: + .. code-tab:: gdscript GDScript + + const FOLLOW_SPEED = 4.0 + + func _process(delta): + var mouse_pos = get_local_mouse_position() + var weight = 1 - exp(-FOLLOW_SPEED * delta) + $Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, weight) + + .. code-tab:: csharp + + private const float FollowSpeed = 4.0f; + + public override void _Process(double delta) + { + Vector2 mousePos = GetLocalMousePosition(); + + Sprite2D sprite = GetNode("Sprite2D"); + float weight = 1f - Mathf.Exp(-FollowSpeed * (float)delta); + sprite.Position = sprite.Position.Lerp(mousePos, weight); + } + + Deriving this formula is beyond the scope of this page. For an explanation, + read `Improved Lerp Smoothing `__ + or watch `Lerp smoothing is broken `__. + + + +