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

По умолчанию Phaser предоставляет одну основную камеру для отрисовки игрового мира. Но что, если вам нужен split-screen для многопользовательской игры, статичный интерфейс поверх основного мира или сложные эффекты с разными областями видимости? Решение — использование нескольких камер, которые можно легко настроить прямо в конфигурации сцены. Эта статья покажет, как декларативно создавать несколько камер с разными параметрами и управлять ими.

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

Живой запуск

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

Исходный код


// Scene configuration
const sceneConfig = {
    key: 'Example',
    cameras: [
        {
            width: 400,
            height: 300,
            backgroundColor: '#ff0000'
        },
        {
            x: 400,
            y: 0,
            width: 400,
            height: 300,
            backgroundColor: '#ff00ff'
        },
        {
            x: 0,
            y: 300,
            width: 400,
            height: 300,
            backgroundColor: '#ffff00'
        },
        {
            x: 400,
            y: 300,
            width: 400,
            height: 300,
            backgroundColor: '#00ff00'
        }
    ]
};

// Scene
class Example extends Phaser.Scene
{
    constructor ()
    {
        super(sceneConfig);
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('mech', 'assets/pics/titan-mech.png');
    }

    create ()
    {
        this.image = this.add.image(200, 150, 'mech');
    }

    update ()
    {
        this.image.rotation += 0.01;
    }
}

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

const game = new Phaser.Game(config);

Конфигурация камер через sceneConfig

В Phaser 3 камеры можно создавать не только через this.cameras.add в методе create сцены, но и на этапе её инициализации. Это делается через специальный объект конфигурации, который передаётся в конструктор родительского класса Phaser.Scene.

Ключевой параметр — массив cameras. Каждый его элемент — это объект с настройками для отдельной камеры. В этом примере создаётся четыре камеры, делящие окно игры на четыре равные части.

const sceneConfig = {
    key: 'Example',
    cameras: [
        {
            width: 400,
            height: 300,
            backgroundColor: '#ff0000'
        },
        // ... другие камеры
    ]
};

class Example extends Phaser.Scene
{
    constructor ()
    {
        super(sceneConfig); // Передаём конфиг в родительский конструктор
    }
}

При таком подходе камеры создаются автоматически до вызова метода preload. Свойство key в конфиге сцены является обязательным для её идентификации в Phaser.

Настройка положения, размера и фона

Каждая камера в массиве настраивается независимо. Основные параметры: - `x,y`: Положение *вида* (viewport) камеры на игровом холсте (рендерере). По умолчанию (0, 0). - width, height: Размеры *вида* камеры. - backgroundColor: Цвет фона, который будет заполнять область вида, если там нет игровых объектов.

В примере создаётся сетка 2x2. Первая камера (красный фон) занимает левый верхний квадрант (0,0, 400x300). Вторая (розовый) смещена по X на 400 пикселей и занимает правый верхний угол. Третья и четвёртая смещены по оси Y на 300 пикселей.

{
    x: 400,
    y: 0,
    width: 400,
    height: 300,
    backgroundColor: '#ff00ff'
}

Важно: эти параметры задают область отрисовки на *экране*, а не область видимости внутри игрового мира. По умолчанию все камеры смотрят на одну и ту же точку мира (0,0), но их можно перемещать независимо с помощью методов camera.scrollX и camera.scrollY.

Работа с камерами в сцене

После создания через конфиг камеры становятся доступны в свойстве this.cameras (объект CameraManager). Основная (первая созданная) камера также доступна через this.cameras.main. Все камеры хранятся в коллекции this.cameras.cameras.

В методе create нашего примера изображение добавляется в сцену через this.add.image. По умолчанию игровые объекты рендерятся на *все* камеры, у которых не отключён рендеринг. Поэтому механическая картинка появляется сразу в четырёх квадрантах экрана.

create ()
{
    // Этот объект будет отрисован на всех активных камерах
    this.image = this.add.image(200, 150, 'mech');
}

Метод update вращает это изображение, и анимация видна во всех четырёх видах одновременно, так как они показывают один и тот же игровой объект в мире.

Практическое применение и управление

Зачем это нужно? Представьте split-screen для гонок, где каждый игрок видит свою часть трассы, или статичный HUD в отдельной камере, который не двигается при скролле основного мира.

Вы можете точечно управлять рендерингом объектов на конкретных камерах. Вот как, например, сделать объект видимым только для первой камеры:

// В методе create, после создания объекта:
this.image.setVisible(false); // Сначала скрываем для всех
this.cameras.cameras[0].visible = true; // Включаем видимость для камеры с индексом 0
// ИЛИ через менеджер, если знаем ключ камеры (если он был задан в конфиге)
// this.cameras.getCamera('Camera1').visible = true;

Камеры можно перемещать по игровому миру независимо друг от друга, задавая им разные scrollX и scrollY. Это позволяет реализовать сложные динамические виды.

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

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

  1. Задать разный zoom для каждой камеры в конфиге
  2. В цикле в update двигать камеры с разной скоростью, создавая эффект параллакса
  3. Назначить разным игровым объектам разные камеры для отрисовки через setVisible