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

Phaser 3 позволяет интегрировать обычные HTML-элементы прямо в игровое пространство, используя DOM Container. Это открывает уникальные возможности: вы можете добавить сложный текстовый контент, веб-формы или даже целые интерфейсные библиотеки прямо в свою игру, сохраняя при этом все преимущества трансформаций и анимаций Phaser. В этой статье мы разберем, как создать и анимировать DOM-элемент как часть игрового объекта, используя контейнеры и твины.

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

    create ()
    {
        const container = this.add.container(400, 300);

        const element = this.add.dom(0, 0, 'div', 'background-color: rgba(255, 255, 0, 0.5); width: 300px; height: 200px; font: 48px Arial; font-weight: bold', 'Phaser 3');

        const marker = this.add.rectangle(400, 300, 16, 16, 0xff00ff);

        container.add(element);

        this.tweens.add({
            targets: container,
            duration: 3000,
            angle: 360,
            scaleX: 2,
            scaleY: 2,
            ease: 'Sine.easeInOut',
            loop: -1,
            yoyo: true
        });
    }
}

const config = {
    type: Phaser.AUTO,
    scale: {
        _mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        width: 800,
        height: 600
    },
    dom: {
        createContainer: true
    },
    scene: Example
};

const game = new Phaser.Game(config);

Настройка конфигурации и загрузка

Для работы с DOM-элементами в Phaser 3 необходимо активировать соответствующую систему. Это делается в конфигурации игры. Кроме того, в методе preload мы загружаем стандартное изображение для визуального контекста, хотя в данном примере оно не используется.

const config = {
    type: Phaser.AUTO,
    scale: {
        _mode: Phaser.Scale.FIT,
        parent: 'phaser-example',
        width: 800,
        height: 600
    },
    dom: {
        createContainer: true // Ключевой параметр для активации DOM-системы
    },
    scene: Example
};
preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('einstein', 'assets/pics/ra-einstein.png');
}

Создание DOM-элемента и контейнера

В методе create происходит основная магия. Сначала создается this.add.container. Контейнер — это специальный игровой объект, который может группировать другие объекты, и все трансформации применяются к нему как к единому целому.

Затем создается сам DOM-элемент с помощью this.add.dom. Его ключевые параметры: позиция (0,0 относительно контейнера), тег ('div'), инлайн-стили и текстовое содержимое.

Маркер (marker) создается просто как визуальная точка отсчета в центре сцены.

create ()
{
    // Создаем контейнер в центре сцены
    const container = this.add.container(400, 300);

    // Создаем DOM-элемент (div) с желтым фоном, размерами и текстом
    const element = this.add.dom(0, 0, 'div', 'background-color: rgba(255, 255, 0, 0.5); width: 300px; height: 200px; font: 48px Arial; font-weight: bold', 'Phaser 3');

    // Создаем маркер-прямоугольник в центре сцены для наглядности
    const marker = this.add.rectangle(400, 300, 16, 16, 0xff00ff);

    // Добавляем DOM-элемент в контейнер
    container.add(element);
}

Анимация контейнера с твинами

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

this.tweens.add({
    targets: container, // Цель анимации — наш контейнер
    duration: 3000,     // Длительность анимации в миллисекундах
    angle: 360,         // Конечный угол поворота (полный оборот)
    scaleX: 2,          // Масштабирование по оси X
    scaleY: 2,          // Масштабирование по оси Y
    ease: 'Sine.easeInOut', // Функция плавности
    loop: -1,           // Бесконечный цикл (-1)
    yoyo: true          // Анимация проигрывается и в обратном направлении
});

Важные особенности и ограничения

Работа с DOM-элементами в Phaser имеет свою специфику.

1. **Производительность:** DOM-операции обычно медленнее, чем отрисовка на Canvas или WebGL. Активно анимируйте не сам DOM-узел, а контейнер Phaser, как в примере. 2. **Стилизация:** Стили задаются строкой, как в инлайн-стилях HTML. Для сложных стилей лучше создать CSS-класс и добавить его к элементу через element.node.classList.add('my-class'), где element.node — это ссылка на нативный DOM-узел. 3. **Взаимодействие:** К DOM-элементу можно добавить слушатели событий через element.addListener('click', ...). 4. **Позиционирование:** Исходная позиция this.add.dom(0, 0, ...) указывается относительно родительского контейнера или сцены. В нашем примере элемент помещен в контейнер, поэтому его позиция (0,0) — это позиция самого контейнера (400,300).

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

Интеграция DOM-элементов через this.add.dom и контейнеры — мощный инструмент для создания гибридных интерфейсов в Phaser 3. Вы можете встроить в игру сложные элементы управления, динамический текст с веб-шрифтами или виджеты. Для экспериментов попробуйте: заменить div на input или button, добавить обработчик клика на элемент, анимировать не контейнер, а CSS-свойства самого DOM-узла через твины, или создать сложный интерфейс меню, состоящий из нескольких вложенных DOM-объектов.