О чем этот пример
Современные веб-игры часто требуют интерактивных интерфейсов, таких как формы ввода или панели меню. Phaser предоставляет мощный инструмент для интеграции обычного HTML-кода в игровую сцену, позволяя использовать привычные веб-формы прямо поверх игрового мира. В этой статье мы разберем пример, который показывает, как совместить интерактивные игровые объекты, такие как перетаскиваемые карты, с HTML-формой для ввода имени, используя модуль `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.html('nameform', 'assets/text/nameform.html');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
create ()
{
// Create a stack of random cards
const frames = this.textures.get('cards').getFrameNames();
let x = 100;
let y = 100;
for (let i = 0; i < 64; i++)
{
const image = this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setInteractive({ draggable: true });
x += 4;
y += 4;
}
this.input.on('dragstart', function (pointer, gameObject)
{
this.children.bringToTop(gameObject);
}, this);
this.input.on('drag', (pointer, gameObject, dragX, dragY) =>
{
gameObject.x = dragX;
gameObject.y = dragY;
});
const text = this.add.text(300, 10, 'Please enter your name', { color: 'white', fontSize: '20px '});
const element = this.add.dom(400, 0).createFromCache('nameform');
element.addListener('click');
element.on('click', function (event)
{
if (event.target.name === 'playButton')
{
const inputText = this.getChildByName('nameField');
// Have they entered anything?
if (inputText.value !== '')
{
// Turn off the click events
this.removeListener('click');
// Hide the login element
this.setVisible(false);
// Populate the text with whatever they typed in
text.setText(`Welcome ${inputText.value}`);
}
else
{
// Flash the prompt
this.scene.tweens.add({
targets: text,
alpha: 0.2,
duration: 250,
ease: 'Power3',
yoyo: true
});
}
}
});
this.tweens.add({
targets: element,
y: 300,
duration: 3000,
ease: 'Power3'
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#222288',
dom: {
createContainer: true
},
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов: HTML и атлас
В методе preload загружаются два ключевых ресурса. HTML-файл с формой загружается как ассет с ключом 'nameform'. Это позволяет кэшировать и повторно использовать HTML-код. Атлас с картами загружается для создания визуальных игровых объектов. Обратите внимание на использование setBaseURL для указания базового пути к ресурсам.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.html('nameform', 'assets/text/nameform.html');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
Создание стопки перетаскиваемых карт
В методе create сначала создается стопка из 64 карт. Каждая карта — это изображение (Image Game Object), использующее случайный кадр из атласа 'cards'. Ключевой момент — вызов метода setInteractive({ draggable: true }) для каждого изображения. Это регистрирует объект в системе ввода Phaser и активирует его перетаскивание.
const frames = this.textures.get('cards').getFrameNames();
let x = 100;
let y = 100;
for (let i = 0; i < 64; i++) {
const image = this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setInteractive({ draggable: true });
x += 4;
y += 4;
}
Затем настраиваются обработчики событий перетаскивания. Обработчик 'dragstart' использует this.children.bringToTop(gameObject), чтобы перетаскиваемая карта отображалась поверх остальных. Обработчик 'drag' обновляет координаты карты в реальном времени, следуя за указателем.
this.input.on('dragstart', function (pointer, gameObject) {
this.children.bringToTop(gameObject);
}, this);
this.input.on('drag', (pointer, gameObject, dragX, dragY) => {
gameObject.x = dragX;
gameObject.y = dragY;
});
Добавление и анимация HTML-формы
Для работы с HTML необходимо включить поддержку DOM в конфигурации игры, установив dom.createContainer: true. В сцене для добавления HTML используется метод this.add.dom(). Созданный элемент позиционируется относительно сцены и может быть анимирован стандартными твинами Phaser.
const element = this.add.dom(400, 0).createFromCache('nameform');
this.tweens.add({
targets: element,
y: 300,
duration: 3000,
ease: 'Power3'
});
Обработка событий DOM-элемента
DOM-элемент может обрабатывать стандартные события браузера, такие как клик. Сначала добавляется слушатель для события 'click', а затем навешивается обработчик. Внутри обработчика проверяется, была ли нажата кнопка с именем 'playButton'. Если да, то происходит проверка поля ввода. При успешном вводе форма скрывается, а в текстовый объект сцены выводится приветствие. Если поле пустое, запускается твин, мигающий текстом-подсказкой.
element.addListener('click');
element.on('click', function (event) {
if (event.target.name === 'playButton') {
const inputText = this.getChildByName('nameField');
if (inputText.value !== '') {
this.removeListener('click');
this.setVisible(false);
text.setText(`Welcome ${inputText.value}`);
} else {
this.scene.tweens.add({
targets: text,
alpha: 0.2,
duration: 250,
ease: 'Power3',
yoyo: true
});
}
}
});
Конфигурация игры с поддержкой DOM
Для корректной работы DOM-элементов в игре необходимо явно включить эту опцию в конфигурации, создав контейнер. Без этого DOM-объекты не будут добавлены на страницу.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#222288',
dom: {
createContainer: true // Ключевая настройка
},
scene: Example
};
Что попробовать дальше
Пример демонстрирует, как Phaser стирает границы между игровым миром и веб-интерфейсом. DOM-элементы можно анимировать, позиционировать и наделять интерактивностью, а игровые объекты — легко перетаскивать. Для экспериментов попробуйте
- Создать сложную форму с несколькими полями и кнопками
- Использовать другие события DOM, такие как
inputилиsubmit - Реализовать перетаскивание DOM-элементов по сцене с помощью той же системы
drag
