О чем этот пример
Анимация персонажей и объектов — это основа динамичной и живой игры. В 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('sea', 'assets/animations/seacreatures_json.png', 'assets/animations/seacreatures_json.json');
// Just a few images to use in our underwater scene
this.load.image('undersea', 'assets/pics/undersea.jpg');
this.load.image('coral', 'assets/pics/seabed.png');
}
create ()
{
this.add.image(400, 300, 'undersea');
// Create the Animations
// These are stored globally, and can be used by any Sprite
// In the texture atlas the jellyfish uses the frame names blueJellyfish0000 to blueJellyfish0032
// So we can use the handy generateFrameNames function to create this for us (and so on)
this.anims.create({ key: 'jellyfish', frames: this.anims.generateFrameNames('sea', { prefix: 'blueJellyfish', end: 32, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'crab', frames: this.anims.generateFrameNames('sea', { prefix: 'crab1', end: 25, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'octopus', frames: this.anims.generateFrameNames('sea', { prefix: 'octopus', end: 24, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'purpleFish', frames: this.anims.generateFrameNames('sea', { prefix: 'purpleFish', end: 20, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'stingray', frames: this.anims.generateFrameNames('sea', { prefix: 'stingray', end: 23, zeroPad: 4 }), repeat: -1 });
const jellyfish = this.add.sprite(400, 300, 'seacreatures').play('jellyfish');
const bigCrab = this.add.sprite(550, 480, 'seacreatures').setOrigin(0).play('crab');
const smallCrab = this.add.sprite(730, 515, 'seacreatures').setScale(0.5).setOrigin(0).play('crab');
const octopus = this.add.sprite(100, 100, 'seacreatures').play('octopus');
const fish = this.add.sprite(600, 200, 'seacreatures').play('purpleFish');
const ray = this.add.sprite(100, 300, 'seacreatures').play('stingray');
this.add.image(0, 466, 'coral').setOrigin(0);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка ассетов: загрузка атласа и изображений
Вся подготовка данных происходит в методе preload. Ключевой момент — загрузка текстурного атласа с помощью метода this.load.atlas. Этот метод принимает три аргумента: уникальный ключ ассета, путь к изображению-атласу и путь к JSON-файлу с данными о координатах кадров (спрайтшит).
Дополнительно загружаются фоновые изображения для создания сцены.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('sea', 'assets/animations/seacreatures_json.png', 'assets/animations/seacreatures_json.json');
this.load.image('undersea', 'assets/pics/undersea.jpg');
this.load.image('coral', 'assets/pics/seabed.png');
}
Создание глобальных анимаций
Основная логика создания анимаций находится в методе create. Анимации создаются глобально через менеджер this.anims и могут быть использованы любым спрайтом в игре.
Для создания используется метод this.anims.create(), который принимает объект конфигурации. Самый важный параметр — frames. Вместо ручного перечисления всех кадров мы используем хелпер this.anims.generateFrameNames(). Этот метод анализирует загруженный атлас по ключу и генерирует массив кадров на основе переданных правил именования.
Рассмотрим параметры generateFrameNames для анимации медузы ('jellyfish'):
- prefix: 'blueJellyfish': Общая часть имени каждого кадра в атласе.
- end: 32: Номер последнего кадра в последовательности.
- zeroPad: 4: Указывает, что номер кадра дополнен нулями до 4 знаков (например, '0000', '0001', ..., '0032').
Параметр repeat: -1 задает бесконечное повторение анимации.
create ()
{
this.anims.create({ key: 'jellyfish', frames: this.anims.generateFrameNames('sea', { prefix: 'blueJellyfish', end: 32, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'crab', frames: this.anims.generateFrameNames('sea', { prefix: 'crab1', end: 25, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'octopus', frames: this.anims.generateFrameNames('sea', { prefix: 'octopus', end: 24, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'purpleFish', frames: this.anims.generateFrameNames('sea', { prefix: 'purpleFish', end: 20, zeroPad: 4 }), repeat: -1 });
this.anims.create({ key: 'stingray', frames: this.anims.generateFrameNames('sea', { prefix: 'stingray', end: 23, zeroPad: 4 }), repeat: -1 });
}
Создание спрайтов и запуск анимаций
После того как анимации созданы, мы можем добавлять спрайты и назначать им анимации. Спрайты создаются с помощью this.add.sprite(), где указывается позиция (x, y) и ключ текстурного атласа ('sea').
Обратите внимание: спрайт использует атлас как источник текстур, но конкретный кадр при создании не важен, так как мы сразу запускаем анимацию методом .play() с ключом созданной ранее анимации (например, 'jellyfish').
Для краба также демонстрируются методы настройки отрисовки: .setOrigin(0) меняет точку привязки (anchor) на верхний левый угол, а .setScale(0.5) уменьшает размер спрайта вдвое.
const jellyfish = this.add.sprite(400, 300, 'sea').play('jellyfish');
const bigCrab = this.add.sprite(550, 480, 'sea').setOrigin(0).play('crab');
const smallCrab = this.add.sprite(730, 515, 'sea').setScale(0.5).setOrigin(0).play('crab');
const octopus = this.add.sprite(100, 100, 'sea').play('octopus');
const fish = this.add.sprite(600, 200, 'sea').play('purpleFish');
const ray = this.add.sprite(100, 300, 'sea').play('stingray');
this.add.image(0, 466, 'coral').setOrigin(0);
Конфигурация и запуск игры
Это стандартная конфигурация игры Phaser. Важно, что в поле scene передается наш класс Example. Игра создается экземпляром Phaser.Game с этой конфигурацией.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Использование текстурных атласов и метода generateFrameNames — это эффективный и чистый способ работы с анимациями в Phaser. Он позволяет легко управлять большими наборами кадров и переиспользовать анимации между спрайтами.
Для экспериментов попробуйте:
1. Изменить параметры repeat (например, на 3) или frameRate в объекте конфигурации анимации.
2. Создать анимацию, которая проигрывается только по клику на спрайт, используя метод .play() в обработчике события.
3. Использовать другой метод для создания кадров, например, generateFrameNumbers, если ваши кадры в атласе пронумерованы последовательно, но без префикса.
