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

Работа с отдельными изображениями для каждого спрайта быстро приводит к падению производительности из-за множества HTTP-запросов и переключений текстур. Атласы, созданные в Texture Packer, решают эту проблему, объединяя множество спрайтов в один файл изображения с JSON-описанием координат. Этот пример показывает, как просто загрузить и использовать такой атлас в Phaser 3, чтобы ваша игра работала плавно и эффективно.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    disk;
    atari;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.path = 'assets/atlas/';

        this.load.atlas('sprites', 'tp3test.png', 'tp3test.json');
    }

    create ()
    {
        //  Include .png until 'Trim filenames' works

        //  This one has a custom pivot point:
        this.atari = this.add.image(150, 100, 'sprites', 'atari130xe.png');

        //  Default pivot point
        this.add.image(200, 300, 'sprites', 'elephant.png');
        this.add.image(500, 200, 'sprites', 'exocet_spaceman.png');

        //  This one has a custom pivot point:
        this.disk = this.add.image(300, 300, 'sprites', 'copy-that-floppy.png');
    }

    update ()
    {
        this.atari.rotation += 0.01;
        this.disk.rotation += 0.01;
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка: загрузка атласа в preload()

Метод preload() предназначен для предварительной загрузки всех необходимых ресурсов до начала игры. Для работы с атласом Texture Packer используется метод this.load.atlas().

Обратите внимание на настройку базового пути. Метод this.load.setBaseURL() задаёт корневой URL для всех последующих загрузок, а this.load.path добавляет к нему конкретную папку с ассетами. Это удобно для организации файлов.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.path = 'assets/atlas/';

    this.load.atlas('sprites', 'tp3test.png', 'tp3test.json');
}

Метод this.load.atlas() принимает три ключевых аргумента: 1. 'sprites' — внутренний ключ (key), по которому атлас будет доступен в коде. 2. 'tp3test.png' — путь к файлу изображения, содержащему все спрайты. 3. 'tp3test.json' — путь к JSON-файлу с данными о координатах каждого фрейма внутри PNG-файла. Phaser автоматически парсит этот файл.

Создание спрайтов из атласа в create()

После успешной загрузки в методе create() мы можем создавать игровые объекты, используя загруженный атлас. Для этого применяется знакомый метод this.add.image(), но с дополнительным параметром.

create ()
{
    //  This one has a custom pivot point:
    this.atari = this.add.image(150, 100, 'sprites', 'atari130xe.png');

    //  Default pivot point
    this.add.image(200, 300, 'sprites', 'elephant.png');
    this.add.image(500, 200, 'sprites', 'exocet_spaceman.png');

    //  This one has a custom pivot point:
    this.disk = this.add.image(300, 300, 'sprites', 'copy-that-floppy.png');
}

Обратите внимание на сигнатуру метода. Первые два аргумента — это координаты X и Y. Третий аргумент — ключ атласа ('sprites'), который мы задали при загрузке. Четвёртый, ключевой аргумент — это имя конкретного фрейма внутри атласа. Phaser ищет это имя в загруженном JSON-описании, находит координаты прямоугольника (frame) в PNG-файле и создаёт из него изображение.

В комментариях указано, что некоторые фреймы (например, 'atari130xe.png') имеют кастомную точку вращения (pivot). Эта настройка задаётся не в коде Phaser, а в самом Texture Packer при создании атласа и сохраняется в JSON-файле. Phaser автоматически читает и применяет эти данные.

Анимация и управление объектами в update()

Метод update() вызывается на каждом кадре игры. Здесь мы можем обновлять состояние наших объектов. В примере объекты, сохранённые в переменные this.atari и this.disk, плавно вращаются.

update ()
{
    this.atari.rotation += 0.01;
    this.disk.rotation += 0.01;
}

Здесь важно понимать, что this.atari и this.disk — это обычные экземпляры Phaser.GameObjects.Image. После создания из атласа с ними можно работать как с любыми другими игровыми объектами в Phaser: перемещать, вращать, масштабировать, менять прозрачность. Факт того, что их текстура взята из общего атласа, абсолютно не влияет на логику их поведения в сцене.

Конфигурация игры и запуск

Это стандартная конфигурация игры Phaser 3. В свойстве scene указывается наш класс Example, который содержит всю логику загрузки и отображения атласа.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

После создания экземпляра Phaser.Game с этой конфигурацией автоматически запустится жизненный цикл сцены: preload(), create(), а затем многократно update().

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

Использование атласов Texture Packer в Phaser — это обязательный шаг для оптимизации любой серьёзной игры. Процесс загрузки через this.load.atlas() и создания объектов интуитивно понятен и практически не отличается от работы с одиночными текстурами. Для экспериментов попробуйте

  1. создать свой атлас в бесплатной версии Texture Packer
  2. анимировать другие свойства спрайтов (например, scale или alpha)
  3. использовать фреймы атласа не только для статичных изображений, но и для создания анимационных спрайтов через this.anims.create()