AgentSkillsCN

godot-tweening

提供程序化动画的专家蓝图,采用Tween实现平滑的属性过渡、UI效果、相机移动与流畅的动画表现。涵盖缓动函数、并行Tween、链式调用与生命周期管理。在实现UI动画或程序化运动时使用。关键词:Tween、缓动、插值、EASE_IN_OUT、TRANS_CUBIC、tween_property、tween_callback。

SKILL.md
--- frontmatter
name: godot-tweening
description: "Expert blueprint for programmatic animation using Tween for smooth property transitions, UI effects, camera movements, and juice. Covers easing functions, parallel tweens, chaining, and lifecycle management. Use when implementing UI animations OR procedural movement. Keywords Tween, easing, interpolation, EASE_IN_OUT, TRANS_CUBIC, tween_property, tween_callback."

Tweening

Tween property animation, easing curves, chaining, and lifecycle management define smooth programmatic motion.

Available Scripts

juice_manager.gd

Expert tween-based juice system with reusable effect presets (bounce, shake, pulse, etc.).

NEVER Do in Tweening

  • 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 changestween_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 UITRANS_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)

Tween Methods

Property Animation

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

# Chain multiple tweens
tween.tween_property($Sprite, "position:x", 200, 1.0)
tween.tween_property($Sprite, "position:y", 100, 0.5)

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

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)

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

Advanced Patterns

Looping Animation

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)

# Both happen simultaneously
tween.tween_property($Sprite, "position", Vector2(100, 100), 1.0)
tween.tween_property($Sprite, "scale", Vector2(2, 2), 1.0)

UI Button Hover Effect

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
    )

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
        )

Best Practices

1. Kill Previous Tweens

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

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

gdscript
var tween := create_tween()

# Fade out
tween.tween_property($Sprite, "modulate:a", 0.0, 0.5)
# Move while invisible
tween.tween_property($Sprite, "position", Vector2(200, 0), 0.0)
# Fade in at new position
tween.tween_property($Sprite, "modulate:a", 1.0, 0.5)

Common Gotchas

Issue: Tween stops when node is removed

gdscript
# Solution: Bind tween to SceneTree
var tween := get_tree().create_tween()
tween.tween_property($Sprite, "position", Vector2(100, 0), 1.0)

Issue: Multiple conflicting tweens

gdscript
# Solution: Use single tween or kill previous
# Always store reference to kill old tween

Reference

Related