2D Game Engine

Tweeny i easing

to, from, delay, sekwencje, 28 krzywych easingu, repeat/yoyo i anulowanie. Animacje właściwości bez dotykania renderera.

Podstawy#

Tweeny mutują zwykłe właściwości obiektu (x, y, alpha, scale…) i nigdy nie dotykają renderera bezpośrednio — synchronizacja idzie przez dirty flags.

ts
this.tween(this.player, { x: 400, y: 300 }, { duration: 0.6, easing: 'quad.out' })

this.tweenFrom(this.title, { alpha: 0, y: 200 }, { duration: 0.5 })

this.delay(1.2, () => this.spawnBoss())

API#

ts
tweenManager.to(target, props, options?): Tween
tweenManager.from(target, props, options?): Tween
tweenManager.delay(seconds, onComplete?, options?): Tween
tweenManager.sequence(steps, options?): TweenSequence
tweenManager.add(tween); update(dt); pause(); resume()
tweenManager.cancel(tween): boolean
tweenManager.stopOwner(owner): number; stopAll()
tweenManager.size; activeCount; sequenceCount; isPaused

tween.play(); pause(); resume(); restart(); cancel(); complete()
tween.progress; totalProgress; values; isPlaying; isPaused; isFinished; isCancelled; stateName

TweenOptions#

ts
type TweenOptions = {
  duration?: number
  delay?: number
  easing?: string | ((t: number) => number)
  repeat?: number
  yoyo?: boolean
  owner?: string
  onStart?: () => void
  onUpdate?: () => void
  onRepeat?: () => void
  onComplete?: () => void
  onCancel?: () => void
}

repeat: -1 = nieskończona pętla.

Przykłady#

Pulsujący przycisk#

ts
this.tween(startButton, { scaleX: 1.08, scaleY: 1.08 }, {
  duration: 0.7,
  easing: 'sine.inOut',
  repeat: -1,
  yoyo: true
})

Wejście obiektu z opóźnieniem#

ts
this.tweenFrom(enemy, { alpha: 0, y: enemy.y - 60 }, {
  duration: 0.4,
  delay: 0.2,
  easing: 'back.out',
  onComplete: () => enemy.addTag('active')
})

Własna krzywa#

ts
this.tween(door, { y: 0 }, {
  duration: 0.8,
  easing: (t) => 1 - Math.pow(1 - t, 3)
})

Sekwencje#

ts
this.tweenSequence([
  { target: this.hero, props: { x: 300 }, duration: 0.5, easing: 'quad.out' },
  { target: this.hero, props: { y: 100 }, duration: 0.3, easing: 'quad.in' },
  { target: this.hero, props: { alpha: 0 }, duration: 0.2 }
], {
  owner: this.id,
  onComplete: () => this.destroyObject(this.hero)
})

TweenStep = { target, props, duration?, delay?, easing?, mode?, onStart?, onUpdate?, onComplete? }. SequenceOptions = { owner?, repeat?, onStart?, onComplete?, onCancel? }.

Anulowanie kroku anuluje całą sekwencję.

Easing — 28 krzywych#

EASINGS zawiera 28 krzywych (m.in. linear, quad, cubic, quart, quint, sine, expo, circ, back, elastic, bounce — każda w wariantach in, out, inOut). resolveEasing(name | fn) zwraca funkcję.

ts
import { EASINGS, resolveEasing } from '@engine'

const ease = resolveEasing('elastic.out')
const y = ease(0.5)

Własność i sprzątanie#

ts
this.tween(coin, { y: coin.y - 30, alpha: 0 }, {
  duration: 0.5,
  owner: this.id,
  onComplete: () => this.destroyObject(coin)
})

this.getTweens().stopOwner(this.id)

Informacja

Tweeny należą do sceny. Przy shutdown() silnik woła stopAll, więc animacje nie przeżywają sceny i nie mutują martwych obiektów.