Tween

继承: RefCounted < Object

通过脚本进行通用动画的轻量级对象,使用 Tweener

描述

Tween 主要用于需要将一个数值属性插值到一系列值的动画。tween 这个名字来自 in-betweening,这是一种动画技术,可以在其中指定 关键帧,然后计算机会插入出现在它们之间的帧。使用 Tween 制作动画被称为补间动画。

TweenAnimationPlayer 更适合事先不知道最终值的动画。例如,插入动态选择的相机缩放值最好使用 Tween 完成;很难使用 AnimationPlayer 节点做同样的事情。Tween 也比 AnimationPlayer 更轻量级,因此它们非常适合简单的动画,或不需要编辑器提供的视觉调整的通用任务。对于通常由代码完成的某些逻辑,它们可以以“即用即弃”的方式使用。例如,可以使用带延迟的循环 CallbackTweener 定期射击。

可以使用 SceneTree.create_tweenNode.create_tween 创建 Tween。手动创建的 Tween(即使用 Tween.new())无效,不能用于对值进行补间。

通过使用 tween_propertytween_intervaltween_callbacktween_method,可将 Tweener 添加到 Tween 对象来创建一个补间动画:

GDScriptC#

  1. var tween = get_tree().create_tween()
  2. tween.tween_property($Sprite, "modulate", Color.RED, 1)
  3. tween.tween_property($Sprite, "scale", Vector2(), 1)
  4. tween.tween_callback($Sprite.queue_free)
  1. Tween tween = GetTree().CreateTween();
  2. tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f);
  3. tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f);
  4. tween.TweenCallback(Callable.From(GetNode("Sprite").QueueFree));

该序列将使 $Sprite 节点变红,然后缩小,最后调用 Node.queue_free 来释放该精灵。默认情况下,Tweener 一个接一个地执行。这种行为可以使用 parallelset_parallel 来更改。

当使用 tween_* 方法之一创建 Tweener 时,可以使用链式方法调用来调整该 Tweener 的属性。例如,如果想在上面的例子中设置一个不同的过渡类型,可以使用 set_trans

GDScriptC#

  1. var tween = get_tree().create_tween()
  2. tween.tween_property($Sprite, "modulate", Color.RED, 1).set_trans(Tween.TRANS_SINE)
  3. tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE)
  4. tween.tween_callback($Sprite.queue_free)
  1. Tween tween = GetTree().CreateTween();
  2. tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f).SetTrans(Tween.TransitionType.Sine);
  3. tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f).SetTrans(Tween.TransitionType.Bounce);
  4. tween.TweenCallback(Callable.From(GetNode("Sprite").QueueFree));

大多数 Tween 方法也可以这样链式调用。在下面的示例中,Tween 被绑定到运行脚本的节点,并为其 Tweener 设置了默认过渡:

GDScriptC#

  1. var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC)
  2. tween.tween_property($Sprite, "modulate", Color.RED, 1)
  3. tween.tween_property($Sprite, "scale", Vector2(), 1)
  4. tween.tween_callback($Sprite.queue_free)
  1. var tween = GetTree().CreateTween().BindNode(this).SetTrans(Tween.TransitionType.Elastic);
  2. tween.TweenProperty(GetNode("Sprite"), "modulate", Colors.Red, 1.0f);
  3. tween.TweenProperty(GetNode("Sprite"), "scale", Vector2.Zero, 1.0f);
  4. tween.TweenCallback(Callable.From(GetNode("Sprite").QueueFree));

Tween 的另一个有趣用途是动画化任意对象集:

GDScriptC#

  1. var tween = create_tween()
  2. for sprite in get_children():
  3. tween.tween_property(sprite, "position", Vector2(0, 0), 1)
  1. Tween tween = CreateTween();
  2. foreach (Node sprite in GetChildren())
  3. tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f);

在上面的示例中,一个节点的所有子节点都被依次移动到位置 (0, 0)。

应该避免为对象的同一属性使用多个 Tween。如果两个或多个补间同时为同一个属性设置动画,则最后创建的补间将优先使用,并分配最终值。如果要中断并重新启动动画,请考虑将 Tween 赋给变量:

GDScriptC#

  1. var tween
  2. func animate():
  3. if tween:
  4. tween.kill() # 终止之前的补间动画。
  5. tween = create_tween()
  1. private Tween _tween;
  2. public void Animate()
  3. {
  4. if (_tween != null)
  5. _tween.Kill(); // 终止之前的补间动画。
  6. _tween = CreateTween();
  7. }

一些 Tweener 会使用过渡和缓动。第一个接受一个 TransitionType 常量,指的是处理动画时间的方式(相关示例见 easings.net)。第二个接受一个 EaseType 常量,并控制 trans_type 应用于插值的位置(在开头、结尾或两者均有)。如果不知道该选择哪种过渡和缓动,可以尝试使用 EASE_IN_OUT 并配合不同 TransitionType 常量,并使用看起来最好的那个。

补间缓动与过渡类型速查表

注意:Tween 并不是针对重用设计的,尝试重用会造成未定义行为。每次从头开始重新播放每个动画都请新建一个 Tween。请记住,Tween 是会立即开始的,所以请只在需要开始动画时创建 Tween。

注意:该补间在当前帧中的所有节点之后进行处理,即节点的 Node._process 方法(或 Node._physics_process,具体取决于传递给 set_process_mode 的值)会在补间之前被调用。

方法

Tween

bind_node(node: Node)

Tween

chain()

bool

custom_step(delta: float)

int

get_loops_left() const

float

get_total_elapsed_time() const

Variant

interpolate_value(initial_value: Variant, delta_value: Variant, elapsed_time: float, duration: float, trans_type: TransitionType, ease_type: EaseType) static

bool

is_running()

bool

is_valid()

void

kill()

Tween

parallel()

void

pause()

void

play()

Tween

set_ease(ease: EaseType)

Tween

set_loops(loops: int = 0)

Tween

set_parallel(parallel: bool = true)

Tween

set_pause_mode(mode: TweenPauseMode)

Tween

set_process_mode(mode: TweenProcessMode)

Tween

set_speed_scale(speed: float)

Tween

set_trans(trans: TransitionType)

void

stop()

CallbackTweener

tween_callback(callback: Callable)

IntervalTweener

tween_interval(time: float)

MethodTweener

tween_method(method: Callable, from: Variant, to: Variant, duration: float)

PropertyTweener

tween_property(object: Object, property: NodePath, final_val: Variant, duration: float)


信号

finished() 🔗

Tween 完成所有补间时发出。该 Tween 设为无限循环时不会发出(见 set_loops)。


loop_finished(loop_count: int) 🔗

完成一次循环时触发(见 set_loops),会提供该循环的索引号。这个信号不会在最后一次循环后触发,这种情况请使用 finished 代替。


step_finished(idx: int) 🔗

完成该 Tween 的一步完成后触发,会提供这一步的索引号。一步指的是单个 Tweener 或一组并行执行的 Tweener


枚举

enum TweenProcessMode: 🔗

TweenProcessMode TWEEN_PROCESS_PHYSICS = 0

Tween 在每个物理帧之后进行更新(见 Node._physics_process)。

TweenProcessMode TWEEN_PROCESS_IDLE = 1

Tween 在每个处理帧之后进行更新(见 Node._process)。


enum TweenPauseMode: 🔗

TweenPauseMode TWEEN_PAUSE_BOUND = 0

如果该 Tween 绑定了节点,它将在该节点可以处理时进行处理(见 Node.process_mode)。否则与 TWEEN_PAUSE_STOP 相同。

TweenPauseMode TWEEN_PAUSE_STOP = 1

如果 SceneTree 被暂停,则该 Tween 也会暂停。

TweenPauseMode TWEEN_PAUSE_PROCESS = 2

无论 SceneTree 是否被暂停,该 Tween 都会处理。


enum TransitionType: 🔗

TransitionType TRANS_LINEAR = 0

动画是线性插值的。

TransitionType TRANS_SINE = 1

动画使用正弦函数进行插值。

TransitionType TRANS_QUINT = 2

动画使用五次(5 次方)函数进行插值。

TransitionType TRANS_QUART = 3

动画使用四次(4 次方)函数进行插值。

TransitionType TRANS_QUAD = 4

动画使用二次(2 次方)函数进行插值。

TransitionType TRANS_EXPO = 5

动画使用指数(x 次方)函数进行插值。

TransitionType TRANS_ELASTIC = 6

动画弹性插值,在边缘摆动。

TransitionType TRANS_CUBIC = 7

动画使用三次(3 次方)函数进行插值。

TransitionType TRANS_CIRC = 8

动画使用平方根的函数进行插值。

TransitionType TRANS_BOUNCE = 9

动画通过在末尾弹跳插值。

TransitionType TRANS_BACK = 10

动画在末端回放插值。

TransitionType TRANS_SPRING = 11

动画像朝着末尾的弹簧一样插值。


enum EaseType: 🔗

EaseType EASE_IN = 0

插值开始缓慢,并加速接近结束。

EaseType EASE_OUT = 1

插值开始快速,接近结束时减慢。

EaseType EASE_IN_OUT = 2

EASE_INEASE_OUT 的组合。两端的插值最慢。

EaseType EASE_OUT_IN = 3

EASE_INEASE_OUT 的组合。两端的插值最快。


方法说明

Tween bind_node(node: Node) 🔗

将这个 Tween 绑定到给定的 node 上。Tween 是由 SceneTree 直接处理的,所以不依赖被动画的节点运行。将该 Tween 绑定到某个 Node 后,该对象不在树中时该 Tween 就会暂停动画,绑定对象被释放时该 Tween 会被自动销毁。另外,TWEEN_PAUSE_BOUND 会让暂停行为依赖于绑定的节点。

使用 Node.create_tween 来创建并绑定 Tween 更简单。


Tween chain() 🔗

用于在使用 true 调用 set_parallel 后,将两个 Tweener 串联。

GDScriptC#

  1. var tween = create_tween().set_parallel(true)
  2. tween.tween_property(...)
  3. tween.tween_property(...) # 会和上一条并行执行。
  4. tween.chain().tween_property(...) # 会在前两条完成后执行。
  1. Tween tween = CreateTween().SetParallel(true);
  2. tween.TweenProperty(...);
  3. tween.TweenProperty(...); // 会和上一条并行执行。
  4. tween.Chain().TweenProperty(...); // 会在前两条完成后执行。

bool custom_step(delta: float) 🔗

使用给定的增量秒数 delta 处理该 Tween。最常见的用法是在该 Tween 暂停时对其进行手动控制。也可用于立即停止该 Tween 的动画,将 delta 设得比完整长度更大即可。

如果该 Tween 仍然有未完成的 Tweener,则返回 true


int get_loops_left() const 🔗

返回该 Tween 所剩的循环数(见 set_loops)。返回 -1 表示 Tween 无限循环,返回 0 表示 Tween 已结束。


float get_total_elapsed_time() const 🔗

返回该 Tween 已进行动画的总时长(即自开始以来经过的时间,不计算暂停等时间),单位为秒。时长会受到 set_speed_scale 影响,stop 会将其重置为 0

注意:由于时长是由帧的增量时间累计而来的,该 Tween 完成动画后所返回的时长会比 Tween 的实际时长略大。


Variant interpolate_value(initial_value: Variant, delta_value: Variant, elapsed_time: float, duration: float, trans_type: TransitionType, ease_type: EaseType) static 🔗

不想使用 Tween 进行动画时,可以使用这个方法进行手动插值。与 @GlobalScope.lerp 类似,但支持自定义过渡和缓动。

initial_value 为插值的起始值。

delta_value 为插值的变化值,即等于 final_value - initial_value

elapsed_time 为插值开始后所经过的秒数,用于控制插值的位置。例如,等于 duration 的一半时,插值后的值位于初始值和最终值的一半。这个值也可以比 duration 大或者比 0 小,此时会进行外插。

duration 为插值的总时长。

注意:如果 duration 等于 0,那么无论提供的 elapsed_time 为多少,该方法返回的始终是最终值。


bool is_running() 🔗

返回该 Tween 目前是否正在执行,即未暂停且未完成。


bool is_valid() 🔗

返回该 Tween 是否有效。有效的 Tween 是由场景树包含的 Tween(即 SceneTree.get_processed_tweens 返回的数组中包含这个 Tween)。Tween 失效的情况有:补间完成、被销毁、使用 Tween.new() 创建。无效的 Tween 不能追加 Tweener


void kill() 🔗

中止所有补间操作,并使该 Tween 无效。


Tween parallel() 🔗

让下一个 Tweener 与上一个并行执行。

示例:

GDScriptC#

  1. var tween = create_tween()
  2. tween.tween_property(...)
  3. tween.parallel().tween_property(...)
  4. tween.parallel().tween_property(...)
  1. Tween tween = CreateTween();
  2. tween.TweenProperty(...);
  3. tween.Parallel().TweenProperty(...);
  4. tween.Parallel().TweenProperty(...);

该示例中的所有 Tweener 都会同时执行。

你可以通过使用 set_parallel 让该 Tween 默认并行。


void pause() 🔗

暂停该补间。可以使用 play 恢复动画。

注意:如果一个 Tween 被暂停并且没有被绑定到任何节点,它将无限期地存在,直到手动启动或失效。如果丢失了对这种 Tween 的引用,可以使用 SceneTree.get_processed_tweens 检索它。


void play() 🔗

恢复已暂停或已停止的 Tween


Tween set_ease(ease: EaseType) 🔗

设置 PropertyTweener 的默认缓动类型,MethodTweener 由该 Tween 设置动画。

如果未指定,默认值为 EASE_IN_OUT


Tween set_loops(loops: int = 0) 🔗

这只该补间序列的重复次数,即 set_loops(2) 会让动画执行两次。

调用这个方法时如果不带参数,那么该 Tween 会无限执行,直到被 kill 销毁、该 Tween 绑定的节点被释放或者所有进行动画的对象都被释放(无法再进行任何动画)。

警告:使用无限循环时请一定要加入一些时长/延迟。为了防止游戏冻结,0 时长的循环动画(例如单个不带延迟的 CallbackTweener)会在循环若干次后停止,造成出乎预料的结果。如果 Tween 的生命期依赖于某个节点,请一定使用 bind_node


Tween set_parallel(parallel: bool = true) 🔗

如果 paralleltrue,则后续追加的 Tweener 默认就是同时运行的,否则默认依次运行。

注意:parallel 类似,在这个方法前添加的那一个补间器也是并行步骤的一部分。

  1. tween.tween_property(self, "position", Vector2(300, 0), 0.5)
  2. tween.set_parallel()
  3. tween.tween_property(self, "modulate", Color.GREEN, 0.5) # 与位置补间器一同运行。

Tween set_pause_mode(mode: TweenPauseMode) 🔗

决定该 TweenSceneTree 暂停时的行为。可选项请查看 TweenPauseMode

默认值为 TWEEN_PAUSE_BOUND


Tween set_process_mode(mode: TweenProcessMode) 🔗

决定该 Tween 应当在处理帧(见 Node._process)还是物理帧(见 Node._physics_process)执行。

默认值为 TWEEN_PROCESS_IDLE


Tween set_speed_scale(speed: float) 🔗

补间的速度缩放。影响所有 Tweener 及其延迟。


Tween set_trans(trans: TransitionType) 🔗

为此 Tween 设置动画化的 PropertyTweenerMethodTweener 的默认过渡类型。

如果未指定,则默认值为 TRANS_LINEAR


void stop() 🔗

停止该补间并将该 Tween 重置为其初始状态。这不会移除任何附加的 Tweener

注意:如果一个 Tween 被停止并且没有被绑定到任何节点,它将无限期地存在,直到手动启动或失效。如果丢失了对这种 Tween 的引用,可以使用 SceneTree.get_processed_tweens


CallbackTweener tween_callback(callback: Callable) 🔗

创建并追加一个 CallbackTweener。这个方法可用于调用任意对象的任意方法。请使用 Callable.bind 绑定额外的调用参数。

示例:总是每隔 1 秒射击一次的对象:

GDScriptC#

  1. var tween = get_tree().create_tween().set_loops()
  2. tween.tween_callback(shoot).set_delay(1)
  1. Tween tween = GetTree().CreateTween().SetLoops();
  2. tween.TweenCallback(Callable.From(Shoot)).SetDelay(1.0f);

示例:将精灵变红然后变蓝,带有 2 秒延迟:

GDScriptC#

  1. var tween = get_tree().create_tween()
  2. tween.tween_callback($Sprite.set_modulate.bind(Color.RED)).set_delay(2)
  3. tween.tween_callback($Sprite.set_modulate.bind(Color.BLUE)).set_delay(2)
  1. Tween tween = GetTree().CreateTween();
  2. Sprite2D sprite = GetNode<Sprite2D>("Sprite");
  3. tween.TweenCallback(Callable.From(() => sprite.Modulate = Colors.Red)).SetDelay(2.0f);
  4. tween.TweenCallback(Callable.From(() => sprite.Modulate = Colors.Blue)).SetDelay(2.0f);

IntervalTweener tween_interval(time: float) 🔗

创建并追加一个 IntervalTweener。这个方法可用于在补间动画中创建延迟,可以替代在其他 Tweener 中使用延迟,或无动画的情况(此时 Tween 充当计时器的角色)。time 为间隔时间,单位为秒。

示例:创建代码执行的间隔:

GDScriptC#

  1. # ... 一些代码
  2. yield(create_tween().tween_interval(2), "finished")
  3. # ... 更多代码
  1. // ... 一些代码
  2. await ToSignal(CreateTween().TweenInterval(2.0f), Tween.SignalName.Finished);
  3. // ... 更多代码

示例:创建每隔几秒就来回移动并跳跃的对象:

GDScriptC#

  1. var tween = create_tween().set_loops()
  2. tween.tween_property($Sprite, "position:x", 200.0, 1).as_relative()
  3. tween.tween_callback(jump)
  4. tween.tween_interval(2)
  5. tween.tween_property($Sprite, "position:x", -200.0, 1).as_relative()
  6. tween.tween_callback(jump)
  7. tween.tween_interval(2)
  1. Tween tween = CreateTween().SetLoops();
  2. tween.TweenProperty(GetNode("Sprite"), "position:x", 200.0f, 1.0f).AsRelative();
  3. tween.TweenCallback(Callable.From(Jump));
  4. tween.TweenInterval(2.0f);
  5. tween.TweenProperty(GetNode("Sprite"), "position:x", -200.0f, 1.0f).AsRelative();
  6. tween.TweenCallback(Callable.From(Jump));
  7. tween.TweenInterval(2.0f);

MethodTweener tween_method(method: Callable, from: Variant, to: Variant, duration: float) 🔗

创建并追加一个 MethodTweener。这个方法与 tween_callbacktween_property 的组合类似,会使用补间后的值作为参数去持续调用某个方法。该值是从 fromto 进行补间的,时长为 duration 秒。请使用 Callable.bind 绑定额外的调用参数。你可以使用 MethodTweener.set_easeMethodTweener.set_trans 来调整该值的缓动和过渡,可以使用 MethodTweener.set_delay 来延迟补间。

示例:让 3D 对象面向另一个点:

GDScriptC#

  1. var tween = create_tween()
  2. tween.tween_method(look_at.bind(Vector3.UP), Vector3(-1, 0, -1), Vector3(1, 0, -1), 1) # look_at() 方法的第二个参数接受的是上向量。
  1. Tween tween = CreateTween();
  2. tween.TweenMethod(Callable.From((Vector3 target) => LookAt(target, Vector3.Up)), new Vector3(-1.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, -1.0f), 1.0f); // 使用 lambda 为调用绑定附加参数。

示例:在一段延迟后,使用中间方法来设置 Label 的文本:

GDScriptC#

  1. func _ready():
  2. var tween = create_tween()
  3. tween.tween_method(set_label_text, 0, 10, 1).set_delay(1)
  4. func set_label_text(value: int):
  5. $Label.text = "Counting " + str(value)
  1. public override void _Ready()
  2. {
  3. base._Ready();
  4. Tween tween = CreateTween();
  5. tween.TweenMethod(Callable.From<int>(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f);
  6. }
  7. private void SetLabelText(int value)
  8. {
  9. GetNode<Label>("Label").Text = $"Counting {value}";
  10. }

PropertyTweener tween_property(object: Object, property: NodePath, final_val: Variant, duration: float) 🔗

创建并追加一个 PropertyTweener。这个方法会将 object 对象的 property 属性在初始值和最终值 final_val 之间进行补间,持续时间为 duration 秒。初始值默认为该 PropertyTweener 启动时该属性的值。

示例:

GDScriptC#

  1. var tween = create_tween()
  2. tween.tween_property($Sprite, "position", Vector2(100, 200), 1)
  3. tween.tween_property($Sprite, "position", Vector2(200, 300), 1)
  1. Tween tween = CreateTween();
  2. tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(100.0f, 200.0f), 1.0f);
  3. tween.TweenProperty(GetNode("Sprite"), "position", new Vector2(200.0f, 300.0f), 1.0f);

会将该精灵移动到 (100, 200) 然后再移动到 (200, 300)。如果你使用了 PropertyTweener.fromPropertyTweener.from_current,那么起始位置就会被给定的值所覆盖。更多调整项请参阅 PropertyTweener 中的其他方法。

注意:鼠标悬停在检查器中的属性上即可查看正确的属性名称。你还可以用 "属性:组件" 的形式提供属性中的组件(例如 position:x),这样就只会修改这个特定的组件。

示例:使用不同的过渡类型从同一位置开始移动两次:

GDScriptC#

  1. var tween = create_tween()
  2. tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().set_trans(Tween.TRANS_SINE)
  3. tween.tween_property($Sprite, "position", Vector2.RIGHT * 300, 1).as_relative().from_current().set_trans(Tween.TRANS_EXPO)
  1. Tween tween = CreateTween();
  2. tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().SetTrans(Tween.TransitionType.Sine);
  3. tween.TweenProperty(GetNode("Sprite"), "position", Vector2.Right * 300.0f, 1.0f).AsRelative().FromCurrent().SetTrans(Tween.TransitionType.Expo);