О чем этот пример
При создании 2D-игр часто требуется управлять множеством анимаций. Phaser 3 предлагает мощный и гибкий способ загрузки данных об анимациях — отдельно от атласов текстур. Это улучшает организацию кода, позволяет переиспользовать одни и те же анимации для разных наборов спрайтов и упрощает работу художникам, которые могут редактировать JSON-файлы независимо. В этой статье мы разберем, как загружать анимации из внешнего JSON-файла и применять их к спрайтам из Texture Atlas.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.animation('gemData', 'assets/animations/gems.json');
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
}
create ()
{
this.add.sprite(400, 100, 'gems').play('diamond');
this.add.sprite(400, 200, 'gems').play('prism');
this.add.sprite(400, 300, 'gems').play('ruby');
this.add.sprite(400, 400, 'gems').play('square');
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Зачем нужна отдельная загрузка анимаций?
Обычно анимации можно определять прямо в коде с помощью this.anims.create(). Однако для больших проектов с десятками анимаций такой подход становится громоздким. Загрузка анимаций из JSON позволяет:
1. **Декомпозировать данные:** Хранить конфигурацию анимаций (кадры, частоту, повторение) отдельно от логики игры. 2. **Упростить контент-менеджмент:** Художники или геймдизайнеры могут редактировать JSON-файлы, не касаясь кода. 3. **Переиспользовать анимации:** Один JSON-файл с анимациями можно применять к разным атласам спрайтов, если в них одинаковая структура кадров.
В примере мы загружаем файл gems.json, который содержит определения нескольких анимаций для драгоценных камней.
Настройка загрузки в методе preload
Ключевой этап — загрузка ресурсов. Мы используем два метода загрузчика (this.load): один для данных анимации, другой для текстур.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.animation('gemData', 'assets/animations/gems.json');
this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
1. setBaseURL задает базовый URL для всех последующих загрузок, что избавляет от необходимости прописывать полные пути.
2. load.animation('gemData', ...) загружает JSON-файл с конфигурацией анимаций и регистрирует его в менеджере анимаций под ключом 'gemData'. Важно: это именно **ключ данных**, а не ключ текстуры.
3. load.atlas('gems', ...) загружает атлас текстур — изображение (gems.png) и файл с координатами кадров (gems.json). Он регистрирует текстуру под ключом 'gems'.
После выполнения preload Phaser автоматически создаст все анимации, описанные в файле assets/animations/gems.json.
Создание и запуск анимированных спрайтов
В методе create, когда все ресурсы загружены, мы создаем спрайты и запускаем на них анимации. Код очень лаконичен, так как вся сложность описания анимаций уже скрыта в JSON-файле.
this.add.sprite(400, 100, 'gems').play('diamond');
this.add.sprite(400, 200, 'gems').play('prism');
this.add.sprite(400, 300, 'gems').play('ruby');
this.add.sprite(400, 400, 'gems').play('square');
1. `this.add.sprite(x, y, 'gems')` создает спрайт в указанных координатах, используя текстуру из атласа с ключом `'gems'`.
2. Метод `.play('diamond')` ищет в глобальном менеджере анимаций (`this.anims`) анимацию с ключом `'diamond'`. Эта анимация была автоматически создана и зарегистрирована при загрузке файла `gemData`. Phaser сопоставляет кадры анимации с кадрами из атласа `'gems'` на основе их названий, указанных в JSON.
Таким образом, спрайт «знает», какую текстуру использовать для отрисовки, а менеджер анимаций «знает», в какой последовательности и с какой скоростью эти текстуры менять.
Структура конфигурационного JSON-файла
Чтобы метод работал корректно, JSON-файл должен следовать определенному формату, который ожидает Phaser. Вот пример структуры для одной анимации:
on
{
"anims": [
{
"key": "diamond",
"frames": [
{ "key": "gems", "frame": "diamond_01" },
{ "key": "gems", "frame": "diamond_02" },
{ "key": "gems", "frame": "diamond_03" }
],
"frameRate": 12,
"repeat": -1
}
]
}
* key: Уникальный ключ анимации, который используется в методе .play().
* frames: Массив объектов, каждый из которых ссылается на конкретный кадр. Поле key внутри каждого кадра — это ключ текстуры ('gems'), а frame — имя конкретного фрейма внутри атласа (должно соответствовать именам в gems.json).
* frameRate: Скорость воспроизведения в кадрах в секунду.
* repeat: Количество повторений (-1 для бесконечного цикла).
В одном файле anims может быть массив с множеством таких определений анимаций.
Что попробовать дальше
Использование load.animation() для загрузки анимаций из JSON — это профессиональный подход к структурированию игровых данных в Phaser 3. Он разделяет ответственность: код отвечает за логику, а внешние файлы — за контент. Для экспериментов попробуйте:
1. Создать один JSON-файл анимаций для всех персонажей игры.
2. Применить одну и ту же анимацию (например, 'idle') к спрайтам из разных атласов, если имена кадров в них совпадают.
3. Динамически загружать разные JSON-файлы с анимациями для разных уровней игры.
