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

В Phaser 3 можно создавать гибридные интерфейсы, совмещающие игровые объекты и обычные HTML-элементы. Это открывает возможности для создания сложных UI, панелей управления или эффектов, которые сложно реализовать на чистых спрайтах. В этом примере мы покажем, как добавить HTML-элемент (`<div>`) в игровую сцену, поместить его в контейнер и применить к нему плавную анимацию средствами движка. Этот подход особенно полезен, когда вам нужно отобразить динамический текст, сложную вёрстку или элементы форм прямо внутри игры, сохраняя при этом все преимущества анимации и физики 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.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: element,
            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);

Настройка проекта и загрузка

Класс сцены Example расширяет Phaser.Scene. В методе preload мы устанавливаем базовый URL для загрузки ассетов и загружаем одно изображение. Обратите внимание, что для работы с DOM-элементами конфигурация игры должна включать специальный параметр.

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');
    }

Ключевая конфигурация: Включение DOM

Чтобы использовать DOM-элементы внутри Phaser, необходимо явно разрешить их создание в главной конфигурации игры. Это делается через свойство dom. Без этой настройки вызов this.add.dom() не сработает.

const config = {
    // ... другие настройки ...
    dom: {
        createContainer: true
    },
    scene: Example
};

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

В методе create мы создаём контейнер в точке (400, 300). Контейнеры в Phaser используются для группировки объектов. Затем создаётся DOM-элемент — div с жёлтым полупрозрачным фоном, размерами и текстом 'Phaser 3'. Важно, что его начальные координаты (0,0) заданы относительно контейнера. Также добавляется фиолетовый прямоугольник-маркер для визуализации центра.

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);
}

Анимация DOM-элемента через Tween

Самый интересный момент: DOM-элемент, будучи добавленным в контейнер, становится полноценным объектом для системы анимаций Phaser. Мы создаём твин, который циклически вращает элемент на 360 градусов и масштабирует его. Свойства angle, scaleX, scaleY применяются к элементу так же, как и к спрайту. Параметр yoyo: true заставляет анимацию проигрываться в обратном порядке.

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

Почему это работает?

Phaser создаёт для DOM-элемента специальный объект-обёртку, который интегрируется в его внутреннее дерево отображения. Когда элемент добавляется в контейнер (container.add(element)), он наследует его трансформации (положение, масштаб, угол). Твин-система движка управляет свойствами этой обёртки, а Phaser синхронизирует их с реальным HTML-элементом на странице, применяя CSS-трансформации. Именно поэтому мы можем использовать знакомые методы вроде this.tweens.add.

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

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

  1. добавить в div поле ввода или кнопку и обрабатывать события
  2. привязать анимацию к физическому телу
  3. создать сложный UI-контейнер из нескольких вложенных DOM-элементов и анимировать их вместе