О чем этот пример
При наведении курсора на перекрывающиеся игровые объекты Phaser может генерировать события для всех объектов под указателем или только для верхнего. Это поведение контролируется методом `setTopOnly()`. Понимание этой механики критично для создания сложных интерфейсов, инвентарей или интерактивных сцен, где объекты наслаиваются друг на друга. В статье разберем, как работает приоритизация событий и когда отключать `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 ()
{
for (let i = 0; i < 14; i++)
{
this.add.sprite(100 + i * 30, 100 + i * 30, 'eye').setInteractive();
}
// If you disable topOnly it will fire events for all objects the pointer is over
// regardless of their place on the display list
this.input.setTopOnly(true);
// Events
this.input.on('gameobjectover', (pointer, gameObject) =>
{
gameObject.setTint(0xff0000);
});
this.input.on('gameobjectout', (pointer, gameObject) =>
{
gameObject.clearTint();
});
const text = this.add.text(10, 10, 'Input.topOnly: true', { font: '16px Courier', fill: '#00ff00' });
this.input.on('pointerdown', function (pointer)
{
if (this.input.topOnly)
{
this.input.setTopOnly(false);
text.setText('Input.topOnly: false');
}
else
{
this.input.setTopOnly(true);
text.setText('Input.topOnly: true');
}
}, this);
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Суть параметра TopOnly
По умолчанию Phaser использует режим topOnly: true. Это означает, что события ввода, такие как 'gameobjectover' (наведение) и 'gameobjectout' (сведение), будут срабатывать только для самого верхнего интерактивного объекта в стеке отображения под курсором. Нижележащие объекты игнорируются, даже если указатель находится и над ними.
Если установить topOnly: false, система будет проверять все объекты под указателем и генерировать события для каждого из них. Это полезно, когда нужно одновременно подсветить несколько перекрывающихся элементов.
Настройка сцены и создание объектов
В примере загружается одно изображение и создается 14 спрайтов, расположенных по диагонали. Каждый спрайт делается интерактивным с помощью метода setInteractive(), что необходимо для обработки событий ввода.
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
for (let i = 0; i < 14; i++)
{
this.add.sprite(100 + i * 30, 100 + i * 30, 'eye').setInteractive();
}
Изначально режим устанавливается в true.
this.input.setTopOnly(true);
Обработка событий наведения и сведения
Регистрируются обработчики для событий 'gameobjectover' и 'gameobjectout'. Когда курсор попадает на объект (over), ему задается красный оттенок (setTint). Когда курсор уходит с объекта (out), оттенок снимается (clearTint).
this.input.on('gameobjectover', (pointer, gameObject) =>
{
gameObject.setTint(0xff0000);
});
this.input.on('gameobjectout', (pointer, gameObject) =>
{
gameObject.clearTint();
});
В режиме topOnly: true эти события будут возникать только для верхнего спрайта в точке пересечения.
Переключение режима в runtime
В примере добавлено переключение режима по клику ('pointerdown'). При каждом клике проверяется текущее состояние this.input.topOnly и оно инвертируется с помощью setTopOnly(). Текстовый объект обновляется, чтобы отображать текущий режим.
this.input.on('pointerdown', function (pointer)
{
if (this.input.topOnly)
{
this.input.setTopOnly(false);
text.setText('Input.topOnly: false');
}
else
{
this.input.setTopOnly(true);
text.setText('Input.topOnly: true');
}
}, this);
Это позволяет наглядно сравнить поведение системы при разных настройках прямо во время работы примера.
Практические отличия в поведении
1. **При topOnly: true**: Наведите курсор на область, где спрайты перекрываются. Подсветится (станет красным) только один, самый верхний спрайт. При движении курсора события out и over будут срабатывать быстро, так как система отслеживает только верхний объект.
2. **При topOnly: false**: Наведите курсор на ту же область. Красными станут все спрайты, находящиеся под курсором. При движении мыши события будут генерироваться для каждого объекта в стеке, что может привести к более сложным цепочкам вызовов. Это хорошо видно, если медленно вести курсор по цепочке спрайтов.
Что попробовать дальше
Метод setTopOnly — это мощный инструмент для управления всплытием событий в сложных интерфейсах. Используйте режим true для обычных кнопок и одиночных взаимодействий, где важен только верхний элемент. Режим false пригодится для составных объектов, кастомных курсоров, влияющих на несколько сущностей сразу, или для отладки наложения коллайдеров. Поэкспериментируйте: создайте инвентарь с перекрывающимися ячейками или меню с выпадающими списками, чтобы почувствовать разницу.
