SpriteAnimation
Анимация спрайт-листа как аспект на Sprite — аксессор node.anim. Клипы
объявляются как данные (размер ячейки кадра плюс именованные списки индексов кадров) и затем
управляются по имени; после определения воспроизведение идёт полностью в нативном коде.
Обзор
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() })Настройка
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), либо объект с переопределениями на клип.
у спрайта уже должна быть texture, когда аспект прикрепляется — сетка нарезается из пиксельного
размера текстуры. Прикрепление без неё бросает.
передача size также задаёт мировой size спрайта равным размеру ячейки, поэтому одна ячейка
рисуется 1 тексель = 1 мировая единица.
sprite.anim.define(): this // пересобрать нативные клипы после изменения anim.clipsВоспроизведение
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') каждый кадр из кода
ввода, не перезапуская анимацию.
События
События анимации эмитятся на узле, с именем клипа как аргументом:
hero.addEventListener('loopReached', clip => {}) // зацикленный клип обернулся (каждый цикл)
hero.addEventListener('completed', clip => {}) // незацикленный клип завершился