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

В динамичных играх часто нужно закрепить некоторые элементы интерфейса (например, здоровье, паузу или таймер) так, чтобы они всегда оставались на одном месте экрана, независимо от перемещения камеры. В Phaser для этого используется простой и мощный метод `setScrollFactor`. Эта статья покажет, как отделить фоновые объекты от элементов HUD, используя возможности камеры. Вы научитесь управлять поведением спрайтов при скроллинге и создадите основу для сложных игровых интерфейсов.

Версия 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('volcano', 'assets/pics/the-end-by-iloe-and-made.jpg');
        this.load.image('hotdog', 'assets/sprites/hotdog.png');
    }

    create ()
    {
        //  A background image - scrolls with the camera at a 1:1 ratio
        this.add.image(400, 300, 'volcano');

        //  A sprite, doesn't scroll with the camera (is fixed to camera)
        this.add.image(400, 300, 'hotdog').setScrollFactor(0);

        //  From here down is just camera controls and feedback
        var cursors = this.input.keyboard.createCursorKeys();

        var 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);

        var cam = this.cameras.main;

        const gui = new dat.GUI();

        var help = {
            line1: 'Cursors to move'
        }

        var f1 = gui.addFolder('Camera');
        f1.add(cam, 'x').listen();
        f1.add(cam, 'y').listen();
        f1.add(cam, 'scrollX').listen();
        f1.add(cam, 'scrollY').listen();
        f1.add(cam, 'rotation').min(0).step(0.01).listen();
        f1.add(help, 'line1');
        f1.open();
    }

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

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

В примере загружаются два изображения: фоновое изображение вулкана и спрайт хот-дога. Обратите внимание, что в методе preload используется setBaseURL, чтобы задать базовый путь для загрузки, что удобно для работы с внешними ресурсами.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('volcano', 'assets/pics/the-end-by-iloe-and-made.jpg');
    this.load.image('hotdog', 'assets/sprites/hotdog.png');
}

Создание объектов и настройка скроллинга

В методе create сначала добавляется фоновое изображение. По умолчанию в Phaser объекты движутся вместе с камерой, то есть имеют scrollFactor, равный 1.

//  A background image - scrolls with the camera at a 1:1 ratio
this.add.image(400, 300, 'volcano');

Затем добавляется спрайт хот-дога, но для него сразу вызывается метод setScrollFactor(0). Это ключевой момент: установка фактора прокрутки в 0 фиксирует объект относительно камеры. Теперь при движении камеры хот-дог будет оставаться на одном месте экрана.

//  A sprite, doesn't scroll with the camera (is fixed to camera)
this.add.image(400, 300, 'hotdog').setScrollFactor(0);

Управление камерой с плавным контролем

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

Конфигурация контрола передаёт ссылку на основную камеру this.cameras.main и привязывает управление к стрелкам клавиатуры. Параметры acceleration, drag и maxSpeed настраивают физику движения.

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

var 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 состояние контрола обновляется каждый кадр, обеспечивая движение камеры.

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

Визуализация параметров камеры

Для наглядности в примере используется библиотека dat.GUI, чтобы в реальном времени отображать параметры камеры. Это помогает понять, как изменяются её свойства при движении.

В интерфейс выводятся текущие координаты камеры (`x,y), значения смещения (scrollX,scrollY) и вращение (rotation). Обратите внимание, что для свойств, которые должны обновляться в реальном времени, вызывается метод.listen()`.

var cam = this.cameras.main;

const gui = new dat.GUI();

var help = {
    line1: 'Cursors to move'
}

var f1 = gui.addFolder('Camera');
f1.add(cam, 'x').listen();
f1.add(cam, 'y').listen();
f1.add(cam, 'scrollX').listen();
f1.add(cam, 'scrollY').listen();
f1.add(cam, 'rotation').min(0).step(0.01).listen();
f1.add(help, 'line1');
f1.open();

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

Метод setScrollFactor — это простой и эффективный способ разделить мир игры и её интерфейс. Фиксируя спрайты относительно камеры, вы создаёте стабильную область для отображения важной информации. Для экспериментов попробуйте задать спрайту setScrollFactor(0.5), чтобы он двигался с половинной скоростью относительно камеры, создавая эффект параллакса. Также можно применить этот подход к целым группам объектов или текстовым элементам для построения сложного HUD.