О чем этот пример
Создание анимаций из атласов спрайтов — рутинная задача. Вручную прописывать десятки кадров с нумерацией — долго и чревато ошибками. К счастью, Phaser предоставляет мощный метод `generateFrameNames`, который автоматически генерирует массив кадров по заданному шаблону. Эта статья покажет, как эффективно использовать этот метод для быстрого создания сложных анимаций, экономя время и упрощая поддержку кода.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
}
create ()
{
this.add.text(400, 32, 'Check the source code for comments', { color: '#00ff00' }).setOrigin(0.5, 0);
// The gems.json file has the following frames in it:
// diamond_0000 to diamond_0015
// So we use:
// generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 })
// Because the prefix is 'diamond_', it has 4 zeros in it (0000), which start at 0000 and end at 0015.
// If the frame names had a suffix, i.e. 'diamond_0000.png' then you could do:
// generateFrameNames('gems', { prefix: 'diamond_', suffix: '.png', end: 15, zeroPad: 4 })
this.anims.create({ key: 'diamond', frames: this.anims.generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'prism', frames: this.anims.generateFrameNames('gems', { prefix: 'prism_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'ruby', frames: this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
this.add.sprite(400, 200, 'gems').play('diamond');
this.add.sprite(400, 300, 'gems').play('prism');
this.add.sprite(400, 400, 'gems').play('ruby');
this.add.sprite(400, 500, 'gems').play('square');
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
pixelArt: true,
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка атласа и подготовка
Всё начинается с загрузки атласа спрайтов — изображения, содержащего все кадры анимации, и JSON-файла с их координатами. В нашем примере мы загружаем атлас с ключом 'gems'.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
}
После загрузки в create() мы можем создавать анимации. Ключевой момент: кадры в JSON-файле имеют последовательные имена, такие как diamond_0000, diamond_0001 и так далее. Именно эту закономерность мы и будем использовать.
Метод generateFrameNames и его параметры
Метод this.anims.generateFrameNames() генерирует массив объектов-кадров для анимации на основе переданного шаблона. Он принимает два аргумента: ключ текстуры (атласа) и объект конфигурации.
Основные параметры конфигурации:
- prefix: Префикс имени кадра (например, 'diamond_').
- end: Номер последнего кадра в последовательности.
- zeroPad: Количество цифр в номере кадра. Если номер меньше, он будет дополнен нулями слева.
- suffix: Суффикс имени кадра (например, '.png'), если он присутствует в исходных данных.
Вот как создаётся анимация для алмаза:
this.anims.create({
key: 'diamond',
frames: this.anims.generateFrameNames('gems', {
prefix: 'diamond_',
end: 15,
zeroPad: 4
}),
repeat: -1
});
Этот код сгенерирует массив кадров для имён от diamond_0000 до diamond_0015. Параметр repeat: -1 задаёт бесконечное повторение анимации.
Создание нескольких анимаций из одного атласа
Один атлас часто содержит кадры для нескольких анимаций. Используя разные префиксы в вызове generateFrameNames, мы можем легко создать их все. В примере создаются четыре разные анимации: 'diamond', 'prism', 'ruby' и 'square'.
this.anims.create({ key: 'prism', frames: this.anims.generateFrameNames('gems', { prefix: 'prism_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'ruby', frames: this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
Обратите внимание, что анимации 'prism' и 'ruby' используют 7 кадров (от 0 до 6), а 'square' — 15 кадров (от 0 до 14). Метод гибко адаптируется под разные последовательности.
Воспроизведение анимаций на спрайтах
После регистрации анимаций в менеджере анимаций (this.anims), их можно проигрывать на любых спрайтах, использующих тот же текстурый атлас. Создаём спрайт и вызываем метод .play() с ключом нужной анимации.
this.add.sprite(400, 200, 'gems').play('diamond');
this.add.sprite(400, 300, 'gems').play('prism');
this.add.sprite(400, 400, 'gems').play('ruby');
this.add.sprite(400, 500, 'gems').play('square');
Каждый спрайт ссылается на текстуру 'gems', но проигрывает свою собственную последовательность кадров, определённую при создании анимации. Это классический и эффективный подход для работы с атласами.
Полная конфигурация игры
Для полноты картины приведём стандартную конфигурацию игры Phaser 3, которая запускает наш пример. Важный параметр pixelArt: true помогает сохранить чёткость пиксельной графики.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
pixelArt: true,
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Этот код инициализирует игровой экземпляр с настройками по умолчанию и запускает сцену Example, содержащую всю логику с анимациями.
Что попробовать дальше
Метод generateFrameNames — незаменимый инструмент для работы с последовательно пронумерованными кадрами в атласах. Он устраняет рутину и потенциальные ошибки при создании анимаций. Для экспериментов попробуйте: изменить параметр zeroPad на 2 для кадров вида diamond_00; добавить параметр start для начала последовательности не с нуля; использовать suffix, если имена кадров в JSON включают расширение файла. Это откроет полный контроль над процессом генерации.
