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

Оптимизация рендеринга — ключевой навык при разработке игр. Этот пример демонстрирует, как Phaser обрабатывает тысячи спрайтов, и знакомит с мощным методом `captureFrame` для отладки и создания скриншотов. Мы разберем, как организовать массовое создание объектов и в каких сценариях это полезно для тестирования производительности вашей игры.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        // this.load.setBaseURL('https://cdn.phaserfiles.com/v385');
        for (let i = 1; i <= 32; i++)
        {
            this.load.image(`pixel${i}`, `assets/tests/pixels/${i}.png`);
        }
    }

    create ()
    {
        let y = 0;
        let total = 0;

        this.input.on('pointerdown', (pointer) => {

            if (pointer.worldY >= 500)
            {
                console.log('Capture');

                this.game.renderer.captureFrame(false, true);
            }
            else
            {
                this.addSprites(y);
                y++;
                total += 1024;

                this.addSprites(y);
                y++;
                total += 1024;

                this.addSprites(y);
                y++;
                total += 1024;

                this.addSprites(y);
                y++;
                total += 1024;

                console.log('Total sprites:', total);
            }

        });
    }

    addSprites (y)
    {
        let color = 1;

        for (let x = 0; x < 1024; x++)
        {
            this.add.image(x, y, `pixel${color}`).setOrigin(0);

            // color++;

            if (color === 15)
            {
                color = 1;
            }
        }
    }
}

const config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 1024,
    height: 512,
    scene: Example
};

const game = new Phaser.Game(config);

Загрузка ресурсов: подготовка пикселей

В методе preload происходит загрузка 32 простейших изображений — цветных пикселей. Это типичный подход для тестов производительности, где важно исключить влияние размера и сложности текстур.

for (let i = 1; i <= 32; i++)
{
    this.load.image(`pixel${i}`, `assets/tests/pixels/${i}.png`);
}

Цикл динамически формирует ключи (pixel1, pixel2 и т.д.) и пути к файлам. Эти ключи позже используются для создания спрайтов.

Интерактивность и логика создания

Вся логика в методе create привязана к событию клика (pointerdown). В зависимости от координаты клика, код либо создает новую порцию спрайтов, либо делает снимок экрана.

this.input.on('pointerdown', (pointer) => {
    if (pointer.worldY >= 500)
    {
        console.log('Capture');
        this.game.renderer.captureFrame(false, true);
    }
    else
    {
        // Создание спрайтов...
    }
});

Условие pointer.worldY >= 500 проверяет, был ли клик в нижней части экрана (ниже 500 пикселей). Если да — вызывается captureFrame. В противном случае — запускается процесс добавления спрайтов.

Метод addSprites: заполняем экран

Метод addSprites(y) отвечает за создание одного ряда из 1024 спрайтов. Координата `y` задает вертикальную позицию ряда.

addSprites (y)
{
    let color = 1;
    for (let x = 0; x < 1024; x++)
    {
        this.add.image(x, y, `pixel${color}`).setOrigin(0);
        if (color === 15)
        {
            color = 1;
        }
    }
}

В цикле для каждой позиции `xсоздается изображение (this.add.image). Ключ текстуры формируется из строкиpixelи переменнойcolor. Метод.setOrigin(0)устанавливает точку привязки спрайта в его левый верхний угол, что позволяет точно выровнять пиксели в сетку. Переменнаяcolor` циклически меняется от 1 до 15, создавая разноцветный ряд.

Наращивание нагрузки и вывод статистики

При клике в верхней части экрана (else-ветка) четыре раза подряд вызывается addSprites, что быстро увеличивает общее количество объектов на сцене.

this.addSprites(y);
y++;
total += 1024;
// ... Повторяется 4 раза
console.log('Total sprites:', total);

Каждый вызов добавляет 1024 спрайта (один ряд). Переменные `yиtotal` обновляются, чтобы отслеживать текущую позицию и общее количество. Вывод в консоль позволяет наблюдать, как растет нагрузка на рендерер.

Захват состояния экрана: captureFrame

Клик в нижней части экрана (Y >= 500) вызывает мощный метод рендерера — this.game.renderer.captureFrame(false, true).

this.game.renderer.captureFrame(false, true);

Первый аргумент (false) указывает, что захватывать нужно не весь игровой мир, а только видимую область канваса. Второй аргумент (true) включает автоматическую загрузку полученного PNG-изображения браузером. Этот инструмент незаменим для отладки визуальных артефактов или создания скриншотов во время выполнения.

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

Этот пример — отличный полигон для экспериментов. Попробуйте изменить количество создаваемых за клик спрайтов, использовать другие текстуры или отключить функцию захвата, чтобы оценить чистую производительность рендеринга. Метод captureFrame можно интегрировать в систему отчетов об ошибках, автоматически сохраняя скриншот при возникновении редкого бага.