I'm trying to make a smooth camera movement using linear interpolation, but looks like I cannot pass Delta with it.. not sure if that is the problem. Instead it just snaps its position
CameraBase is only a spatial 3D, and the actual camera Node is his child node
func _unhandled_input(event):
if event.is_action_released("ui_focus_next"):
i += 1
if i >= allies.size():
i = 0
pointer.translation = allies[i].translation + Vector3(0,5,0)
focus_camera(allies[i])
func focus_camera(target):
var move = $CameraBase.translation.linear_interpolate(target.translation, CAMERA_SPEED)
$CameraBase.set_translation(move)
It would work fine if was using Input instead of unhandle, but I read that is not the proper way to do it
Let us have a look at the documentation for linear_interpolate
:
Vector3 linear_interpolate ( Vector3 to, float weight )
Returns the result of the linear interpolation between this vector and to by amount t. weight is on the range of 0.0 to 1.0, representing the amount of interpolation.
As you can see the second parameter is a weight. If it is 0.0, you get a vector without modification. If it is 1.0, you get the vector you pass as first parameter. Any value between 0.0 and 1.0 will give a point in between.
We can confirm this in in "Vector Interpolation":
Here is simple pseudo-code for going from point A to B using interpolation:
func _physics_process(delta): t += delta * 0.4 $Sprite.position = $A.position.linear_interpolate($B.position, t)
It will produce the following motion:
To reiterate, a weight
of 0.0 give you the first position and a weight
1.0 gives you the second position. For the motion you are meant to pass a value that varies from 0.0 to 1.0 over time.
Which is why the example uses _physics_process
and delta
(which is in in seconds, by the way). Every physics frame, Godot calls _physics_process
, where the code computes the new value for the weight
(the t
variable in this case) using the elapsed time since the last time Godot called _physics_process
(that is delta
).
If you want to use linear_interpolate
to create motion, you must use it similar fashion. Calling it from _process
, _physics_process
, or from the handler the timeout
signal of a Timer
or similar solution.
However, I'm going to suggest an entirely different approach: use a Tween
node.
You can add a Tween
node and use it for your interpolation. You can add the node in the editor, and take a reference like this:
onready var tween:Tween = $Tween
Or you can create it from code like this:
var tween:Tween
func _ready():
tween = Tween.new()
add_child(tween)
Either way, once you have a variable with the Tween, we can use it like this:
tween.interpolate_property($CameraBase, "translation",
$CameraBase.translation, target.translation, duration)
That can be in _input
or _unhandled_input
or anywhere, it does not matter. Nor does it need delta
. And you don't need to call it multiple times (which is what you have to do to get motion with linear_interpolate
, in case that wasn't clear).
The code is telling the Tween
node to interpolate the translation
property of $CameraBase
. The values will go from the current value of $CameraBase.translation
to target.translation
. And the motion will take duration
seconds.
We can tweak this to use speed:
var distance = $CameraBase.translation.distance_to(target.translation)
var duration = distance / CAMERA_SPEED
tween.interpolate_property($CameraBase, "translation",
$CameraBase.translation, target.translation, duration)
This assumes CAMERA_SPEED
is units per second.
Also let us not forget to call start
:
tween.start()
And, as as bonus, interpolate_property
and the other interpolation Tween
methods allow you to specify the kind of interpolation (it is linear by default), by passing a TransitionType
and a EaseType
.
By the way, you can check is_active
to find out if the Tween
is running, and there are also stop
and stop_all
methods.