godot-tweening

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Tweening

Tween动画

Tween property animation, easing curves, chaining, and lifecycle management define smooth programmatic motion.
Tween属性动画、缓动曲线、链式动画以及生命周期管理共同构成了流畅的程序化运动效果。

Available Scripts

可用脚本

juice_manager.gd

juice_manager.gd

Expert tween-based juice system with reusable effect presets (bounce, shake, pulse, etc.).
基于Tween的专业视觉增强系统,包含可复用的效果预设(弹跳、震动、脉冲等)。

NEVER Do in Tweening

Tween动画的禁忌

  • NEVER create tweens without killing previous — Spam click button, create 100 tweens? Memory leak + conflicting animations. ALWAYS
    if tween: tween.kill()
    before creating new.
  • NEVER tween in _process without create_tween()
    create_tween()
    every frame? 60 tweens/second × 60 frames = 3600 tween objects. Create ONCE, reuse OR kill old.
  • NEVER forget to set_parallel for simultaneous — Chain
    tween_property()
    expecting simultaneous? Sequential by default. Use
    tween.set_parallel(true)
    first.
  • NEVER use 0-duration tweens for instant changes
    tween_property(x, 0.0)
    for teleport? Overhead of tween system. Just set property:
    sprite.position = target
    .
  • NEVER skip finished signal for cleanup — Tween completes, node still references it? Memory held. Connect
    tween.finished
    for cleanup OR null reference.
  • NEVER use linear interpolation for UI
    TRANS_LINEAR
    for button hover? Robotic feel. Use
    EASE_OUT + TRANS_QUAD
    OR
    EASE_IN_OUT + TRANS_CUBIC
    for organic motion.

gdscript
extends Sprite2D

func _ready() -> void:
    # Create tween
    var tween := create_tween()
    
    # Animate position over 2 seconds
    tween.tween_property(self, "position", Vector2(100, 100), 2.0)
  • 绝对不要在未销毁旧补间的情况下创建新补间 — 反复点击按钮会创建100个补间?这会导致内存泄漏和动画冲突。创建新补间前务必执行
    if tween: tween.kill()
  • 绝对不要在_process中不使用create_tween()就执行补间操作 — 每帧调用
    create_tween()
    ?每秒60个补间×60帧=3600个补间对象。应该创建一次后复用,或者销毁旧补间。
  • 绝对不要忘记设置并行以实现同步动画 — 链式调用
    tween_property()
    却期望同步执行?默认是顺序执行。请先使用
    tween.set_parallel(true)
  • 绝对不要用0时长补间实现即时变更 — 用
    tween_property(x, 0.0)
    实现瞬移?这会带来补间系统的额外开销。直接设置属性即可:
    sprite.position = target
  • 绝对不要忘记通过完成信号进行清理 — 补间完成后,节点仍引用它?这会占用内存。请连接
    tween.finished
    信号进行清理,或者将引用置空。
  • 绝对不要在UI中使用线性插值 — 按钮悬停效果用
    TRANS_LINEAR
    ?会显得机械生硬。请使用
    EASE_OUT + TRANS_QUAD
    EASE_IN_OUT + TRANS_CUBIC
    实现自然的运动效果。

gdscript
extends Sprite2D

func _ready() -> void:
    # Create tween
    var tween := create_tween()
    
    # Animate position over 2 seconds
    tween.tween_property(self, "position", Vector2(100, 100), 2.0)

Tween Methods

Tween方法

Property Animation

属性动画

gdscript
undefined
gdscript
undefined

Tween single property

Tween single property

var tween := create_tween() tween.tween_property($Sprite, "modulate:a", 0.0, 1.0) # Fade out
var tween := create_tween() tween.tween_property($Sprite, "modulate:a", 0.0, 1.0) # Fade out

Chain multiple tweens

Chain multiple tweens

tween.tween_property($Sprite, "position:x", 200, 1.0) tween.tween_property($Sprite, "position:y", 100, 0.5)
undefined
tween.tween_property($Sprite, "position:x", 200, 1.0) tween.tween_property($Sprite, "position:y", 100, 0.5)
undefined

Callbacks

回调函数

gdscript
var tween := create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)
tween.tween_callback(func(): print("Animation done!"))
tween.tween_callback(queue_free)  # Delete after animation
gdscript
var tween := create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)
tween.tween_callback(func(): print("Animation done!"))
tween.tween_callback(queue_free)  # Delete after animation

Intervals

时间间隔

gdscript
var tween := create_tween()
tween.tween_property($Label, "modulate:a", 0.0, 0.5)
tween.tween_interval(1.0)  # Wait 1 second
tween.tween_property($Label, "modulate:a", 1.0, 0.5)
gdscript
var tween := create_tween()
tween.tween_property($Label, "modulate:a", 0.0, 0.5)
tween.tween_interval(1.0)  # Wait 1 second
tween.tween_property($Label, "modulate:a", 1.0, 0.5)

Easing Functions

缓动函数

gdscript
var tween := create_tween()
tween.set_ease(Tween.EASE_IN_OUT)  # Smooth start and end
tween.set_trans(Tween.TRANS_CUBIC)  # Cubic curve
tween.tween_property($Sprite, "position:x", 200, 1.0)
Common Combinations:
  • EASE_IN + TRANS_QUAD
    : Accelerating
  • EASE_OUT + TRANS_QUAD
    : Decelerating
  • EASE_IN_OUT + TRANS_CUBIC
    : Smooth S-curve
  • EASE_OUT + TRANS_BOUNCE
    : Bouncy effect
gdscript
var tween := create_tween()
tween.set_ease(Tween.EASE_IN_OUT)  # Smooth start and end
tween.set_trans(Tween.TRANS_CUBIC)  # Cubic curve
tween.tween_property($Sprite, "position:x", 200, 1.0)
常用组合:
  • EASE_IN + TRANS_QUAD
    : 加速运动
  • EASE_OUT + TRANS_QUAD
    : 减速运动
  • EASE_IN_OUT + TRANS_CUBIC
    : 平滑S曲线
  • EASE_OUT + TRANS_BOUNCE
    : 弹跳效果

Advanced Patterns

高级模式

Looping Animation

循环动画

gdscript
var tween := create_tween()
tween.set_loops()  # Infinite loop
tween.tween_property($Sprite, "rotation", TAU, 2.0)
gdscript
var tween := create_tween()
tween.set_loops()  # Infinite loop
tween.tween_property($Sprite, "rotation", TAU, 2.0)

Parallel Tweens

并行补间

gdscript
var tween := create_tween()
tween.set_parallel(true)
gdscript
var tween := create_tween()
tween.set_parallel(true)

Both happen simultaneously

Both happen simultaneously

tween.tween_property($Sprite, "position", Vector2(100, 100), 1.0) tween.tween_property($Sprite, "scale", Vector2(2, 2), 1.0)
undefined
tween.tween_property($Sprite, "position", Vector2(100, 100), 1.0) tween.tween_property($Sprite, "scale", Vector2(2, 2), 1.0)
undefined

UI Button Hover Effect

UI按钮悬停效果

gdscript
extends Button

func _ready() -> void:
    mouse_entered.connect(_on_mouse_entered)
    mouse_exited.connect(_on_mouse_exited)

func _on_mouse_entered() -> void:
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2(1.1, 1.1), 0.2)

func _on_mouse_exited() -> void:
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2.ONE, 0.2)
gdscript
extends Button

func _ready() -> void:
    mouse_entered.connect(_on_mouse_entered)
    mouse_exited.connect(_on_mouse_exited)

func _on_mouse_entered() -> void:
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2(1.1, 1.1), 0.2)

func _on_mouse_exited() -> void:
    var tween := create_tween()
    tween.tween_property(self, "scale", Vector2.ONE, 0.2)

Number Counter

数字计数器

gdscript
extends Label

func count_to(target: int, duration: float = 1.0) -> void:
    var current := int(text)
    var tween := create_tween()
    
    tween.tween_method(
        func(value: int): text = str(value),
        current,
        target,
        duration
    )
gdscript
extends Label

func count_to(target: int, duration: float = 1.0) -> void:
    var current := int(text)
    var tween := create_tween()
    
    tween.tween_method(
        func(value: int): text = str(value),
        current,
        target,
        duration
    )

Camera Smooth Follow

相机平滑跟随

gdscript
extends Camera2D

@export var follow_speed := 5.0
var target: Node2D

func _process(delta: float) -> void:
    if target:
        var tween := create_tween()
        tween.tween_property(
            self,
            "global_position",
            target.global_position,
            1.0 / follow_speed
        )
gdscript
extends Camera2D

@export var follow_speed := 5.0
var target: Node2D

func _process(delta: float) -> void:
    if target:
        var tween := create_tween()
        tween.tween_property(
            self,
            "global_position",
            target.global_position,
            1.0 / follow_speed
        )

Best Practices

最佳实践

1. Kill Previous Tweens

1. 销毁旧补间

gdscript
var current_tween: Tween = null

func animate_to(pos: Vector2) -> void:
    if current_tween:
        current_tween.kill()  # Stop previous animation
    
    current_tween = create_tween()
    current_tween.tween_property(self, "position", pos, 1.0)
gdscript
var current_tween: Tween = null

func animate_to(pos: Vector2) -> void:
    if current_tween:
        current_tween.kill()  # Stop previous animation
    
    current_tween = create_tween()
    current_tween.tween_property(self, "position", pos, 1.0)

2. Use Signals for Completion

2. 使用信号监听完成状态

gdscript
var tween := create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)
tween.finished.connect(_on_tween_finished)

func _on_tween_finished() -> void:
    print("Animation complete!")
gdscript
var tween := create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)
tween.finished.connect(_on_tween_finished)

func _on_tween_finished() -> void:
    print("Animation complete!")

3. Chaining for Sequences

3. 链式调用实现序列动画

gdscript
var tween := create_tween()
gdscript
var tween := create_tween()

Fade out

Fade out

tween.tween_property($Sprite, "modulate:a", 0.0, 0.5)
tween.tween_property($Sprite, "modulate:a", 0.0, 0.5)

Move while invisible

Move while invisible

tween.tween_property($Sprite, "position", Vector2(200, 0), 0.0)
tween.tween_property($Sprite, "position", Vector2(200, 0), 0.0)

Fade in at new position

Fade in at new position

tween.tween_property($Sprite, "modulate:a", 1.0, 0.5)
undefined
tween.tween_property($Sprite, "modulate:a", 1.0, 0.5)
undefined

Common Gotchas

常见问题

Issue: Tween stops when node is removed
gdscript
undefined
问题: 节点被移除时补间停止
gdscript
undefined

Solution: Bind tween to SceneTree

解决方案: 将补间绑定到SceneTree

var tween := get_tree().create_tween() tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)

**Issue**: Multiple conflicting tweens
```gdscript
var tween := get_tree().create_tween() tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)

**问题**: 多个补间冲突
```gdscript

Solution: Use single tween or kill previous

解决方案: 使用单个补间或销毁旧补间

Always store reference to kill old tween

始终保存引用以销毁旧补间

undefined
undefined

Reference

参考资料

Related

相关内容

  • Master Skill: godot-master
  • 核心技能: godot-master