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

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

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

    create ()
    {
        const sprite = this.add.sprite(400, 300, 'megaset', 'mask-test2').setInteractive({ pixelPerfect: true });

        const text = this.add.text(10, 10, 'Click. Only the black areas should re-act.', { font: '16px Courier', fill: '#000000' });

        this.input.on('pointerdown', () =>
        {

            text.setText('');

        });

        sprite.on('pointerdown', (pointer, x, y, event) =>
        {

            text.setText('Sprite Alpha clicked');

            event.stopPropagation();

        });
    }
}

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

const game = new Phaser.Game(config);

Суть Pixel Perfect

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

Опция pixelPerfect: true меняет это поведение. Она включает проверку альфа-канала конкретного кадра (frame) текстуры в точке клика. Если альфа-канал пикселя равен 0 (полностью прозрачный), событие не срабатывает. Это позволяет сделать кликабельной только непрозрачную часть изображения.

const sprite = this.add.sprite(400, 300, 'megaset', 'mask-test2').setInteractive({ pixelPerfect: true });

Загрузка ресурсов и настройка сцены

В примере используется атлас текстур — эффективный способ хранения множества изображений в одном файле. Метод this.load.atlas() загружает PNG-изображение и соответствующую ему JSON-карту с координатами кадров.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.atlas('megaset', 'assets/atlas/megaset-0.png', 'assets/atlas/megaset-0.json');
}

Конфигурация игры стандартна. Обратите внимание, что фон сцены (backgroundColor: '#efefef') светлый, чтобы черные пиксели спрайта были хорошо видны.

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

const game = new Phaser.Game(config);

Обработка событий ввода

В примере реализована простая демонстрация работы pixelPerfect. Создается текстовый элемент, который обнуляется при клике в любом месте сцены. Однако, если клик происходит по непрозражному (черному) пикселю спрайта, срабатывает его собственный обработчик, который выводит другое сообщение и останавливает дальнейшее распространение события с помощью event.stopPropagation().

this.input.on('pointerdown', () =>
{
    text.setText('');
});

sprite.on('pointerdown', (pointer, x, y, event) =>
{
    text.setText('Sprite Alpha clicked');
    event.stopPropagation();
});

Таким образом, при клике по прозрачной области спрайта (но в пределах его прямоугольника) сработает только первый обработчик, очищающий текст. Клик по черной области вызовет второй обработчик и покажет сообщение 'Sprite Alpha clicked'.

Важные нюансы и производительность

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

- **Используйте для ключевых объектов:** Лучше применять эту опцию для наиболее важных или небольших по размеру спрайтов. - **Альтернативы для сложных форм:** Для объектов очень сложной формы иногда эффективнее использовать несколько простых геометрических зон (setHitArea) или физические тела. - **Работает только с POINTER событиями:** Опция актуальна для событий мыши и касаний (pointerdown, pointerup, pointerover и т.д.).

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

Опция pixelPerfect — мощный инструмент для тонкой настройки интерактивности в Phaser. Она незаменима при создании интерфейсов со сложными иконками, интерактивных масок или игровых объектов, форма которых критична для геймплея (например, пазлы). **Идеи для экспериментов:** 1. Создайте спрайт-кнопку в виде звезды и сделайте ее отзывчивой только по контуру. 2. Реализуйте механику "вырезания" объекта из фона, где кликабельна только его внутренняя часть. 3. Сравните производительность: добавьте 50 интерактивных спрайтов с pixelPerfect и без, перемещая курсор над ними.