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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    smallCamera;
    controls;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('tiles', 'assets/tilemaps/tiles/dangerous-kiss-x2.png');
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/dangerous-kiss.json');
    }

    create ()
    {
        const map = this.make.tilemap({ key: 'map' });

        // The map was created with 8x8 tiles, but we want to load it with a 2x high resolution tileset
        map.setBaseTileSize(16, 16);
        const tileset = map.addTilesetImage('DangerousKiss_bank.png', 'tiles', 16, 16);

        const layer = map.createLayer('ShoeBox Tile Grab', tileset, 0, 0);

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

        this.smallCamera = this.cameras.add(800 - 320, 20, 300, 300);
        this.smallCamera.rotation = 0.2;
        this.smallCamera.zoom = 0.5;
        this.smallCamera.setBackgroundColor('rgba(0, 0, 0, 1)');

        const controlConfig = {
            camera: this.smallCamera,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            acceleration: 0.04,
            drag: 0.0005,
            maxSpeed: 0.7
        };

        this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);

        this.smallCamera.setBounds(0, 0, layer.width, layer.height);

    }

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

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    pixelArt: true,
    scene: Example
};

const game = new Phaser.Game(config);

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

Класс сцены Example расширяет Phaser.Scene. В нем объявляются две переменные для хранения ссылок на вторую камеру и ее контроллер.

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

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('tiles', 'assets/tilemaps/tiles/dangerous-kiss-x2.png');
    this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/dangerous-kiss.json');
}

Создание тайловой карты и основной сцены

В методе create происходит основная инициализация. Сначала создается объект тайловой карты (Tilemap) из загруженных данных.

Ключевой момент: исходная карта была создана с тайлами 8x8 пикселей, но загружается тайлсет с удвоенным разрешением (16x16). Метод setBaseTileSize(16, 16) сообщает движку о новом размере базового тайла для корректного отображения.

Затем тайлсет добавляется на карту, и создается слой для отрисовки.

const map = this.make.tilemap({ key: 'map' });
map.setBaseTileSize(16, 16);
const tileset = map.addTilesetImage('DangerousKiss_bank.png', 'tiles', 16, 16);
const layer = map.createLayer('ShoeBox Tile Grab', tileset, 0, 0);

Добавление и настройка второй камеры

Основная камера в Phaser создается по умолчанию и охватывает весь холст. Мы создаем вторую, дополнительную камеру с помощью метода this.cameras.add. Ее параметры — координаты X, Y, ширина и высота области просмотра на экране.

Созданная камера smallCamera позиционируется в правом верхнем углу. Ей задается небольшой поворот (rotation), уменьшенный масштаб (zoom) и черный фон для визуального отделения от основной сцены.

this.smallCamera = this.cameras.add(800 - 320, 20, 300, 300);
this.smallCamera.rotation = 0.2;
this.smallCamera.zoom = 0.5;
this.smallCamera.setBackgroundColor('rgba(0, 0, 0, 1)');

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

this.smallCamera.setBounds(0, 0, layer.width, layer.height);

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

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

Сначала создается объект конфигурации controlConfig. В него передается ссылка на управляемую камеру (smallCamera), привязка к клавишам-стрелкам (из cursors), а также параметры ускорения, торможения и максимальной скорости.

const controlConfig = {
    camera: this.smallCamera,
    left: cursors.left,
    right: cursors.right,
    up: cursors.up,
    down: cursors.down,
    acceleration: 0.04,
    drag: 0.0005,
    maxSpeed: 0.7
};

this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);

Созданный контроллер необходимо обновлять каждый кадр в методе update, передавая ему дельту времени.

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

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

Инициализация игры происходит стандартно. В конфигурационном объекте важно установить флаг pixelArt: true. Это отключает линейную интерполяцию текстур при масштабировании, что сохраняет четкость пиксельной графики, особенно при уменьшении масштаба во второй камере (zoom: 0.5).

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    pixelArt: true,
    scene: Example
};

const game = new Phaser.Game(config);

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

Использование нескольких камер открывает большие возможности для геймдизайна. Вы можете не только создавать мини-карты, но и реализовывать split-screen для мультиплеера, кат-сцены с разными ракурсами или UI-элементы, привязанные к миру игры. Для экспериментов попробуйте: связать положение мини-камеры с главным героем, добавить на нее статические маркеры объектов, изменить режим смешивания (setBlendMode) для эффекта подсветки или использовать ее как прицел для снайперской винтовки.