О чем этот пример
Создание плавной анимации из спрайтшита — основа визуальной динамики в играх. Phaser предлагает несколько способов указать, какие кадры использовать, от автоматического выбора всех кадров до тонкой настройки последовательности. В этой статье мы разберем три подхода на примере анимации взрыва, чтобы вы могли выбрать оптимальный для своего проекта и контролировать каждый кадр анимации.
Версия 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.spritesheet('boom', 'assets/sprites/explosion.png', { frameWidth: 64, frameHeight: 64, endFrame: 23 });
}
create ()
{
this.add.text(400, 32, 'Check the source code for comments', { color: '#00ff00' }).setOrigin(0.5, 0);
// Our 'boom' spritesheet has 23 frames in it.
// This animation will use them all by just giving it the sprite sheet key:
const config1 = {
key: 'explode1',
frames: 'boom',
frameRate: 20,
repeat: -1
};
// Here we use the 'generateFrameNumbers' function instead to set the start and end frame:
const config2 = {
key: 'explode2',
frames: this.anims.generateFrameNumbers('boom', { start: 0, end: 23 }),
frameRate: 20,
repeat: -1
};
// Here we use the 'frames' array because we want to specify the exact frames to use:
const config3 = {
key: 'explode3',
frames: this.anims.generateFrameNumbers('boom', { frames: [ 0, 1, 2, 1, 2, 3, 4, 0, 1, 2 ] }),
frameRate: 20,
repeat: -1
};
this.anims.create(config1);
this.anims.create(config2);
this.anims.create(config3);
this.add.sprite(200, 300, 'boom').play('explode1');
this.add.sprite(400, 300, 'boom').play('explode2');
this.add.sprite(600, 300, 'boom').play('explode3');
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка спрайтшита: подготовка данных
Перед созданием анимации необходимо загрузить спрайтшит — изображение, содержащее все кадры. Ключевой метод load.spritesheet принимает ключ для идентификации, путь к файлу и объект конфигурации.
this.load.spritesheet('boom', 'assets/sprites/explosion.png', { frameWidth: 64, frameHeight: 64, endFrame: 23 });
В этом примере мы задали ключ 'boom', ширину и высоту каждого кадра (64x64), а также явно указали последний кадр (endFrame: 23). Phaser автоматически "нарежет" изображение на 24 кадра (от 0 до 23). Указание endFrame помогает движку, если количество кадров неочевидно.
Подход 1: Простая анимация из всего спрайтшита
Самый простой способ создать анимацию — передать ключ спрайтшита напрямую в свойство frames конфигурационного объекта. Phaser сам сгенерирует номера всех кадров, на которые был разрезан спрайтшит при загрузке.
const config1 = {
key: 'explode1',
frames: 'boom',
frameRate: 20,
repeat: -1
};
Здесь key — это уникальное имя анимации для последующего воспроизведения. Свойство frames содержит строку 'boom', что является инструкцией для Phaser: "возьми все кадры из спрайтшита с этим ключом". frameRate задает скорость проигрывания (20 кадров в секунду), а repeat: -1 делает анимацию зацикленной бесконечно. Этот метод идеален, когда нужно проиграть все кадры подряд без исключений.
Подход 2: Указание диапазона кадров через generateFrameNumbers
Для большего контроля используйте метод this.anims.generateFrameNumbers(). Он позволяет явно задать начальный и конечный кадры для анимации.
const config2 = {
key: 'explode2',
frames: this.anims.generateFrameNumbers('boom', { start: 0, end: 23 }),
frameRate: 20,
repeat: -1
};
Метод generateFrameNumbers первым аргументом принимает ключ спрайтшита, а вторым — объект опций. В данном случае опции start и end определяют диапазон. Результатом вызова метода является массив объектов-кадров, который помещается в свойство frames. Этот подход полезен, если ваш спрайтшит содержит несколько анимаций в одном ряду или вам нужно проиграть только часть кадров.
Подход 3: Произвольная последовательность кадров
Самый гибкий вариант — задать массив с конкретными номерами кадров в нужном порядке. Это делается с помощью опции frames внутри вызова generateFrameNumbers.
const config3 = {
key: 'explode3',
frames: this.anims.generateFrameNumbers('boom', { frames: [ 0, 1, 2, 1, 2, 3, 4, 0, 1, 2 ] }),
frameRate: 20,
repeat: -1
};
Здесь мы передаем массив [0, 1, 2, 1, 2, 3, 4, 0, 1, 2]. Phaser создаст анимацию, которая проигрывает кадры именно в этой последовательности. Это открывает возможности для нелинейных анимаций: можно создать эффект "дрожания" (повторяя кадры 1 и 2), вернуться к началу в середине последовательности или вовсе пропустить многие кадры.
Создание и воспроизведение анимаций
После настройки конфигурационных объектов их необходимо зарегистрировать в менеджере анимаций сцены и применить к спрайтам.
this.anims.create(config1);
this.anims.create(config2);
this.anims.create(config3);
this.add.sprite(200, 300, 'boom').play('explode1');
this.add.sprite(400, 300, 'boom').play('explode2');
this.add.sprite(600, 300, 'boom').play('explode3');
Метод this.anims.create() регистрирует анимацию в глобальном хранилище сцены по ключу, указанному в конфиге. После этого любой спрайт может её проиграть. В примере мы создаем три спрайта с помощью this.add.sprite(), передавая начальный ключ текстуры ('boom'), а затем для каждого вызываем метод .play() с ключом нужной анимации ('explode1', 'explode2', 'explode3').
Что попробовать дальше
Phaser предоставляет три уровня контроля над анимацией: от автоматического использования всех кадров до программирования сложных последовательностей. Для быстрого прототипирования используйте передачу ключа спрайтшита. Для стандартных анимаций — задавайте диапазон start и end. Для уникальных эффектов, вроде мерцания или возврата назад, составляйте массив frames. Экспериментируйте: попробуйте создать анимацию дыхания персонажа, циклически повторяя 2-3 кадра, или эффект телепортации, проигрывая кадры в обратном порядке.
