LeCodesdocs

SpriteAnimation

Анимация спрайт-листа как аспект на Sprite — аксессор node.anim. Клипы объявляются как данные (размер ячейки кадра плюс именованные списки индексов кадров) и затем управляются по имени; после определения воспроизведение идёт полностью в нативном коде.

Обзор

TypeScript
const hero = new Sprite({ texture: tex, anchor: [0.5, 1] })
  .aspect(SpriteAnimation, {
    size: [32, 48],                                  // одна ячейка кадра, в пикселях текстуры
    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() })

Настройка

TypeScript
sprite.aspect(SpriteAnimation, {
  size?: [w, h]                    // размер ячейки кадра в пикселях текстуры; по умолчанию = вся текстура
  fps?: number                     // fps по умолчанию для клипов; по умолчанию 12
  loop?: boolean                   // loop по умолчанию для клипов; по умолчанию true
  clips?: Record<string, Clip>     // Clip = number[] | { frames: number[], fps?, loop? }
})

Индексы кадров считаются построчно по сетке листа: сетка имеет floor(texture.width / cellW) столбцов, индекс 0 — верхняя-левая ячейка, индексы продолжаются слева направо, затем вниз. Клип — это либо простой массив индексов (наследует fps/loop), либо объект с переопределениями на клип.

Note

у спрайта уже должна быть texture, когда аспект прикрепляется — сетка нарезается из пиксельного размера текстуры. Прикрепление без неё бросает.

Note

передача size также задаёт мировой size спрайта равным размеру ячейки, поэтому одна ячейка рисуется 1 тексель = 1 мировая единица.

TypeScript
sprite.anim.define(): this    // пересобрать нативные клипы после изменения anim.clips

Воспроизведение

TypeScript
sprite.anim.play(name: string): this   // бросает на неизвестное имя клипа
sprite.anim.stop(): this
sprite.anim.speed = 2                  // множитель скорости воспроизведения (только запись)
sprite.anim.current                    // имя играющего клипа или null
sprite.anim.frame                      // текущий индекс кадра (только чтение)

Повторный запуск уже активного клипа — no-op — безопасно звать play('walk') каждый кадр из кода ввода, не перезапуская анимацию.

События

События анимации эмитятся на узле, с именем клипа как аргументом:

TypeScript
hero.addEventListener('loopReached', clip => {})   // зацикленный клип обернулся (каждый цикл)
hero.addEventListener('completed', clip => {})     // незацикленный клип завершился

Смотрите также

  • Sprite — узел-хост; ручные frame / setFramePx.
  • Texture2D — загрузка листа.
  • Node2DaddEventListener.