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

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

Версия 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('einstein', 'assets/pics/ra-einstein.png');
    }

    create () 
    {
        const image = this.add.image(400, 300, 'einstein');

        this.UIText1 = this.add.text(0, 32, '0');
        this.UIText2 = this.add.text(0, 64, '0');
    
        //  Add in a new camera, the same size and position as the main camera
        const UICam = this.cameras.add(0, 0, 800, 600);
    
        //  The main camera will not render the UI Text objects
        this.cameras.main.ignore([ this.UIText1, this.UIText2 ]);
    
        //  The new UI Camera will not render the background image
        UICam.ignore(image);
    }

    update () 
    {
        this.UIText1.setText("Main camera rotation: " + this.cameras.main.rotation);
        this.UIText2.setText("Main camera zoom: " + this.cameras.main.zoom);
    
        this.cameras.main.setZoom(Math.abs(Math.sin(this.cameras.main.rotation)) * 0.5 + 1);
        this.cameras.main.rotation += 0.01;
    }
}

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

const game = new Phaser.Game(config);

Суть метода `camera.ignore`

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

В основном, вы управляете двумя списками: что видит основная камера (this.cameras.main) и что видит ваша пользовательская камера.

Настройка сцены и создание объектов

В методе preload загружается изображение, а в create создаются все необходимые объекты: фон, текстовые поля и вторая камера.

const image = this.add.image(400, 300, 'einstein');

this.UIText1 = this.add.text(0, 32, '0');
this.UIText2 = this.add.text(0, 64, '0');

Эти объекты изначально добавлены в мир и будут отображаться всеми камерами по умолчанию.

Создание UI-камеры и применение ignore

Следующий шаг — создать дополнительную камеру. Она будет отвечать за отображение интерфейса. Важно, что ее размер и положение совпадают с основной камерой, чтобы координаты объектов UI оставались предсказуемыми.

const UICam = this.cameras.add(0, 0, 800, 600);

Теперь применяется метод ignore. Основная камера перестает видеть текстовые поля, а UI-камера — фоновое изображение.

this.cameras.main.ignore([ this.UIText1, this.UIText2 ]);
UICam.ignore(image);

В результате вращение и зум основной камеры не затронут текст, а статичная UI-камера всегда будет показывать текст четко и ровно.

Динамическое обновление и визуальный эффект

В методе update каждый кадр обновляется текст, отображающий параметры основной камеры, и сами эти параметры меняются.

this.UIText1.setText("Main camera rotation: " + this.cameras.main.rotation);
this.UIText2.setText("Main camera zoom: " + this.cameras.main.zoom);

this.cameras.main.setZoom(Math.abs(Math.sin(this.cameras.main.rotation)) * 0.5 + 1);
this.cameras.main.rotation += 0.01;

Хотя текст физически находится в одной сцене с фоном, он не подвержен этим трансформациям, потому что его рендерит другая камера (UICam). Это наглядно демонстрирует мощь разделения.

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

Использование метода ignore для камер — это чистый и производительный способ разделить игровой мир и интерфейс. Для экспериментов попробуйте: добавить больше UI-элементов (кнопки, шкалы здоровья) в список игнорируемых для основной камеры; создать несколько камер для разных слоев UI (например, отдельно для HUD и меню паузы); или анимировать саму UI-камеру для эффектов встряски экрана, которые не затронут геймплей.