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

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

Версия 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/loginform.html');
        this.load.image('pic', 'assets/pics/turkey-1985086.jpg');
    }

    create ()
    {
        this.add.image(400, 300, 'pic');

        const text = this.add.text(10, 10, 'Please login to play', { color: 'white', fontFamily: 'Arial', fontSize: '32px '});

        const element = this.add.dom(400, 600).createFromCache('nameform');

        element.setPerspective(800);

        element.addListener('click');

        element.on('click', function (event)
        {

            if (event.target.name === 'loginButton')
            {
                const inputUsername = this.getChildByName('username');
                const inputPassword = this.getChildByName('password');

                //  Have they entered anything?
                if (inputUsername.value !== '' && inputPassword.value !== '')
                {
                    //  Turn off the click events
                    this.removeListener('click');

                    //  Tween the login form out
                    this.scene.tweens.add({ targets: element.rotate3d, x: 1, w: 90, duration: 3000, ease: 'Power3' });

                    this.scene.tweens.add({
                        targets: element, scaleX: 2, scaleY: 2, y: 700, duration: 3000, ease: 'Power3',
                        onComplete: function ()
                        {
                            element.setVisible(false);
                        }
                    });

                    //  Populate the text with whatever they typed in as the username!
                    text.setText(`Welcome ${inputUsername.value}`);
                }
                else
                {
                    //  Flash the prompt
                    this.scene.tweens.add({ targets: text, alpha: 0.1, duration: 200, ease: 'Power3', yoyo: true });
                }
            }

        });

        this.tweens.add({
            targets: element,
            y: 300,
            duration: 3000,
            ease: 'Power3'
        });
    }
}

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

const game = new Phaser.Game(config);

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

Первым делом нужно настроить проект для работы с DOM-элементами. Это делается в конфигурации игры, где необходимо включить опцию createContainer. Без неё система DOM не будет инициализирована.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    dom: {
        createContainer: true // Ключевая настройка для работы с HTML
    },
    scene: Example
};

В методе preload() мы загружаем не только изображение для фона, но и HTML-файл с нашей формой. Важно использовать метод this.load.html(), который загружает и кеширует разметку для последующего использования.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.html('nameform', 'assets/text/loginform.html'); // Загрузка формы
    this.load.image('pic', 'assets/pics/turkey-1985086.jpg'); // Загрузка фона
}

Создание и позиционирование DOM-элемента

После загрузки ресурсов, в методе create(), мы можем создать DOM-узел из кеша. Объект this.add.dom() создает специальный игровой объект, который является контейнером для HTML. Метод .createFromCache('nameform') вставляет внутрь этого контейнера загруженную ранее HTML-разметку.

create ()
{
    this.add.image(400, 300, 'pic'); // Фоновое изображение
    const element = this.add.dom(400, 600).createFromCache('nameform'); // Создание DOM-объекта
}

Изначально элемент помещается за пределами экрана (y=600). Чтобы плавно ввести его в игровую область, используется твин (анимация) для свойства `y`. Это стандартный подход для анимации любых игровых объектов в Phaser, включая DOM-элементы.

this.tweens.add({
    targets: element, // Цель анимации — наш DOM-объект
    y: 300,          // Конечная позиция по Y
    duration: 3000,  // Длительность 3 секунды
    ease: 'Power3'   // Функция плавности
});

Обработка событий и данных формы

Чтобы форма стала интерактивной, нужно подписаться на её события. В данном примере мы добавляем слушатель на событие click для всей формы (делегирование событий). Это эффективно, так как обрабатывает клики по любой кнопке внутри элемента.

element.addListener('click');
element.on('click', function (event) {
    // event.target — это конкретный HTML-элемент, по которому кликнули
    if (event.target.name === 'loginButton') {
        // Логика обработки нажатия кнопки Login
    }
});

Внутри обработчика мы получаем ссылки на поля ввода по их атрибуту name. Это стандартный DOM-API, доступный через this.getChildByName(), где this внутри функции-обработчика ссылается на DOM-объект Phaser (element).

const inputUsername = this.getChildByName('username');
const inputPassword = this.getChildByName('password');

if (inputUsername.value !== '' && inputPassword.value !== '') {
    // Поля заполнены, можно логинить
}

Визуальная обратная связь и анимации

Phaser позволяет добавлять визуальную обратную связь, используя встроенную систему твинов. В примере реализованы два сценария.

Если пользователь ввел логин и пароль, форма анимированно "улетает" со сцены. Обратите внимание на анимацию 3D-вращения через свойство rotate3d — это уникальная возможность для DOM-объектов в Phaser.

// 3D-вращение формы
this.scene.tweens.add({ targets: element.rotate3d, x: 1, w: 90, duration: 3000, ease: 'Power3' });
// Увеличение и смещение вниз
this.scene.tweens.add({
    targets: element, scaleX: 2, scaleY: 2, y: 700, duration: 3000,
    onComplete: function () { element.setVisible(false); } // Скрытие после анимации
});

Если же поля пусты, мы мигаем текстовой подсказкой, изменяя её свойство alpha (прозрачность). Твин с yoyo: true сначала уменьшает прозрачность до 0.1, а затем возвращает к 1, создавая эффект мерцания.

this.scene.tweens.add({
    targets: text, // Текстовый объект с подсказкой
    alpha: 0.1,
    duration: 200,
    ease: 'Power3',
    yoyo: true // Возврат к исходному значению
});

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

Интеграция HTML-форм через DOM Game Object — мощный инструмент, который стирает границы между игрой и веб-приложением. Вы можете использовать его не только для логина, но и для создания внутриигровых браузеров, сложных HUD-панелей или систем рейтингов. Для экспериментов попробуйте: валидировать email в поле ввода, динамически генерировать форму на основе JSON-конфигурации или привязать анимацию формы к игровым событиям (например, показ формы при проигрыше).