О чем этот пример
При интеграции стандартных HTML-элементов в игровую сцену Phaser может возникнуть необходимость контролировать их визуальный приоритет относительно других игровых объектов, таких как спрайты или изображения. По умолчанию DOM-элементы, добавленные через `this.add.dom()`, могут перекрывать графику игры, что не всегда желательно. Эта статья покажет, как управлять порядком отрисовки (z-index) DOM-элементов, используя встроенные методы 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 div1 = document.createElement('div');
div1.style = 'background-color: lime; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
div1.innerText = 'Phaser 3';
const div2 = document.createElement('div');
div2.style = 'background-color: yellow; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
div2.innerText = 'Phaser 3';
const element1 = this.add.dom(300, 0, div1);
const element2 = this.add.dom(400, 0, div2);
element1.setDepth(2);
this.tweens.add({
targets: [ element1, element2 ],
y: 600,
angle: 200,
duration: 3000,
scaleX: 2,
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 необходимо активировать соответствующую опцию в конфигурации игры. Без этого система DOM не будет инициализирована, и вызов this.add.dom() приведет к ошибке.
В методе preload загружается изображение, которое будет использоваться в сцене как фоновый или игровой объект. Обратите внимание, что setBaseURL задает базовый путь для загрузки ресурсов.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
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 создаются два стандартных HTML-элемента div. Им задаются стили CSS для визуального оформления. Эти элементы являются чисто веб-компонентами и не являются частью графического контекста Canvas/WebGL Phaser по умолчанию.
Метод this.add.dom(x, y, element) интегрирует созданный HTML-элемент в игровое дерево отображения Phaser. Он возвращает объект DOMElement, который уже можно анимировать и которому можно задавать глубину. Первые два аргумента — это начальные координаты элемента на сцене.
const div1 = document.createElement('div');
div1.style = 'background-color: lime; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
div1.innerText = 'Phaser 3';
const div2 = document.createElement('div');
div2.style = 'background-color: yellow; width: 220px; height: 100px; font: 48px Arial; font-weight: bold';
div2.innerText = 'Phaser 3';
const element1 = this.add.dom(300, 0, div1);
const element2 = this.add.dom(400, 0, div2);
Управление глубиной (Depth) DOM-элементов
Ключевой момент — управление порядком отрисовки. Без вмешательства DOM-элементы, будучи добавленными последними, будут отрисованы поверх всех игровых объектов (как Image или Sprite), созданных в create. Это происходит из-за их положения в дереве отображения Phaser.
Метод setDepth(value) позволяет явно задать значение глубины для объекта DOMElement. Объекты с большим значением depth отрисовываются поверх объектов с меньшим значением. В примере element1.setDepth(2) гарантирует, что этот элемент будет поверх изображения Эйнштейна, которое по умолчанию имеет глубину 0.
Важно: второй элемент (element2) не получает явного setDepth. Его положение в порядке отрисовки относительно других объектов будет определяться порядком добавления в сцену и его значением глубины по умолчанию.
element1.setDepth(2);
this.add.image(400, 300, 'einstein'); // Этот image имеет глубину 0 по умолчанию.
Анимация DOM-элементов средствами Phaser
Одно из главных преимуществ использования this.add.dom() — возможность анимировать HTML-элементы через мощную систему твинов Phaser точно так же, как и обычные игровые объекты. Это обеспечивает плавную и синхронизированную с игрой анимацию.
В примере создается твин, который одновременно воздействует на оба DOM-элемента (element1 и element2). Он анимирует их свойства `y(вертикальное положение),angle(вращение) иscaleX(масштаб по горизонтали). Параметрыloopиyoyo` создают непрерывную возвратно-поступательную анимацию.
this.tweens.add({
targets: [ element1, element2 ], // Массив целевых объектов для анимации
y: 600,
angle: 200,
duration: 3000,
scaleX: 2,
ease: 'Sine.easeInOut',
loop: -1, // Бесконечный цикл
yoyo: true // Анимация в прямом и обратном направлении
});
Что попробовать дальше
Использование this.add.dom() и setDepth() открывает мощный канал интеграции динамического HTML/CSS-контента в игровой процесс на Phaser. Вы можете создавать сложные интерфейсы, меню или эффекты, которые плавно анимируются и корректно взаимодействуют с графикой игры. Для экспериментов попробуйте: изменять значение глубины у element2, чтобы управлять тем, какой div поверх другого; анимировать другие CSS-свойства через твины (например, opacity или backgroundColor с помощью плагинов); или создать сложную композицию, где DOM-элементы служат интерактивными виджетами поверх игрового мира.
