О чем этот пример

Загрузка анимаций из внешних JSON-файлов — это мощный подход к организации ресурсов в Phaser. Он позволяет отделить данные анимаций (кадры, частоту) от логики игры, что упрощает работу художникам и аниматорам. В этой статье разберем пример загрузки и воспроизведения нескольких анимаций из одного JSON-файла, что особенно полезно для проектов с большим количеством анимационных клипов.

Версия 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.animation('gemData', 'assets/animations/gems.json');
        this.load.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
    }

    create ()
    {
        this.add.text(400, 32, 'Animations from Animation JSON file', { color: '#00ff00' }).setOrigin(0.5, 0);

        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',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Зачем выносить анимации в JSON?

Встроенное создание анимаций через this.anims.create() прямо в коде сцены подходит для прототипов. Однако для production-проектов такой подход становится громоздким. Храня определения анимаций в JSON, вы достигаете нескольких целей:

* **Разделение ответственности:** Аниматоры могут редактировать файлы данных, не касаясь кода. * **Упрощение обновлений:** Можно заменить один файл, чтобы обновить все анимации объекта. * **Динамическая загрузка:** Загружайте пакеты анимаций по мере необходимости, экономя первоначальный объем загрузки.

Пример в статье демонстрирует базовый, но эффективный паттерн для работы с таким подходом.

Загрузка данных анимации и текстурного атласа

Вся подготовка происходит в методе preload(). Ключевой момент — загрузка двух связанных ресурсов: файла с данными анимаций и самого атласа спрайтов, на который эти данные ссылаются.

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');
}
*   `this.load.animation()` загружает JSON-файл и автоматически регистрирует все анимации, описанные в нем, в глобальный менеджер анимаций (`this.anims`). Первый параметр — произвольный ключ, второй — путь к данным.
*   `this.load.atlas()` загружает изображение-атлас (`gems.png`) и файл с координатами кадров внутри него (`gems.json`). Ключ `'gems'` будет использоваться для создания спрайтов.

Важно, что файлы gems.json (для атласа) и gems.json (для анимаций) — это разные файлы, хотя и имеют схожие имена в этом примере.

Создание спрайтов и запуск анимаций

После загрузки в методе create() анимации уже доступны в системе. Нам остается только создать спрайты из загруженного атласа и проиграть на них нужные клипы.

create ()
{
    this.add.text(400, 32, 'Animations from Animation JSON file', { color: '#00ff00' }).setOrigin(0.5, 0);

    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');
}

* Каждый вызов this.add.sprite() создает новый спрайт, использующий текстуру с ключом 'gems'. * Метод .play() сразу запускает анимацию. Имена анимаций ('diamond', 'prism' и т.д.) должны точно соответствовать тем, что объявлены в загруженном JSON-файле. Phaser сам находит созданную ранее анимацию по этому имени и применяет ее к спрайту.

Структура JSON-файла с анимациями

Чтобы данный пример работал, файл gems.json (с данными анимации) должен иметь специфическую структуру, понятную загрузчику Phaser. Вот примерный вид такого файла:

{
    "anims": [
        {
            "key": "diamond",
            "frames": [
                { "key": "gems", "frame": "diamond_01" },
                { "key": "gems", "frame": "diamond_02" }
            ],
            "frameRate": 8,
            "repeat": -1
        },
        {
            "key": "prism",
            "frames": [ { "key": "gems", "frame": "prism_01" } ],
            "frameRate": 1
        }
    ]
}

* key: Уникальное имя анимации, используемое в методе .play(). * frames: Массив объектов, каждый из которых ссылается на key атласа и frame — имя конкретного кадра внутри атласа (эти имена определены в gems.json атласа). * frameRate: Скорость воспроизведения. * repeat: Количество повторений (-1 для бесконечного цикла).

Именно в этом формате Phaser ожидает получить данные от this.load.animation().

Что попробовать дальше

Использование внешних JSON-файлов для анимаций делает код чище, а процесс разработки — гибче. Для экспериментов попробуйте: 1. Изменить частоту кадров (frameRate) или порядок кадров в JSON-файле и увидеть, как это мгновенно отразится в игре без перезаписи кода. 2. Загружать разные JSON-файлы с анимациями для разных уровней или персонажей по требованию. 3. Скомбинировать этот подход с созданием анимаций в коде для особых, динамически генерируемых эффектов.