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

При разработке игр на Phaser часто возникают ситуации, когда интерактивные элементы перестают реагировать на пользовательский ввод. Это может быть связано с тем, что другие DOM-элементы на странице перекрывают игровое поле или сами границы интерактивной зоны объекта настроены некорректно. Понимание принципов работы системы ввода и настройки bounds (границ) критически важно для создания отзывчивого геймплея. В этой статье мы разберем на примере, как Phaser обрабатывает события ввода и что делать, если взаимодействие внезапно прекращается.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


var config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

function preload ()
{
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('bg', 'assets/skies/background1.png');
}

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


    var r4 = this.add.rectangle(200, 400, 148, 148, 0xff6699);
r4.setInteractive();
  r4.on('pointerover', () => {
    r4.setFillStyle(0x9966ff);
  })
    r4.on('pointerout', () => {
    r4.setFillStyle(0xff6699);
  })


}

setTimeout(() => {
  document.body.prepend(document.createElement("INPUT"))
}, 4000);

Проблема: исчезновение интерактивности

Рассмотрим простую сцену. В ней создается прямоугольник r4, который меняет цвет при наведении курсора. Однако через 4 секунды после старта игры на страницу программно добавляется элемент <input>. Этот элемент, будучи обычным DOM-узлом, может перехватывать события мыши, из-за чего интерактивность игрового прямоугольника теряется – курсор больше не вызывает смену цвета.

Это классический пример конфликта между DOM и Canvas. События мыши, которые Phaser ловит на уровне canvas, больше не доходят до него, так как их перехватывает новый элемент, появившийся поверх.

Решение: настройка границ ввода (Input Bounds)

Phaser предоставляет простой механизм для решения этой проблемы – объект input и его методы для управления границами ввода. Границы ввода определяют область на странице, в которой Phaser будет слушать события мыши, касаний и клавиатуры.

Чтобы указать системе ввода, что нужно отслеживать события только в пределах канваса игры, необходимо явно задать его границы. Это делается в методе create сцены.

function create() {
    // ... создание фона и интерактивных объектов ...

    // Устанавливаем границы ввода равными границам игрового канваса
    this.input.setHitArea(this.sys.canvas);
}

Метод this.input.setHitArea() принимает DOM-элемент (в данном случае сам canvas) или объект с координатами. После этой настройки события мыши будут обрабатываться Phaser'ом только внутри указанной области, даже если поверх появились другие HTML-элементы.

Детальная настройка границ

Иногда нужно ограничить ввод не всем канвасом, а его конкретной областью. Например, для игры в оконном режиме или при наличии нескольких интерактивных зон. Для этого можно передать в setHitArea объект с координатами прямоугольной области.

function create() {
    // ... создание фона и интерактивных объектов ...

    // Устанавливаем границы ввода в виде прямоугольника {x, y, width, height}
    this.input.setHitArea({ x: 100, y: 100, width: 600, height: 400 });
}

В этом примере Phaser будет реагировать на события мыши только внутри прямоугольника с началом в точке (100, 100) и размерами 600x400 пикселей. Все, что вне этой зоны, системой ввода игнорируется.

Важно: координаты области задаются относительно *страницы*, а не относительно канваса. Это нужно учитывать при сложной вёрстке.

Практический пример: защита от DOM-вторжений

Вернемся к исходному примеру. Добавим настройку границ ввода, чтобы защитить интерактивность прямоугольника от вновь создаваемого DOM-элемента.

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

    var r4 = this.add.rectangle(200, 400, 148, 148, 0xff6699);
    r4.setInteractive();
    r4.on('pointerover', () => {
        r4.setFillStyle(0x9966ff);
    });
    r4.on('pointerout', () => {
        r4.setFillStyle(0xff6699);
    });

    // КРИТИЧЕСКИ ВАЖНАЯ СТРОКА: Защищаем интерактивность канваса
    this.input.setHitArea(this.sys.canvas);
}

После этого, даже когда элемент <input> появится поверх игры, события наведения (pointerover) и увода (pointerout) курсора с прямоугольника будут корректно обрабатываться движком, так как границы ввода жестко привязаны к канвасу.

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

Явная настройка границ ввода (input bounds) – это простой, но мощный инструмент для обеспечения стабильной интерактивности в играх на Phaser, особенно когда игра встроена в сложную веб-страницу с динамическим контентом. Для экспериментов попробуйте

  1. Создать несколько интерактивных зон с разными hitArea и переключаться между ними в runtime
  2. Связать границы ввода с камерой, чтобы интерактивной была только видимая область игрового мира
  3. Реализовать свою логику проверки попадания курсора в объект на основе пользовательских bounds