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

В играх с большими уровнями часто возникает необходимость ограничить движение камеры, чтобы она не выходила за пределы игрового мира. Phaser 3 предоставляет для этого простой и мощный инструмент — метод `setBounds`. Эта статья покажет, как задать границы для камеры, чтобы игрок мог исследовать только определённую область сцены, и как реализовать плавное управление камерой с клавиатуры. Этот приём незаменим для создания карт, больших задних планов или интерфейсов с прокруткой.

Версия 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.image('pic', 'assets/pics/lazur-skkaay3.png');
    }

    create ()
    {
        this.add.image(0, 200, 'pic').setOrigin(0);

        //  Set the camera bounds to be the size of the image
        //  In this case we can scroll horizontally, but not vertically
        this.cameras.main.setBounds(0, 0, 1280, 200);

        //  Camera controls
        const cursors = this.input.keyboard.createCursorKeys();

        const controlConfig = {
            camera: this.cameras.main,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            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.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    backgroundColor: '#000000',
    scene: Example
};

const game = new Phaser.Game(config);

Устанавливаем границы камеры

Основная задача — сообщить камере, за какие пределы она не должна выходить. В примере используется длинная панорамная картинка, и мы хотим, чтобы игрок мог прокручивать её только по горизонтали, а по вертикали камера оставалась фиксированной.

Для этого в методе create вызывается this.cameras.main.setBounds(). Этот метод главной камеры принимает четыре аргумента: координаты левого верхнего угла (X, Y) и размеры области (ширину и высоту).

this.cameras.main.setBounds(0, 0, 1280, 200);

В данном случае границы установлены от точки (0, 0) до точки (1280, 200). Это значит, что центр камеры не сможет выйти за эти пределы. Поскольку высота игрового окна (viewport) составляет 600 пикселей (как указано в конфиге), а граница по высоте — всего 200, вертикальный скроллинг становится невозможен. Камера будет свободно перемещаться только в пределах ширины изображения (1280 пикселей).

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

Чтобы игрок мог перемещать камеру в рамках установленных границ, нужно настроить управление. В примере для этого используется встроенный класс Phaser.Cameras.Controls.SmoothedKeyControl, который обеспечивает плавное, инерционное движение.

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

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

Затем формируется конфигурационный объект controlConfig. Ключевые параметры: * camera: целевая камера (главная). * left, right, up, down: кнопки управления. * acceleration: ускорение камеры при нажатии клавиши. * drag: «трение», которое замедляет камеру после отпускания клавиши. * maxSpeed: максимальная скорость перемещения.

const controlConfig = {
    camera: this.cameras.main,
    left: cursors.left,
    right: cursors.right,
    up: cursors.up,
    down: cursors.down,
    acceleration: 0.06,
    drag: 0.0005,
    maxSpeed: 1.0
};

После этого создаётся экземпляр контрола, который сохраняется в свойстве сцены this.controls для дальнейшего использования.

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

Класс SmoothedKeyControl требует, чтобы его метод update вызывался каждый кадр игры. Это необходимо для расчёта плавного движения с учётом ускорения и трения.

В методе update сцены вызывается this.controls.update(delta). Параметр delta — это время, прошедшее с предыдущего кадра в миллисекундах. Его передача обеспечивает независимость скорости движения камеры от частоты кадров (frame rate independent movement).

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

Именно на этом этапе контрол проверяет состояние клавиш, применяет физику движения и перемещает камеру, автоматически соблюдая установленные для неё границы (setBounds).

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

Весь функционал упакован в сцену Example. Чтобы игра запустилась, нужно создать конфигурационный объект и передать его в конструктор Phaser.Game.

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

const game = new Phaser.Game(config);

Важные параметры: * width и height: определяют размер viewport'а (окна отрисовки). Камера по умолчанию имеет такие же размеры. * scene: указывает класс сцены, которая будет запущена сразу после инициализации игры. Именно в этой сцене и работает весь наш код с камерой. * backgroundColor: задаёт чёрный фон вокруг изображения.

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

Комбинация cameras.main.setBounds() и SmoothedKeyControl — это основа для создания прокручиваемых областей в Phaser 3. Вы можете экспериментировать: задайте границы больше или меньше размеров viewport'а, отключите скроллинг по одной из осей (как в примере) или создайте несколько камер с разными границами для разделения экрана. Попробуйте привязать камеру не к статичным координатам, а к динамическим, чтобы границы перемещались вместе с игроком на огромной карте.