如何在 GODOT 中使用线性插值 [英] How to use linear interpolation inside GODOT

查看:63
本文介绍了如何在 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_processdelta(顺便说一下,以秒为单位)的原因.每个物理帧,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 节点插入$CameraBasetranslation 属性.这些值将从 $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 方法允许您通过传递 TransitionTypeEaseType.>

顺便说一下,您可以查看is_active 以查明 Tween 是否正在运行,还有 stopstop_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆