О чем этот пример
В играх часто требуется динамическая реакция на взаимодействие игрока с множеством элементов на экране — например, подсветка карты при наведении курсора. Phaser предоставляет мощные инструменты для обработки таких событий на уровне всей группы объектов, избегая необходимости писать индивидуальные обработчики для каждого. В этой статье мы разберем, как использовать события `gameobjectover` и `gameobjectout` для создания интерактивных интерфейсов, где сотни объектов могут реагировать на действия пользователя одновременно.
Версия 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.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
create ()
{
this.createCards();
this.input.on('gameobjectover', (pointer, gameObject) =>
{
gameObject.setTint(0xff0000);
});
this.input.on('gameobjectout', (pointer, gameObject) =>
{
gameObject.clearTint();
});
}
createCards ()
{
const frames = this.textures.get('cards').getFrameNames();
for (let i = 0; i < 64; i++)
{
const x = Phaser.Math.Between(0, 800);
const y = Phaser.Math.Between(0, 600);
const s = Phaser.Math.FloatBetween(0.4, 0.6);
this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setScale(s).setInteractive();
}
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Основы: события наведения и ухода курсора
Phaser позволяет обрабатывать события взаимодействия курсора с игровыми объектами (GameObject) на глобальном уровне. Вместо того чтобы назначать отдельные обработчики каждому объекту, можно использовать общие события gameobjectover (курсор наводится на объект) и gameobjectout (курсор покидает объект). Эти события автоматически срабатывают для любого объекта, который был сделан интерактивным через метод setInteractive().
Когда событие происходит, система передает в функцию-обработчик два параметра: pointer (информация о курсоре или касании) и gameObject (конкретный объект, над которым произошло действие). Это позволяет централизованно управлять реакцией всех интерактивных элементов в сцене.
Подготовка и создание множества объектов
В примере мы создаем множество карт, используя атлас (atlas) текстуры. Атлас — это изображение, содержащее множество отдельных спрайтов (фреймов), что эффективно для работы с большим количеством графических элементов.
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
После загрузки ресурсов в методе createCards() мы генерируем 64 карты. Для каждой карты выбирается случайная позиция, случайный масштаб и случайный фрейм из атласа. Ключевой шаг — сделать каждый объект интерактивным, чтобы он мог реагировать на события курсора.
this.add.image(x, y, 'cards', Phaser.Math.RND.pick(frames)).setScale(s).setInteractive();
Метод setInteractive() без дополнительных параметров устанавливает область взаимодействия равной размеру самого изображения (с учетом текущего масштаба).
Настройка глобальных обработчиков событий
В методе create() сцена устанавливает два обработчика событий на глобальный объект this.input. Эти обработчики будут вызываться для любого интерактивного объекта в сцене при наведении и уходе курсора.
this.input.on('gameobjectover', (pointer, gameObject) => {
gameObject.setTint(0xff0000);
});
При событии gameobjectover объект окрашивается в красный цвет (tint). Метод setTint применяет цветовой фильтр к изображению, не изменяя исходную текстуру.
this.input.on('gameobjectout', (pointer, gameObject) => {
gameObject.clearTint();
});
При событии gameobjectout tint удаляется, возвращая объекту исходный цвет. Это создает эффект подсветки при наведении.
Почему это эффективно?
Использование глобальных событий вместо индивидуальных обработчиков на каждом объекте (gameObject.on('pointerover', ...)) значительно упрощает код и снижает нагрузку на управление событиями. Система Phaser сама определяет, какой объект стал целевым, и передает его в ваш обработчик. Это особенно полезно в сценах с десятками или сотнями интерактивных элементов, таких как карты в пасьянсе, предметы в инвентаре или плитки на поле.
Такой подход также обеспечивает единообразие реакции: все объекты будут подсвечиваться одинаково, согласно одной функции. Если нужно разное поведение для разных типов объектов, можно проверять свойства gameObject внутри обработчика (например, gameObject.type или пользовательские данные).
Что попробовать дальше
Глобальные события gameobjectover и gameobjectout — мощный инструмент для создания интерактивных интерфейсов в Phaser. Они позволяют централизованно управлять взаимодействием с множеством объектов, делая код чище и эффективнее. Для экспериментов попробуйте: добавить разные реакции для разных типов объектов (например, проверять gameObject.frame.name); использовать другие эффекты вместо tint (например, изменение масштаба или добавление анимации); или комбинировать эти события с другими, например gameobjectdown, для обработки кликов.
