О чем этот пример
В веб-играх часто нужны динамические интерфейсы, которые реагируют на действия игрока. Пример демонстрирует, как встроить обычный HTML-элемент в игровой мир Phaser, наделить его физическим телом и управлять им с клавиатуры. Это полезно для создания нестандартных меню, интерактивных виджетов или частиц интерфейса, которые живут по законам игровой физики.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
element;
player;
cursors;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
this.cursors = this.input.keyboard.createCursorKeys();
this.element = this.add.dom(400, 300, 'div', 'font-size: 96px', '💩').setOrigin(0);
this.physics.add.existing(this.element, false);
this.element.body.setCollideWorldBounds(true);
}
update ()
{
this.element.body.setVelocity(0);
if (this.cursors.left.isDown)
{
this.element.body.setVelocityX(-300);
}
else if (this.cursors.right.isDown)
{
this.element.body.setVelocityX(300);
}
if (this.cursors.up.isDown)
{
this.element.body.setVelocityY(-300);
}
else if (this.cursors.down.isDown)
{
this.element.body.setVelocityY(300);
}
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
backgroundColor: '#0072bc',
width: 800,
height: 600,
dom: {
createContainer: true
},
physics: {
default: 'arcade',
arcade: {
debug: true
}
},
scene: Example
};
const game = new Phaser.Game(config);
Настройка сцены и загрузка ресурсов
В методе preload мы загружаем спрайт, но в данном примере он не используется — фокус на DOM-элементе. Ключевой момент — конфигурация игры, где необходимо явно указать поддержку DOM.
const config = {
// ... другие настройки ...
dom: {
createContainer: true
},
physics: {
default: 'arcade',
arcade: {
debug: true // Включаем отладку для визуализации hitbox
}
},
scene: Example
};
Без параметра dom: { createContainer: true } система DOM не будет инициализирована, и вызов this.add.dom приведет к ошибке. Параметр debug: true в физике позволяет увидеть границы физического тела вокруг элемента.
Создание и "оживление" DOM-элемента
В методе create мы создаем три ключевых объекта: обработчик клавиш, DOM-элемент и привязываем к нему физическое тело.
create ()
{
// Создаем объект для отслеживания стрелок клавиатуры
this.cursors = this.input.keyboard.createCursorKeys();
// Создаем DOM-элемент (div) в координатах (400, 300)
// Задаем ему стиль font-size и текстовое содержимое '💩'
this.element = this.add.dom(400, 300, 'div', 'font-size: 96px', '💩').setOrigin(0);
// Делаем элемент физическим телом (false = не как спрайт)
this.physics.add.existing(this.element, false);
// Разрешаем телу сталкиваться с границами мира
this.element.body.setCollideWorldBounds(true);
}
Метод this.add.dom() принимает координаты, тег HTML, строку стилей и контент. После создания элемент интегрируется в канвас Phaser. Вызов this.physics.add.existing(this.element, false) добавляет к уже существующему игровому объекту компонент тела Arcade Physics. Второй аргумент false указывает, что это не спрайт (у спрайта тело привязано к текстуре).
Управление движением через физику
Логика управления сосредоточена в update. Мы напрямую манипулируем скоростью физического тела, привязанного к элементу.
update ()
{
// Сбрасываем скорость по обеим осям каждый кадр
this.element.body.setVelocity(0);
// Проверяем состояние клавиш и задаем соответствующую скорость
if (this.cursors.left.isDown)
{
this.element.body.setVelocityX(-300);
}
else if (this.cursors.right.isDown)
{
this.element.body.setVelocityX(300);
}
if (this.cursors.up.isDown)
{
this.element.body.setVelocityY(-300);
}
else if (this.cursors.down.isDown)
{
this.element.body.setVelocityY(300);
}
}
Важно сбрасывать скорость (setVelocity(0)) в начале каждого кадра. Иначе тело будет продолжать движение по инерции, даже когда клавиши отпущены. Методы setVelocityX() и setVelocityY() задают мгновенную скорость в пикселях в секунду. Условия проверяют свойство .isDown у каждого ключа в объекте this.cursors.
Особенности и ограничения DOM-элементов
DOM-элементы в Phaser — это мощный, но специфический инструмент.
* **Производительность:** Не стоит использовать сотни таких элементов для игровой графики. Они тяжелее обычных спрайтов. Идеально подходят для небольшого числа UI-компонентов.
* **Координаты и Origin:** По умолчанию точка вращения и позиционирования (origin) DOM-элемента — его центр. В примере используется .setOrigin(0), что меняет точку отсчета на левый верхний угол. Это влияет на расположение физического тела.
* **Взаимодействие:** С DOM-элементом можно работать как с обычным HTML-узлом через свойство this.element.node. Это открывает возможности для сложной стилизации, добавления полей ввода или обработки браузерных событий.
Что попробовать дальше
Пример показывает, что Phaser стирает границы между игровым миром и веб-интерфейсом. Вы можете заставить летать меню, сталкиваться кнопки или создавать разрушаемый текст. Для экспериментов попробуйте: заменить эмодзи на реальный HTML-инпут; добавить несколько DOM-элементов и заставить их отталкиваться; привязать движение элемента не к клавиатуре, а к движку мыши — возможности ограничены только вашей фантазией и требованиями к производительности.
