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

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

Версия 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('bg', 'assets/pics/uv-grid-diag.png');
        this.load.image('block', 'assets/sprites/block.png');
    }

    create () 
    {
        this.cameras.main.setBounds(0, 0, 1024 * 2, 1024 * 2);

        this.add.image(0, 0, 'bg').setOrigin(0);
        this.add.image(1024, 0, 'bg').setOrigin(0);
        this.add.image(0, 1024, 'bg').setOrigin(0);
        this.add.image(1024, 1024, 'bg').setOrigin(0);
    
        this.cursors = this.input.keyboard.createCursorKeys();
        this.keys = this.input.keyboard.addKeys('W,A,S,D');
    
        // this.cameras.main.originX = 1;
        this.cameras.main.centerToBounds();
    
        this.text = this.add.text(32, 32).setScrollFactor(0).setFontSize(32).setColor('#ffffff');
    }

    update () 
    {
        const cam = this.cameras.main;

        this.text.setText([
            'ScrollX: ' + cam.scrollX,
            'ScrollY: ' + cam.scrollY,
            'MidX: ' + cam.midPoint.x,
            'MidY: ' + cam.midPoint.y
        ]);
    
        if (this.keys.A.isDown)
        {
            cam.scrollX -= 6;
        }
        else if (this.keys.D.isDown)
        {
            cam.scrollX += 6;
        }
    
        if (this.keys.W.isDown)
        {
            cam.scrollY -= 6;
        }
        else if (this.keys.S.isDown)
        {
            cam.scrollY += 6;
        }
    
        if (this.cursors.left.isDown)
        {
            cam.rotation -= 0.01;
        }
        else if (this.cursors.right.isDown)
        {
            cam.rotation += 0.01;
        }
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
    },
    scene: Example
};
const game = new Phaser.Game(config);

Настройка сцены и загрузка ресурсов

В методе preload мы загружаем два изображения: фон (uv-grid-diag.png) и спрайт блока. Обратите внимание, что базовый URL задается через this.load.setBaseURL, что удобно для примеров с внешними ресурсами.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/pics/uv-grid-diag.png');
    this.load.image('block', 'assets/sprites/block.png');
}

В методе create первым делом расширяем границы основной камеры this.cameras.main.setBounds. Это определяет область, по которой камера может перемещаться. Мы задаем её в четыре раза больше (по площади), чем один фон 1024x1024.

this.cameras.main.setBounds(0, 0, 1024 * 2, 1024 * 2);

Затем мы размещаем четыре фоновых изображения в виде сетки 2x2, чтобы заполнить эту большую область.

this.add.image(0, 0, 'bg').setOrigin(0);
this.add.image(1024, 0, 'bg').setOrigin(0);
this.add.image(0, 1024, 'bg').setOrigin(0);
this.add.image(1024, 1024, 'bg').setOrigin(0);

Управление с клавиатуры и начальная позиция камеры

Для управления нам понадобятся клавиши. Создаем две группы:
- `this.cursors` для стрелок (по умолчанию в Phaser).
- `this.keys` для клавиш WASD, созданные через `this.input.keyboard.addKeys`.
this.cursors = this.input.keyboard.createCursorKeys();
this.keys = this.input.keyboard.addKeys('W,A,S,D');

Важный шаг — вызов this.cameras.main.centerToBounds(). Этот метод мгновенно позиционирует камеру так, чтобы её центр находился в центре заданных границ (bounds). Это удобно для старта в середине большой игровой области.

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

this.text = this.add.text(32, 32).setScrollFactor(0).setFontSize(32).setColor('#ffffff');

Логика обновления: движение и вращение

Вся магия происходит в методе update. Для удобства создаем ссылку cam на основную камеру.

Сначала мы обновляем текст, выводя текущие свойства камеры: scrollX, scrollY (смещение камеры) и координаты её средней точки (midPoint).

const cam = this.cameras.main;

this.text.setText([
    'ScrollX: ' + cam.scrollX,
    'ScrollY: ' + cam.scrollY,
    'MidX: ' + cam.midPoint.x,
    'MidY: ' + cam.midPoint.y
]);

Затем обрабатываем ввод. Клавиши A и D изменяют свойство cam.scrollX, что приводит к горизонтальной прокрутке камеры. Аналогично W и S управляют cam.scrollY для вертикальной прокрутки.

if (this.keys.A.isDown)
{
    cam.scrollX -= 6;
}
else if (this.keys.D.isDown)
{
    cam.scrollX += 6;
}

if (this.keys.W.isDown)
{
    cam.scrollY -= 6;
}
else if (this.keys.S.isDown)
{
    cam.scrollY += 6;
}

Стрелки влево и вправо управляют ключевым свойством — cam.rotation. Его изменение приводит к вращению всего видового порта камеры вокруг её текущей точки обзора.

if (this.cursors.left.isDown)
{
    cam.rotation -= 0.01;
}
else if (this.cursors.right.isDown)
{
    cam.rotation += 0.01;
}

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

Код завершается стандартной конфигурацией игры Phaser. Обратите внимание, что в config включен physics плагин Arcade, хотя в данном примере он не используется. Основная камера создается автоматически и доступна как this.cameras.main.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    physics: {
        default: 'arcade',
    },
    scene: Example
};
const game = new Phaser.Game(config);

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

Вращение камеры в Phaser 3 сводится к изменению одного свойства rotation у объекта камеры. Этот пример демонстрирует базовый паттерн: настройка границ, позиционирование и обработка ввода для управления scrollX, scrollY и rotation. Для экспериментов попробуйте: изменить скорость вращения, привязать вращение к движению персонажа, использовать cam.zoom вместе с вращением для создания эффекта "закручивания", или анимировать свойство rotation через Tween для плавных переходов между локациями.