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

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

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

    create ()
    {
        const sprite = this.add.sprite(400, 300, 'ball').setScale(2);

        //  The circle x/y relates to the top-left of the sprite.
        //  So if you want the circle positioned in the middle then you need to offset it by half the sprite width/height:
        const shape = new Phaser.Geom.Circle(46, 45, 45);

        sprite.setInteractive(shape, Phaser.Geom.Circle.Contains);

        //  Input Event listeners

        sprite.on('pointerover', () =>
        {

            sprite.setTint(0x7878ff);

        });

        sprite.on('pointerout', () =>
        {

            sprite.clearTint();

        });
    }
}

const config = {
    type: Phaser.WEBGL,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    pixelArt: true,
    scene: Example
};

const game = new Phaser.Game(config);

Проблема стандартного хитбокса

По умолчанию, при вызове setInteractive() без параметров, Phaser назначает спрайту интерактивную область в виде прямоугольника, совпадающего с его границами (bounding box). Для круглого спрайта, такого как мяч, это означает, что игрок может активировать событие наведения (pointerover), даже если курсор находится в "пустом" углу спрайта.

Это создает несоответствие между видимой графикой и областью взаимодействия, что может раздражать пользователя.

Создание геометрической области

Phaser предоставляет систему геометрии, которую можно использовать для определения точной формы. Вместо прямоугольника мы создадим круг (Phaser.Geom.Circle). Конструктор круга принимает три аргумента: координаты X и Y центра, и радиус.

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

const shape = new Phaser.Geom.Circle(46, 45, 45);

В данном примере спрайт увеличен в 2 раза (setScale(2)), а исходное изображение имеет размер 92x90 пикселей. Поэтому, чтобы разместить круг по центру увеличенного спрайта, его центр смещается на половину от исходных размеров: 92/2=46 и 90/2=45. Радиус 45 пикселей почти достигает краев изображения.

Назначение области спрайту

Метод setInteractive() может принимать два параметра: объект геометрии (или конфигурацию) и функцию проверки на вхождение точки в эту геометрию. Phaser имеет встроенные функции для стандартных фигур.

sprite.setInteractive(shape, Phaser.Geom.Circle.Contains);

Здесь мы передаем созданный круг и ссылку на статический метод Phaser.Geom.Circle.Contains. Этот метод будет автоматически вызываться движком ввода для проверки, находится ли курсор внутри нашей круглой области.

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

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

sprite.on('pointerover', () => {
    sprite.setTint(0x7878ff); // Накладываем синий оттенок
});

sprite.on('pointerout', () => {
    sprite.clearTint(); // Убираем оттенок
});

Теперь подсветка будет включаться и выключаться только когда курсор находится в пределах заданного круга, а не прямоугольной рамки спрайта.

Расчет координат для других форм

Подход одинаков для любой геометрии: Phaser.Geom.Rectangle, Phaser.Geom.Ellipse, Phaser.Geom.Polygon и других. Ключевой момент — правильно рассчитать координаты вершин или центра фигуры относительно левого верхнего угла спрайта.

Для полигона (Polygon) координаты точек задаются в массиве, где каждая точка — это объект { x, y } в локальной системе координат спрайта.

Функция проверки всегда соответствует типу фигуры: Phaser.Geom.Rectangle.Contains, Phaser.Geom.Ellipse.Contains, Phaser.Geom.Polygon.Contains и т.д.

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

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