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

При создании игр с обширными уровнями или большим количеством спрайтов критически важна оптимизация производительности. Класс `Blitter` в Phaser 3 — это мощный инструмент для отрисовки тысяч спрайтов с минимальными затратами ресурсов, так как он использует один текстуру-атлас и метод пакетной отрисовки (batch rendering). В этой статье мы разберем, как создавать сетки из сотен объектов с помощью `Blitter` и реализовать плавное управление камерой с помощью встроенного контроллера `SmoothedKeyControl`. Этот подход идеально подходит для прототипирования карт, изометрических миров или сцен с большим количеством частиц.

Версия 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.spritesheet('bobs', 'assets/sprites/bobs-by-cleathley.png', { frameWidth: 32, frameHeight: 32 });
    }

    create ()
    {
        const blitter = this.add.blitter(0, 0, 'bobs');

        //  Create a load of bobs aligned in a grid
        for (let y = 0; y < 30; y++)
        {
            for (let x = 0; x < 30; x++)
            {
                blitter.create(x * 32, y * 32, Phaser.Math.Between(0, 399));
            }
        }

        const cursors = this.input.keyboard.createCursorKeys();

        const controlConfig = {
            camera: this.cameras.main,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
            zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
            acceleration: 0.06,
            drag: 0.0005,
            maxSpeed: 1.0
        };

        this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
    }

    update (time, delta)
    {
        this.controls.update(delta);
    }
}

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

const game = new Phaser.Game(config);

Оптимизация через Blitter

Основная задача Blitter — эффективное отображение множества спрайтов из одного набора кадров (spritesheet). Вместо создания сотен отдельных игровых объектов (Sprite), которые нагружают систему, Blitter работает как конвейер, рисуя множество копий (бобов) из одного источника.

В методе preload загружается спрайтшит, содержащий 400 отдельных кадров (по 32x32 пикселя).

this.load.spritesheet('bobs', 'assets/sprites/bobs-by-cleathley.png', { frameWidth: 32, frameHeight: 32 });

В create создается один объект Blitter, который будет отвечать за отрисовку всех элементов.

const blitter = this.add.blitter(0, 0, 'bobs');

Создание сетки объектов

Для заполнения сцены используется двойной цикл, который создает 30x30 (900) бобов, располагая их в сетку. Ключевой метод — blitter.create(x, y, frame).

* **x, y**: Координаты для отрисовки данного боба на экране. * **frame**: Индекс кадра из загруженного спрайтшита. Phaser.Math.Between(0, 399) случайным образом выбирает один из 400 доступных кадров для каждого боба, создавая визуальное разнообразие.

for (let y = 0; y < 30; y++) {
    for (let x = 0; x < 30; x++) {
        blitter.create(x * 32, y * 32, Phaser.Math.Between(0, 399));
    }
}

В результате мы получаем поле размером 960x960 пикселей, состоящее из 900 спрайтов, но с высокой производительностью.

Настройка плавного управления камерой

Чтобы исследовать созданный большой мир, нужна камера, которой можно управлять. Phaser предоставляет готовый контроллер SmoothedKeyControl для реализации плавного, инерционного движения камеры с клавиатуры.

Сначала создаются объекты для отслеживания нажатий стрелок.

const cursors = this.input.keyboard.createCursorKeys();

Затем настраивается конфигурационный объект для контроллера. В нем указывается камера (this.cameras.main), привязка клавиш для движения и зума, а также параметры физики движения: ускорение, сопротивление (drag) и максимальная скорость.

const controlConfig = {
    camera: this.cameras.main,
    left: cursors.left,
    right: cursors.right,
    up: cursors.up,
    down: cursors.down,
    zoomIn: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.Q),
    zoomOut: this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.E),
    acceleration: 0.06,
    drag: 0.0005,
    maxSpeed: 1.0
};

this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);

Обновление состояния контроллера

Контроллер SmoothedKeyControl не обновляется автоматически. Необходимо вручную вызывать его метод update в каждом кадре игрового цикла, передавая дельту времени (delta). Это позволяет контроллеру корректно рассчитать плавное движение и инерцию, независимо от частоты кадров.

update (time, delta) {
    this.controls.update(delta);
}

Без этого вызова камера не будет реагировать на нажатия клавиш.

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

Комбинация Blitter для эффективного рендеринга и SmoothedKeyControl для навигации — это мощный дуэт для создания прототипов больших игровых миров в Phaser 3. Вы получаете основу для тайловых карт, систем частиц или стратегий с видом сверху без падения производительности. Для экспериментов попробуйте: изменить логику создания бобов на лету в ответ на клики мыши; использовать другой контроллер, например, FixedKeyControl, для мгновенного перемещения камеры; или привязать зум камеры к колесику мыши, переопределив методы обработки ввода.