LeCodesdocs

SpriteAnimation

Sprite-sheet animation, as an aspect on a Sprite — accessor node.anim. Clips are declared as data (a frame cell size plus named frame-index lists) and then driven by name; once defined, playback advances entirely in native code.

At a glance

TypeScript
const hero = new Sprite({ texture: tex, anchor: [0.5, 1] })
  .aspect(SpriteAnimation, {
    size: [32, 48],                                  // one frame cell, in texture pixels
    fps: 10,
    clips: {
      idle: [0, 1],
      walk: [4, 5, 6, 7],
      die:  { frames: [8, 9, 10], fps: 6, loop: false },
    },
  })

hero.anim.play('walk')
hero.addEventListener('completed', clip => { if (clip === 'die') hero.destroy() })

Configuring

TypeScript
sprite.aspect(SpriteAnimation, {
  size?: [w, h]                    // frame cell size in texture pixels; default = full texture
  fps?: number                     // default fps for clips; default 12
  loop?: boolean                   // default loop for clips; default true
  clips?: Record<string, Clip>     // Clip = number[] | { frames: number[], fps?, loop? }
})

Frame indices count row-major through the sheet's grid: the grid has floor(texture.width / cellW) columns, index 0 is the top-left cell, and indices continue left-to-right, then down. A clip is either a plain index array (inherits fps/loop) or an object with per-clip overrides.

Note

the sprite must already have its texture when the aspect attaches — the grid is sliced from the texture's pixel size. Attaching without one throws.

Note

passing size also sets the sprite's world size to the cell size, so one cell draws at 1 texel = 1 world unit.

TypeScript
sprite.anim.define(): this    // rebuild native clips after mutating anim.clips

Playback

TypeScript
sprite.anim.play(name: string): this   // throws on an unknown clip name
sprite.anim.stop(): this
sprite.anim.speed = 2                  // playback rate multiplier (write-only)
sprite.anim.current                    // name of the playing clip, or null
sprite.anim.frame                      // current frame index (read-only)

Re-playing the already-active clip is a no-op — safe to call play('walk') every frame from input code without restarting the animation.

Events

Animation events are emitted on the node, with the clip name as the argument:

TypeScript
hero.addEventListener('loopReached', clip => {})   // a looping clip wrapped around (each loop)
hero.addEventListener('completed', clip => {})     // a non-looping clip finished

See also

  • Sprite — the host node; manual frame / setFramePx
  • Texture2D — loading the sheet
  • Node2DaddEventListener