197 lines
7.6 KiB
Markdown
197 lines
7.6 KiB
Markdown
---
|
|
id: tween
|
|
icon: play.start
|
|
group: gameplay
|
|
title: Tweens and timers
|
|
order: 3
|
|
---
|
|
# Tweens and timers
|
|
|
|
A tween moves one property of a node from its current value to a target over time; a timer counts down and fires. Both run during Play and in `aego run`, belong to the play world and allocate nothing per frame once created.
|
|
|
|
import (
|
|
"aego/curve"
|
|
"aego/timer"
|
|
"aego/tween"
|
|
)
|
|
|
|
func Hurt() coroutine {
|
|
yield tween.ToColor(node, "SpriteRenderer.Tint", HitTint, 0.1, curve.OutQuad)
|
|
yield tween.ToColor(node, "SpriteRenderer.Tint", Color{1, 1, 1, 1}, 0.3, curve.InQuad)
|
|
}
|
|
|
|
---
|
|
id: tween/paths
|
|
icon: view.vectors
|
|
parent: tween
|
|
order: 1
|
|
title: Property paths
|
|
---
|
|
# Property paths
|
|
|
|
A tween names its property by a path, resolved once when the tween starts.
|
|
|
|
| Path | Property |
|
|
|---|---|
|
|
| `SpriteRenderer.Tint` | a component field; the short component name works when it is unique, otherwise write `render2d.SpriteRenderer.Tint` |
|
|
| `SpriteRenderer.Tint.a` | one lane of a vector or color: `x y z w` or `r g b a` |
|
|
| `transform.position`, `transform.rotation`, `transform.scale` | the local transform, 2D or 3D |
|
|
| `script/Player.Speed`, `script/mygame.player.Player.Speed` | an exported or private field of a script on the node |
|
|
|
|
Field names are accepted as in the schema (`tint`) or with an upper-case first letter (`Tint`). Values that tween: `float` and `int` (rounded), `Vec2`, `Vec3`, `Color`, `Rect`, `Quat` (shortest arc). Strings, enums, references, read-only fields and lists do not. A wrong path or a value of the wrong type stops the calling script with `AES6010` and returns `nil`.
|
|
|
|
Tweening the transform of a dynamic physics body is a teleport at the next physics step; move bodies with velocity instead.
|
|
|
|
---
|
|
id: tween/scripts
|
|
icon: file.script
|
|
parent: tween
|
|
order: 2
|
|
title: Tweens in scripts
|
|
---
|
|
# Tweens in scripts
|
|
|
|
| Function | |
|
|
|---|---|
|
|
| `ToFloat(node, path, to float, duration, ease) Tween` | a float or int property, or one lane |
|
|
| `ToVec2`, `ToVec3`, `ToColor`, `ToQuat(node, path, to, duration, ease) Tween` | vector, color and rotation properties |
|
|
| `Position(node, to Vec2, duration, ease) Tween` | `transform.position` of a 2D node |
|
|
|
|
`ease` is a preset from `aego/curve`: `curve.Linear`, `curve.OutQuad`, `curve.InOutSine`, `curve.OutBack`, `curve.OutBounce` and the rest of the `in`/`out`/`inOut` family of quad, cubic, sine, expo, back, elastic and bounce.
|
|
|
|
Options are chained right after the call:
|
|
|
|
tween.ToFloat(node, "SpriteRenderer.Tint.a", 0, 0.5, curve.Linear).Delay(1).PingPong(-1)
|
|
|
|
| Method | |
|
|
|---|---|
|
|
| `Delay(s)` | wait before starting; the start value is read when the delay ends |
|
|
| `Loop(n)` | play `n` times from the start, `-1` forever |
|
|
| `PingPong(n)` | `n` legs, every second one backwards; `2` goes there and back |
|
|
| `Unscaled()` | real time: runs while the game is paused and ignores the time scale |
|
|
| `Curve(c)` | use a curve field instead of the easing, its time range stretched over the duration |
|
|
| `Stop()` | end where it is; the property keeps its current value |
|
|
| `Done() bool`, `Running() bool` | state; a `nil`, stopped or finished tween is done |
|
|
| `Completed(finished bool)` | signal, once when the tween ends; `finished` is false after `Stop`, a replacement or a lost target |
|
|
|
|
Rules:
|
|
|
|
- When the last leg ends, the property gets exactly the end value: `to`, or the start after an even number of ping-pong legs.
|
|
- A new tween on the same property of the same node stops the running one.
|
|
- A tween stops when its node, its component or its script is gone.
|
|
|
|
---
|
|
id: tween/timers
|
|
icon: panel.profiler
|
|
parent: tween
|
|
order: 3
|
|
title: Timers
|
|
---
|
|
# Timers
|
|
|
|
var attack timer.Timer
|
|
|
|
func Ready() {
|
|
attack = timer.Cooldown(0.4)
|
|
}
|
|
|
|
func Update(dt float) {
|
|
if input.Pressed("Fire") && attack.Use() {
|
|
shoot()
|
|
}
|
|
}
|
|
|
|
| Function | |
|
|
|---|---|
|
|
| `timer.Start(s) Timer` | a one-shot timer; it frees itself when it fires |
|
|
| `timer.New(s) Timer` | a timer that stays after it ends, so `Restart` can run it again |
|
|
| `timer.Cooldown(s) Timer` | starts ready; `Use()` takes it and starts the wait |
|
|
|
|
| Method | |
|
|
|---|---|
|
|
| `Repeat(n) Timer` | fire `n` times, `-1` until `Cancel` |
|
|
| `Unscaled() Timer` | count real time |
|
|
| `Pause()`, `Resume()`, `Restart() bool`, `Cancel()` | control |
|
|
| `Done() bool`, `Remaining() float`, `Count() int` | state |
|
|
| `Ready() bool`, `Use() bool` | cooldowns |
|
|
| `Fired(count int)` | signal, on every fire |
|
|
|
|
A timer made by a script belongs to that script's node and is cancelled when the node is destroyed. `Restart` on a one-shot timer that already fired does nothing: its slot is gone. Use `timer.New` for timers you restart.
|
|
|
|
---
|
|
id: tween/waiting
|
|
icon: status.busy
|
|
parent: tween
|
|
order: 4
|
|
title: Waiting in coroutines
|
|
---
|
|
# Waiting in coroutines
|
|
|
|
`yield` waits for a tween or a timer:
|
|
|
|
func Die() coroutine {
|
|
yield tween.ToFloat(node, "SpriteRenderer.Tint.a", 0, 0.2, curve.OutQuad)
|
|
node.Destroy()
|
|
}
|
|
|
|
func Spawner() coroutine {
|
|
t := timer.New(2).Repeat(-1)
|
|
for {
|
|
yield t
|
|
spawn()
|
|
}
|
|
}
|
|
|
|
How waits resume:
|
|
|
|
- `yield t` resumes on the frame after the tween ends or is stopped, or after the timer fires or is cancelled.
|
|
- A repeating timer wakes the coroutine on every fire.
|
|
- A `nil` or finished handle resumes on the next frame.
|
|
- Woken coroutines run with the other game-time coroutines, so they wait while the game is paused even when the tween or timer itself is unscaled. In a pause menu, wait with `yield waitUnscaled(s)`.
|
|
|
|
There is no polling: a coroutine parked on a handle costs nothing until the handle wakes it.
|
|
|
|
---
|
|
id: tween/actions
|
|
icon: panel.tasks
|
|
parent: tween
|
|
order: 5
|
|
title: Actions
|
|
---
|
|
# Actions
|
|
|
|
An action runs tweens and timers in order or together:
|
|
|
|
yield action.Sequence().
|
|
Then(tween.Position(node, Vec2{4, 0}, 0.5, curve.OutCubic)).
|
|
Wait(0.2).
|
|
Then(tween.ToFloat(node, "SpriteRenderer.Tint.a", 0, 0.3, curve.Linear))
|
|
|
|
| Function or method | |
|
|
|---|---|
|
|
| `action.Sequence()`, `action.Parallel()` | a new action; it starts at the next tween update |
|
|
| `Then(tween)`, `ThenTimer(timer)`, `ThenAction(action)`, `Wait(s)` | steps, added before the action starts |
|
|
| `Stop()`, `Done()`, `Running()` | control and state |
|
|
| `Completed(finished bool)` | signal when the action ends |
|
|
|
|
A tween or timer passed to `Then` must be created in the same frame and belong to no other action; it waits for its turn. A step that ends early counts as done. `Stop` stops every unfinished step and ends the action with `finished=false`. An action is stopped when the node of the script that made it dies. A coroutine waits for an action with `yield a`; an action cannot wait for a coroutine.
|
|
|
|
---
|
|
id: tween/go
|
|
icon: code.brackets
|
|
parent: tween
|
|
order: 6
|
|
title: Go
|
|
---
|
|
# Go
|
|
|
|
tw := sdk.TweensOf(ctx)
|
|
h, err := tw.ToVec2(node, "transform.scale", sdk.Vec2{X: 1.2, Y: 1.2}, 0.1, sdk.TweenOptions{Ease: curve.OutBack, Legs: 2, PingPong: true})
|
|
t, _ := tw.StartTimer(1.5, sdk.TimerOptions{Repeat: -1, Owner: node})
|
|
|
|
`TweenOptions` has `Ease`, `Curve`, `Delay`, `Legs`, `PingPong` and `Unscaled`. `TimerOptions` has `Repeat`, `Unscaled`, `Keep` and `Owner`. Handles are values; a stale handle reads as done.
|
|
|
|
The systems `tween.game` (PostUpdate, stops while paused) and `tween.unscaled` (PostUpdate, always runs) advance the pools. A module that hands out its own awaitable handles registers them with `sdk.ScriptHandle` and calls `scriptwait.Waker.Complete` when an object ends (see Native bindings in the language reference).
|
|
|
|
`OnCompleted(h, func(finished bool))` and `OnFired(h, func(count int))` connect Go code to the same signals and return a `Connection` for `Disconnect`.
|