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

При разработке игр часто требуется реагировать на наведение курсора мыши на игровые объекты, например, для подсветки интерактивных элементов. В Phaser.js для этого есть события `gameobjectover` и `gameobjectout`. Однако, по умолчанию, срабатывает только событие для самого верхнего объекта в стеке отображения, что может быть не всегда удобно. В этой статье мы разберем, как управлять этим поведением с помощью свойства `topOnly` и создавать более гибкие интерфейсы.

Версия 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('eye', 'assets/pics/lance-overdose-loader-eye.png');
    }

    create ()
    {
        const sprite1 = this.add.sprite(400, 300, 'eye').setInteractive();
        const sprite2 = this.add.sprite(450, 350, 'eye').setInteractive();
        const sprite3 = this.add.sprite(500, 400, 'eye').setInteractive();

        //  If you disable topOnly it will fire events for all objects the pointer is over, regardless of place on the display list
        this.input.topOnly = false;

        //  Events

        this.input.on('gameobjectover', (pointer, gameObject) =>
        {

            gameObject.setTint(0xff0000);

        });

        this.input.on('gameobjectout', (pointer, gameObject) =>
        {

            gameObject.clearTint();

        });
    }
}

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

const game = new Phaser.Game(config);

Создание интерактивных спрайтов

Первым шагом является создание игровых объектов и назначение им интерактивности. Без этого объекты не будут реагировать на события мыши.

const sprite1 = this.add.sprite(400, 300, 'eye').setInteractive();
const sprite2 = this.add.sprite(450, 350, 'eye').setInteractive();
const sprite3 = this.add.sprite(500, 400, 'eye').setInteractive();

Метод setInteractive() делает объект чувствительным к вводу. Теперь на него можно наводить курсор и кликать.

Свойство `topOnly` и его роль

Ключевой момент — свойство this.input.topOnly. Оно определяет, как система ввода обрабатывает перекрывающиеся объекты.

this.input.topOnly = false;

По умолчанию topOnly имеет значение true. Это означает, что события gameobjectover и gameobjectout будут срабатывать только для самого верхнего объекта в z-индексе (порядке отображения) под курсором. Если установить значение false, события будут генерироваться для всех объектов, находящихся под указателем мыши, независимо от их глубины. Это полезно, когда нужно одновременно подсветить несколько перекрывающихся элементов.

Обработка событий наведения и ухода

Основная логика реагирования на наведение реализуется через слушатели событий gameobjectover и gameobjectout.

this.input.on('gameobjectover', (pointer, gameObject) => {
    gameObject.setTint(0xff0000);
});

this.input.on('gameobjectout', (pointer, gameObject) => {
    gameObject.clearTint();
});

При срабатывании gameobjectover переданный в колбэк объект gameObject окрашивается в красный цвет с помощью setTint. Когда курсор покидает объект (gameobjectout), tint очищается методом clearTint, возвращая спрайту исходный вид.

Практический пример и поведение

В нашем примере три спрайта расположены так, что они частично перекрывают друг друга. При topOnly: false: 1. Если навести курсор на область, где пересекаются все три спрайта, все они станут красными. 2. При движении курсора события будут срабатывать для каждого объекта индивидуально при пересечении его границ. 3. Если изменить значение на true (или удалить строку с настройкой), подсвечиваться будет только самый верхний спрайт в точке наведения.

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

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

Использование topOnly дает контроль над тем, как события мыши распространяются по перекрывающимся объектам. Это мощный инструмент для создания интуитивных интерфейсов, инвентарей, меню или сложных игровых сцен. Попробуйте поэкспериментировать: добавьте разные реакции для разных типов объектов (например, изменение масштаба вместо tint) или комбинируйте это свойство с другими событиями ввода, такими как gameobjectdown.