如何在 GODOT 中使用线性插值

问题描述

我正在尝试使用线性插值来平滑相机移动,但看起来我无法通过它传递 Delta.. 不确定这是否是问题所在。相反,它只是捕捉它的位置

CameraBase只是一个空间3D,实际的camera 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)

如果使用 Input 而不是 unhandle,它会工作得很好,但我读到这不是正确的方法

解决方法

让我们看看 linear_interpolate 的文档:

Vector3 linear_interpolate ( Vector3 to,float weight )

返回此向量与 to 之间的线性插值结果,数量为 t。权重在 0.0 到 1.0 的范围内,表示插值量。

如您所见,第二个参数是权重。如果它是 0.0,你会得到一个没有修改的向量。如果它是 1.0,您将获得作为第一个参数传递的向量。任何介于 0.0 和 1.0 之间的值都会在两者之间给出一个点。

我们可以在 "Vector Interpolation" 中确认这一点:

这是使用插值从 A 点到 B 点的简单伪代码:

func _physics_process(delta):
   t += delta * 0.4

   $Sprite.position = $A.position.linear_interpolate($B.position,t)

它将产生以下运动:

Circle moving from pint A to point B,as t goes from 0 to 1

重申一下,weight 为 0.0 为您提供第一个位置,weight 1.0 为您提供第二个位置。对于运动,您应该传递一个随时间变化从 0.0 到 1.0 的值。

这就是示例使用 _physics_processdelta(顺便说一下,以秒为单位)的原因。每个物理帧,Godot 都会调用 _physics_process,其中代码使用自上次 Godot 调用 {{ 1}}(即 weight)。

如果您想使用 t 来创建动作,您必须使用类似的方式。从 _physics_processdelta 或从处理程序调用 linear_interpolate 或类似解决方案的 _process 信号。


但是,我将建议一种完全不同的方法:使用 Tween 节点。

您可以添加一个 _physics_process 节点并将其用于插值。您可以在编辑器中添加节点,并像这样引用:

timeout

或者你可以用这样的代码创建它:

Timer

不管怎样,一旦你有一个带有 Tween 的变量,我们就可以像这样使用它:

Tween

这可以在 onready var tween:Tween = $Tween var tween:Tween func _ready(): tween = Tween.new() add_child(tween) 或任何地方,这无关紧要。它也不需要 tween.interpolate_property($CameraBase,"translation",$CameraBase.translation,target.translation,duration) 。而且您不需要多次调用它(这是您使用 _input 获得运动所必须执行的操作,以防不清楚)。

代码告诉 _unhandled_input 节点插入 deltalinear_interpolate 属性。这些值将从 Tween 的当前值变为 translation。并且该动作需要 $CameraBase 秒。

我们可以调整它以使用速度:

$CameraBase.translation

这里假设 target.translation 是每秒单位数。

而且,作为奖励,interpolate_property 和其他插值 duration 方法允许您指定插值类型(默认情况下是线性的),通过传递一个 TransitionType 和一个EaseType

顺便说一下,您可以检查 is_active 以了解 var distance = $CameraBase.translation.distance_to(target.translation) var duration = distance / CAMERA_SPEED tween.interpolate_property($CameraBase,duration) 是否正在运行,还有 stopstop_all 方法。