如何在 GODOT 中使用线性插值 [英] How to use linear interpolation inside GODOT
问题描述
我正在尝试使用线性插值来平滑相机移动,但看起来我无法通过它传递 Delta.. 不确定这是否是问题所在.相反,它只是捕捉它的位置
CameraBase只是一个空间3D,实际的camera Node是他的子节点
func _unhandled_input(event):如果 event.is_action_released(ui_focus_next"):我 += 1如果我 >= allies.size():我 = 0pointer.translation = allies[i].translation + Vector3(0,5,0)focus_camera(盟友[i])功能焦点相机(目标):var move = $CameraBase.translation.linear_interpolate(target.translation, CAMERA_SPEED)$CameraBase.set_translation(移动)
如果使用 Input 而不是 unhandle,它会工作得很好,但我读到这不是正确的方法
让我们来看看
重申一下,0.0 的 weight
为您提供第一个位置,而 weight
1.0 为您提供第二个位置.对于运动,您应该传递一个随时间变化从 0.0 到 1.0 的值.
这就是示例使用 _physics_process
和 delta
(顺便说一下,以秒为单位)的原因.每个物理帧,Godot 都会调用 _physics_process
,其中代码使用经过的时间计算 weight
(在本例中为 t
变量)的新值自上次 Godot 调用 _physics_process
(即 delta
)以来的时间.
如果你想使用 linear_interpolate
来创建运动,你必须使用类似的方式.从 _process
、_physics_process
或从处理程序调用 Timer
或类似解决方案的 timeout
信号.
但是,我将建议一种完全不同的方法:使用 Tween
节点.
您可以添加一个 Tween
节点并将其用于插值.您可以在编辑器中添加节点,并像这样引用:
onready var tween:Tween = $Tween
或者你可以用这样的代码创建它:
var tween:Tween功能_就绪():吐温 = Tween.new()add_child(补间)
不管怎样,一旦你有一个带有 Tween 的变量,我们就可以像这样使用它:
tween.interpolate_property($CameraBase, "translation",$CameraBase.translation、target.translation、持续时间)
可以在 _input
或 _unhandled_input
或任何地方,这无关紧要.它也不需要delta
.而且您不需要多次调用它(这是使用 linear_interpolate
获得运动所必须执行的操作,以防不清楚).
代码告诉Tween
节点插入$CameraBase
的translation
属性.这些值将从 $CameraBase.translation
的当前值变为 target.translation
.并且该动作将花费 duration
秒.
我们可以调整它以使用速度:
var distance = $CameraBase.translation.distance_to(target.translation)var 持续时间 = 距离/CAMERA_SPEEDtween.interpolate_property($CameraBase, "translation",$CameraBase.translation、target.translation、持续时间)
这里假设 CAMERA_SPEED
是每秒单位数.
另外让我们不要忘记调用start
:
tween.start()
而且,作为奖励,interpolate_property
和其他插值 Tween
方法允许您通过传递 TransitionType
和 EaseType
.>
顺便说一下,您可以查看is_active
以查明 Tween
是否正在运行,还有 stop
和 stop_all
方法.
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.
这篇关于如何在 GODOT 中使用线性插值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!