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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    element;

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('einstein', 'assets/pics/ra-einstein.png');
    }

    create ()
    {
        const div = document.createElement('div');
        div.style = 'background-color: lime; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
        div.innerText = 'Phaser 3';

        this.element = this.add.dom(400, 300, div);

        this.tweens.add({
            targets: this.element,
            skewX: 1.1,
            skewY: 0.4,
            duration: 3000,
            ease: 'Sine.easeInOut',
            loop: -1,
            yoyo: true
        });

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

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

const game = new Phaser.Game(config);

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

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

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    dom: {
        createContainer: true // Ключевая опция для активации DOM-системы
    },
    scene: Example
};

В методе preload() загружается фоновое изображение. Обратите внимание, что DOM-элемент не требует загрузки через this.load, так как создается динамически средствами браузера.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('einstein', 'assets/pics/ra-einstein.png');
}

Создание и добавление DOM-элемента в сцену

В методе create() происходит основная магия. Сначала мы создаем нативный HTML-элемент div и задаем ему стили через свойство style, как в обычной веб-разработке.

const div = document.createElement('div');
div.style = 'background-color: lime; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
div.innerText = 'Phaser 3';

Затем этот элемент добавляется в игровой мир с помощью метода this.add.dom(x, y, element). Он позиционируется относительно центра сцены (400, 300) и становится полноценным объектом сцены, который можно анимировать.

this.element = this.add.dom(400, 300, div);

После этого на сцену добавляется фоновое изображение, которое будет находиться под нашим DOM-объектом, создавая композицию.

Анимация искажения с помощью твинов

Phaser Tween Manager позволяет анимировать свойства объектов, включая DOM-элементы. В данном примере анимируются свойства skewX и skewY, которые отвечают за наклон элемента по соответствующим осям.

this.tweens.add({
    targets: this.element, // Цель анимации - наш DOM-объект
    skewX: 1.1,           // Конечное значение искажения по оси X (в радианах)
    skewY: 0.4,           // Конечное значение искажения по оси Y
    duration: 3000,       // Длительность анимации в миллисекундах
    ease: 'Sine.easeInOut', // Функция плавности для мягкого старта и остановки
    loop: -1,             // Бесконечный цикл анимации
    yoyo: true            // Анимация проигрывается и в обратном направлении
});

Параметр yoyo: true заставляет твин "отматываться" назад после завершения, а loop: -1 запускает этот процесс заново бесконечно. В результате элемент плавно искажается и возвращается в исходное состояние, создавая гипнотический эффект.

Особенности работы с DOM в Phaser

Важно понимать, что DOM-объект, созданный через add.dom(), интегрирован в систему отображения Phaser. Это означает:

1. Он участвует в порядке отрисовки (depth). В примере изображение Эйнштейна добавлено после DOM-элемента, поэтому оно оказывается под ним. 2. К нему можно применять трансформации, доступные для игровых объектов Phaser: позицию, масштаб, вращение, прозрачность и, как мы видели, искажение. 3. С ним можно взаимодействовать, добавляя слушатели событий мыши или клавиатуры.

Однако, для сложных CSS-анимаций или фильтров может потребоваться обращаться непосредственно к свойству this.element.node, которое содержит ссылку на исходный HTML-элемент.

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

Интеграция DOM-элементов через this.add.dom() — это мощный мост между игровым миром Phaser и возможностями CSS. Вы можете создавать текст со сложными стилями, интерактивные кнопки или информационные панели, которые было бы трудно реализовать на текстурах. Для экспериментов попробуйте: - Анимировать другие свойства, например scaleX/scaleY или alpha. - Применить CSS-фильтры (blur, hue-rotate) через this.element.node.style. - Создать сложный интерфейс с несколькими элементами и анимировать их последовательно с помощью цепочек твинов (tween.chain()). - Обрабатывать клики по элементу, добавляя событие 'click' к this.element.node.