Can you write this from memory?
Set up a tween animation system for smooth effects, storing it in a variable called tween.
In GDScript, tweens are code-driven mini-animations: hit flashes, pop scales, UI slides, smooth fades, and camera nudges.
Godot 4 uses Tween + Tweener objects: create_tween() → add tween_property/tween_callback/tween_interval → optionally await tween.finished.
Tween = the sequence controller. Tweener = one step (PropertyTweener, CallbackTweener, IntervalTweener, MethodTweener).
Create (don't use Tween.new)
var t := create_tween() # Node.create_tween()
Basic property tween
t.tween_property(self, "scale", Vector2.ONE * 1.2, 0.1)
Parallel, then continue
var t := create_tween().set_parallel(true)
t.tween_property(self, "position", target_pos, 0.2)
t.tween_property(self, "modulate:a", 0.0, 0.2)
t.chain().tween_callback(queue_free)
Kill/replace (avoid fighting tweens)
if hit_tween:
hit_tween.kill()
hit_tween = create_tween()
Delay / tween as timer
await create_tween().tween_interval(0.2).finished
1) Damage Flash (replace previous)
var flash_tween: Tween
func flash() -> void:
if flash_tween:
flash_tween.kill()
flash_tween = create_tween()
flash_tween.tween_property(self, "modulate", Color(1.6, 1.6, 1.6), 0.05)
flash_tween.tween_property(self, "modulate", Color.WHITE, 0.1)
2) Pickup Pop (squash/stretch)
func pop() -> void:
var t := create_tween()
t.tween_property(self, "scale", Vector2(1.3, 0.7), 0.08)
t.tween_property(self, "scale", Vector2(0.9, 1.1), 0.08)
t.tween_property(self, "scale", Vector2.ONE, 0.1)
3) UI Punch (spam-safe)
Use from_current() so repeated calls start from "where it is now":
var punch_tween: Tween
func punch_score() -> void:
if punch_tween:
punch_tween.kill()
punch_tween = create_tween()
punch_tween.tween_property(score_label, "scale", Vector2.ONE * 1.4, 0.08).from_current()
punch_tween.tween_property(score_label, "scale", Vector2.ONE, 0.12).from_current()
var t := create_tween().set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_OUT)
t.tween_property(self, "position", target_pos, 0.25)
Common combos:
- Smooth UI: TRANS_QUAD + EASE_OUT
- Snappy overshoot: TRANS_BACK + EASE_OUT
- Bouncy: TRANS_BOUNCE + EASE_OUT
- Elastic: TRANS_ELASTIC + EASE_OUT
func fade_out_and_free() -> void:
var t := create_tween()
t.tween_property(self, "modulate:a", 0.0, 0.25)
t.tween_interval(0.05)
t.tween_callback(queue_free)
await t.finished
var t := create_tween().bind_node(self).set_loops()
t.tween_callback(shoot).set_delay(1.0)
Warning: Infinite loops must include some duration/delay, or they can freeze / stop unexpectedly. Use
bind_node()to ensure the tween dies with the node.
Move and fade at the same time, then do something after both finish:
func slide_out() -> void:
var t := create_tween().set_parallel(true)
t.tween_property(self, "position:x", position.x + 200, 0.3)
t.tween_property(self, "modulate:a", 0.0, 0.3)
t.chain().tween_callback(queue_free) # Runs after both complete
When to Use GDScript Tweens & Polish
- Hit feedback: flash, knockback, brief scale squash/stretch
- UI animations: slide-in panels, fade-in/out, progress bar smoothing
- Camera smoothing and small polish effects (shake, zoom pulses)
Check Your Understanding: GDScript Tweens & Polish
Check Your Understanding: When would you use Tween vs AnimationPlayer?
Use Tween for quick code-driven one-offs (small UI movements, hit flashes, procedural effects). Use AnimationPlayer for authored timelines, complex sequences, or when designers/animators need to edit animations visually.
What You'll Practice: GDScript Tweens & Polish
Common GDScript Tweens & Polish Pitfalls
- Using Tween.new() (always invalid) instead of create_tween()
- Creating multiple tweens that fight over the same property—kill/replace previous tween
- Infinite loops with 0-duration steps (can freeze)—always include a delay or duration
- Not using bind_node() for long-lived/looped tweens—they may outlive the node
- Not using from_current() when re-triggering tweens—spam causes jumps
- Forgetting that tween_property uses a property name string—typos fail silently
GDScript Tweens & Polish FAQ
Why does Tween.new() not work in Godot 4?
Tweens created manually with Tween.new() are invalid. You must create them with Node.create_tween() or SceneTree.create_tween() so they're added to the scene tree.
How do I tween two properties at once, then continue?
Use set_parallel(true) for simultaneous tweens, then chain() to continue sequentially: create_tween().set_parallel(true).tween_property(...).tween_property(...).chain().tween_callback(...)
How do I add a delay inside a tween sequence?
Use tween_interval(seconds). You can also await create_tween().tween_interval(x).finished for a quick inline delay.
How do I loop a tween safely?
Use set_loops() and always include a duration/delay (e.g., tween_callback().set_delay(1.0)). Use bind_node(self) so the tween stops when the node is freed.
How do I wait for a tween to finish?
Use await tween.finished after creating the tween. The function pauses until the tween completes.
Why do my tweens stack and look weird?
You're creating new tweens without stopping old ones. Store a tween reference and call tween.kill() before creating a new one on the same property.
Why does my repeated tween "jump" when spammed?
Use from_current() on PropertyTweeners so they start from the current value instead of the original. This prevents jumps when re-triggering tweens.
What is from_current() vs as_relative()?
from_current() uses the property's current value as the start point. as_relative() treats the target as an offset from current (e.g., +100 pixels instead of "to 100").
How do I tween in physics time?
Use tween.set_process_mode(Tween.TWEEN_PROCESS_PHYSICS). The tween then updates in sync with _physics_process instead of _process.
GDScript Tweens & Polish Syntax Quick Reference
func pop() -> void:
var t := create_tween()
t.tween_property(self, "scale", Vector2(1.2, 0.8), 0.07)
t.tween_property(self, "scale", Vector2.ONE, 0.1)func slide_out() -> void:
var t := create_tween().set_parallel(true)
t.tween_property(self, "position:x", position.x + 200, 0.3)
t.tween_property(self, "modulate:a", 0.0, 0.3)
t.chain().tween_callback(queue_free)func start_pulse() -> void:
var t := create_tween().bind_node(self).set_loops()
t.tween_property(self, "modulate:a", 0.5, 0.5)
t.tween_property(self, "modulate:a", 1.0, 0.5)var punch_tween: Tween
func punch() -> void:
if punch_tween:
punch_tween.kill()
punch_tween = create_tween()
punch_tween.tween_property(self, "scale", Vector2.ONE * 1.3, 0.08).from_current()
punch_tween.tween_property(self, "scale", Vector2.ONE, 0.1).from_current()GDScript Tweens & Polish Sample Exercises
Create a hit flash that fades sprite from red to white over 0.2s. Chain tween_property on the tween variable. (Assume tween and sprite exist.)
tween.tween_property(sprite, "modulate", Color.WHITE, 0.2).from(Color.RED)Configure a tween to run animations in parallel instead of sequentially using set_parallel(). (Assume tween exists.)
tween.set_parallel(true)Add two sequential tween_property calls on the `tween` object: fade out sprite's modulate alpha to 0.0 over 0.3s, then scale to Vector2.ZERO over 0.2s. Write each call on a separate line.
tween.tween_property(sprite, "modulate:a", 0.0, 0.3)
tween.tween_property(sprite, "scale", Vector2.ZERO, 0.2)+ 15 more exercises