О чем этот пример
В Phaser можно создавать не только графику на Canvas, но и использовать DOM-элементы прямо на игровом слое. Это открывает возможности для интеграции сложных HTML-интерфейсов, форм ввода или кастомных виджетов в игру. Однако обработка событий для DOM отличается от обычных игровых объектов. В этой статье на конкретном примере разберем, как добавлять DOM-элементы, делать их интерактивными и корректно уничтожать.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super('Example');
}
create ()
{
let textbutton = this.add.text(50, 50, "Text", { font: '64px Courier' });
textbutton.setInteractive();
let x = 0;
textbutton.on('pointerup', () => {
console.log('clicked text object');
this.add.text(100, 100 + 50 * x, "inserted", { font: '64px Courier' });
x++;
});
var div = document.createElement('div');
div.setAttribute("style", "color: white; font: 48px Arial;");
div.innerText = "DOM Element";
let el = this.add.dom(500, 80, div);
el.addListener('click');
el.on('click', (event) => {
console.log('clicked dom thingy');
el.destroy();
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example,
dom: {
createContainer: true
}
};
const game = new Phaser.Game(config);
Настройка проекта для работы с DOM
Для использования DOM-элементов в Phaser необходимо активировать соответствующую опцию в конфигурации игры. Без этого система add.dom не будет работать.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example,
dom: {
createContainer: true
}
};
Ключевой параметр — dom.createContainer: true. Он указывает Phaser создать специальный контейнер для DOM-элементов и интегрировать его в игровой цикл рендеринга.
Создание и позиционирование DOM-элемента
DOM-элементы создаются в два этапа: сначала средствами JavaScript создается нативный HTML-элемент, затем он добавляется на сцену через фабрику this.add.dom.
// 1. Создаем нативный HTML-элемент
var div = document.createElement('div');
div.setAttribute("style", "color: white; font: 48px Arial;");
div.innerText = "DOM Element";
// 2. Добавляем его на сцену Phaser
let el = this.add.dom(500, 80, div);
Метод this.add.dom(x, y, element) принимает координаты и созданный элемент. Phaser поместит его в контейнер и будет управлять его позицией (x, y) относительно сцены. Стилизация элемента полностью контролируется через обычный CSS или атрибут style.
Обработка событий: DOM vs Игровые объекты
Phaser предоставляет единую систему событий для игровых объектов (Sprite, Text, Image). Для DOM-элементов используется отдельный механизм прослушивания нативных событий.
**Для обычного текстового объекта Phaser:**
let textbutton = this.add.text(50, 50, "Text", { font: '64px Courier' });
textbutton.setInteractive();
textbutton.on('pointerup', () => {
console.log('clicked text object');
});
Здесь используется метод setInteractive(), чтобы объект реагировал на ввод, и система событий Phaser (pointerup).
**Для DOM-элемента:**
el.addListener('click');
el.on('click', (event) => {
console.log('clicked dom thingy');
el.destroy();
});
Сначала для элемента нужно зарегистрировать слушатель определенного типа события с помощью addListener('click'). Только после этого можно подписаться на это событие через el.on('click', ...). Это отдельный API, специфичный для DOM-объектов Phaser.
Уничтожение DOM-объектов
Уничтожение DOM-элемента, созданного через Phaser, следует выполнять его собственным методом destroy(). Это гарантирует корректное удаление как из внутренней системы Phaser, так и из DOM-дерева браузера.
el.on('click', (event) => {
el.destroy();
});
Вызов el.destroy() удалит объект из сцены и освободит связанные с ним ресурсы. Важно не путать этот метод с прямым удалением через div.remove() — это может привести к утечкам памяти внутри Phaser.
Что попробовать дальше
Интеграция DOM-элементов — мощный инструмент для создания гибридных интерфейсов в играх на Phaser. Главное помнить о двух разных системах обработки событий. Для экспериментов попробуйте: создать сложную HTML-форму поверх игры, анимировать DOM-элемент через el.setPosition в update() или сделать кастомный курсор мыши из DOM-элемента, который следует за pointer.
