О чем этот пример
Визуальное взаимодействие — ключевая часть игрового процесса. Когда игрок наводит курсор на объект, реакция должна быть мгновенной и точной. Но что, если ваш спрайт — это часть большого атласа текстур с прозрачными областями? Стандартная прямоугольная область для клика может захватывать пустое пространство, создавая ложные срабатывания. В этом материале мы разберем, как реализовать пиксель-перфект (pixel perfect) взаимодействие в Phaser 3. Этот подход гарантирует, что события мыши (например, наведение) будут срабатывать только при касании непрозрачных пикселей спрайта, а не его ограничивающего прямоугольника. Это особенно полезно для сложных UI-элементов, иконок или игровых объектов неправильной формы.
Версия 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('atlas', 'assets/atlas/megaset-2.png', 'assets/atlas/megaset-2.json');
}
create ()
{
const sprite = this.add.sprite(400, 300, 'atlas', 'hello').setInteractive({ pixelPerfect: true });
sprite.on('pointerover', function ()
{
this.setTint(0xff0000);
});
sprite.on('pointerout', function ()
{
this.setTint();
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#efefef',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка атласа: подготовка ресурсов
Первым шагом является загрузка атласа текстур. Атлас — это единое изображение (спрайтшит), содержащее множество отдельных кадров (спрайтов) и JSON-файл с координатами этих кадров. Использование атласов оптимизирует загрузку и отрисовку.
В методе preload мы используем this.load.atlas. Важно правильно указать путь к изображению и JSON-файлу с разметкой.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('atlas', 'assets/atlas/megaset-2.png', 'assets/atlas/megaset-2.json');
Метод setBaseURL устанавливает базовый URL для всех последующих загрузок, что упрощает указание путей. Ключ 'atlas' — это уникальный идентификатор, по которому мы будем обращаться к загруженному ресурсу в коде.
Создание интерактивного спрайта с Pixel Perfect
В методе create мы создаем спрайт и сразу делаем его интерактивным. Ключевой параметр здесь — pixelPerfect: true, который передается в метод setInteractive.
const sprite = this.add.sprite(400, 300, 'atlas', 'hello').setInteractive({ pixelPerfect: true });
Давайте разберем эту строку:
1. `this.add.sprite(400, 300, 'atlas', 'hello')` — создает спрайт в координатах (400, 300), используя текстуру с ключом `'atlas'` и конкретный кадр (frame) с именем `'hello'` из этого атласа.
2. `.setInteractive({ pixelPerfect: true })` — делает этот спрайт интерактивным. Опция `pixelPerfect: true` указывает системе ввода Phaser использовать для проверки пересечения не прямоугольную область (bounding box) спрайта, а его альфа-канал (прозрачность). События мыши будут срабатывать только тогда, когда курсор касается непрозрачных пикселей изображения.
Обработка событий наведения и ухода
После настройки интерактивности мы подписываемся на события указателя (мыши или касания). В данном примере мы меняем визуальное состояние спрайта при наведении и убираем изменение, когда курсор уходит.
sprite.on('pointerover', function () {
this.setTint(0xff0000); // Закрашиваем спрайт красным цветом
});
sprite.on('pointerout', function () {
this.setTint(); // Сбрасываем закраску (tint) в исходное состояние
});
Как это работает:
- Событие 'pointerover' срабатывает в тот момент, когда курсор впервые попадает на непрозрачный пиксель спрайта (благодаря pixelPerfect). Внутри функции-обработчика this ссылается на сам спрайт (sprite). Мы применяем оттенок (tint) красного цвета 0xff0000.
- Событие 'pointerout' срабатывает, когда курсор покидает зону взаимодействия спрайта. Вызов this.setTint() без аргументов сбрасывает примененный оттенок.
Конфигурация и запуск игры
Код примера завершается стандартной для Phaser 3 конфигурацией и созданием экземпляра игры. В конфиге мы указываем тип рендерера, размеры холста, цвет фона и стартовую сцену.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
backgroundColor: '#efefef',
scene: Example
};
const game = new Phaser.Game(config);
Важный момент: опция pixelPerfect работает корректно только для растровых спрайтов (Phaser.GameObjects.Sprite или Image), созданных из текстур, где доступны данные об альфа-канале. Для графических примитивов или растрового текста эта опция не применима.
Что попробовать дальше
Использование pixelPerfect: true — это простой и эффективный способ сделать взаимодействие с игровыми объектами более точным и приятным для игрока. Оно устраняет проблему срабатывания событий на прозрачных участках спрайтов сложной формы.
**Идеи для экспериментов:**
1. Сравните поведение с pixelPerfect: true и false для спрайта с большими прозрачными областями.
2. Добавьте событие 'pointerdown' и реализуйте логику клика/тапа по объекту.
3. Попробуйте применить этот подход к анимированному спрайту (с this.anims.create). Убедитесь, что точное взаимодействие работает на всех кадрах анимации.
