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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
    }

    create ()
    {
        //  Create a stack of random cards

        const frames = this.textures.get('cards').getFrameNames();

        let x = 0;
        let y = 0;

        for (let i = 0; i < 64; i++)
        {
            this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setInteractive();

            x += 4;
            y += 4;
        }

        //  Shrink the main camera
        this.cameras.main.setSize(511, 299).setZoom(0.5).setBackgroundColor('#000000');

        //  3 more cams
        this.cameras.add(513, 0, 511, 299).setZoom(0.5).setBackgroundColor('#0000aa');
        this.cameras.add(0, 301, 511, 299).setZoom(0.5).setBackgroundColor('#00aa00');
        this.cameras.add(513, 301, 511, 299).setZoom(0.5).setBackgroundColor('#aa0000').setRotation(0.8);

        this.input.on('gameobjectdown', function (pointer, gameObject)
        {

            //  Will contain the top-most Game Object (in the display list)
            this.tweens.add({
                targets: gameObject,
                x: { value: 1100, duration: 1500, ease: 'Power2' },
                y: { value: 500, duration: 500, ease: 'Bounce.easeOut', delay: 150 }
            });

        }, this);
    }
}

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

const game = new Phaser.Game(config);

Подготовка ассетов и создание интерактивных карт

В методе preload мы загружаем атлас спрайтов — текстуру, содержащую все кадры (карты) и JSON-файл с их описанием. Это эффективный способ работы с множеством мелких изображений.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');

В create мы сначала получаем массив имён всех кадров из загруженного атласа. Затем в цикле создаём 64 карты, располагая их со смещением, чтобы образовалась стопка. Каждая карта создаётся с помощью this.add.image и сразу же делается интерактивной вызовом .setInteractive(). Это необходимо для обработки событий ввода, таких как клик.

const frames = this.textures.get('cards').getFrameNames();
let x = 0;
let y = 0;
for (let i = 0; i < 64; i++)
{
    this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setInteractive();
    x += 4;
    y += 4;
}

Настройка основной и дополнительных камер

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

this.cameras.main.setSize(511, 299).setZoom(0.5).setBackgroundColor('#000000');

Метод this.cameras.add создаёт новую камеру. Его параметры — это координаты X, Y и размеры области просмотра (viewport) на экране. Создаются три дополнительные камеры. Они также масштабируются, получают фоновый цвет, а одна из них — красная — дополнительно поворачивается.

this.cameras.add(513, 0, 511, 299).setZoom(0.5).setBackgroundColor('#0000aa');
this.cameras.add(0, 301, 511, 299).setZoom(0.5).setBackgroundColor('#00aa00');
this.cameras.add(513, 301, 511, 299).setZoom(0.5).setBackgroundColor('#aa0000').setRotation(0.8);

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

Обработка кликов в условиях нескольких камер

Несмотря на наличие четырёх камер, система ввода Phaser работает глобально. Событие gameobjectdown сработает при клике на любой интерактивный объект, независимо от того, через какую камеру он виден в данный момент. В обработчике события pointer содержит информацию о точке взаимодействия, а gameObject — ссылку на кликнутую карту.

this.input.on('gameobjectdown', function (pointer, gameObject)
{
    // gameObject — это кликнутая карта
}, this);

Внутри обработчика запускается твин (анимация) для перемещения карты. Анимация составная: по оси X карта плавно уезжает за пределы экрана, а по оси Y — подпрыгивает с эффектом отскока (Bounce.easeOut) после небольшой задержки.

this.tweens.add({
    targets: gameObject,
    x: { value: 1100, duration: 1500, ease: 'Power2' },
    y: { value: 500, duration: 500, ease: 'Bounce.easeOut', delay: 150 }
});

Поскольку все камеры смотрят на одну сцену, анимированное движение карты будет видно во всех четырёх областях просмотра одновременно, что наглядно демонстрирует их общую природу.

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

Использование нескольких камер открывает широкие возможности для геймдизайна. Вы можете создать локальный кооператив на одном экране, реализовать сложную систему наблюдения или динамически менять ракурс в стратегических играх. Для экспериментов попробуйте: назначить разным камерам слежку за разными игровыми объектами с помощью cameras.startFollow; изменить порядок отрисовки камер, управляя их свойством depth; или обрабатывать ввод только в определённой камере, проверяя свойство pointer.camera в обработчике событий.