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

При разработке игр часто возникает задача сделать спрайт интерактивным — чтобы он реагировал на наведение курсора. Но что, если ваш спрайт имеет сложную форму с прозрачными областями? Обычный прямоугольный хитбокс будет срабатывать даже при наведении на пустые пиксели, что выглядит неряшливо. В этой статье мы разберем, как использовать опцию `pixelPerfect` в Phaser для создания точного, пиксельного определения попадания, которое учитывает альфа-канал изображения. Это значительно улучшит пользовательский опыт, особенно в казуальных играх или интерфейсах с иконками сложной формы.

Версия 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('hello', 'assets/sprites/hello.png');
    }

    create ()
    {
        const sprite = this.add.sprite(400, 300, '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);

Проблема прямоугольного хитбокса

По умолчанию, когда вы делаете игровой объект интерактивным с помощью .setInteractive(), Phaser создает для него хитбокс в форме прямоугольника, равного размеру текстуры. Это быстро и эффективно для вычислений, но создает проблемы визуального восприятия.

Представьте спрайт в форме звезды или надписи с закругленными буквами. Прямоугольная область, в которую он вписан, будет включать в себя много прозрачных пикселей по углам. Игрок будет видеть, как курсор меняет состояние (например, на указатель), наводя его на пустое пространство вокруг спрайта. Это ломает immersion и выглядит как баг.

// Стандартный вызов создает прямоугольный хитбокс
sprite.setInteractive();

Решение: Включение Pixel Perfect

Phaser предоставляет элегантное решение — опцию pixelPerfect в конфигурационном объекте метода .setInteractive(). Когда эта опция установлена в true, система взаимодействия начинает проверять не просто попадание в прямоугольник, а конкретно в непрозрачные пиксели текстуры спрайта.

Внутренний механизм работает так: при событии взаимодействия (например, pointerover) Phaser берет координаты курсора, переводит их в координаты текстуры спрайта и проверяет альфа-значение (прозрачность) пикселя в этой позиции. Если пиксель непрозрачен (альфа > 0), событие срабатывает. Если пиксель прозрачен — событие игнорируется.

// Включение точного пиксельного проверки попадания
const sprite = this.add.sprite(400, 300, 'hello').setInteractive({ pixelPerfect: true });

Обработка событий Pointerover и Pointerout

С включенным pixelPerfect логика обработки событий становится интуитивно правильной. Мы можем повесить обработчики на события pointerover (курсор нашел непрозрачный пиксель) и pointerout (курсор покинул все непрозрачные пиксели).

В предоставленном примере при наведении спрайт окрашивается в красный оттенок с помощью метода .setTint(). Когда курсор уходит, оттенок снимается вызовом того же метода без аргументов.

Важно помнить, что контекст (this) внутри функций-обработчиков, переданных в .on(), будет ссылаться на сам спрайт, к которому привязано событие. Это позволяет легко модифицировать его свойства.

sprite.on('pointerover', function () {
    // 'this' здесь — это спрайт 'sprite'
    this.setTint(0xff0000); // Применяем красный оттенок
});

sprite.on('pointerout', function () {
    this.setTint(); // Сбрасываем оттенок
});

Производительность и ограничения

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

Рекомендации по использованию: * Применяйте для ключевых, крупных или сложных по форме объектов (персонажи, большие кнопки, иконки). * Избегайте для множества мелких, часто обновляемых объектов (например, частиц). * Для простых геометрических форм (квадраты, круги) достаточно стандартного хитбокса или хитбокса, заданного вручную через setInteractive(shape, callback).

Опция идеально подходит для статичных или малоподвижных элементов UI и важных игровых предметов, где точность взаимодействия критична.

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

Опция pixelPerfect: true — это мощный инструмент для повышения качества взаимодействия в вашей игре. Она позволяет спрайтам реагировать на курсор ровно так, как видит игрок, исключая ложные срабатывания на прозрачных областях. Для экспериментов попробуйте применить этот подход к анимированному спрайту (с pixelPerfect на каждом кадре анимации) или создайте сложную интерактивную карту, где разные области одного большого изображения реагируют по-разному. Помните о балансе между точностью и производительностью, и ваши игры станут заметно приятнее и профессиональнее.