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

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

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


var config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: {
        preload: preload,
        create: create
    }
};

var game = new Phaser.Game(config);

function preload ()
{
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('fork', 'assets/sprites/fork.png');
}

function create ()
{
    //  So we can see our zone
    var r2 = this.add.rectangle(400, 300, 300, 150, 0x9966ff).setAngle(40);

    var fork = this.add.image(1024, 600, 'fork').setOrigin(0.5, 0).setAngle(-20);

    var zone1 = this.add.zone(400, 300).setSize(300, 150).setAngle(40).setInteractive();

    this.input.on('gameobjectdown', function (pointer, gameObject) {

        fork.x = pointer.x;
        fork.y = pointer.y;

    });
}

Подготовка сцены и создание визуала

В примере создается базовая сцена с двумя объектами: прямоугольником и изображением. Прямоугольник служит лишь визуальным ориентиром для зоны.

var r2 = this.add.rectangle(400, 300, 300, 150, 0x9966ff).setAngle(40);

Здесь setAngle(40) поворачивает прямоугольник на 40 градусов по часовой стрелке. Это чисто графическая операция.

Изображение вилки (fork) загружается и позиционируется за пределами экрана, также с поворотом в -20 градусов.

var fork = this.add.image(1024, 600, 'fork').setOrigin(0.5, 0).setAngle(-20);

Установка setOrigin(0.5, 0) смещает точку вращения и позиционирования к верхней середине спрайта.

Создание интерактивной зоны

Ключевой объект — Phaser.GameObjects.Zone. Это невидимый игровой объект, предназначенный для обработки событий ввода.

var zone1 = this.add.zone(400, 300).setSize(300, 150).setAngle(40).setInteractive();

Методы настройки зоны: - setSize(300, 150) — задает ее размеры. - setAngle(40) — **пытается** задать угол поворота. - setInteractive() — активирует обработку событий ввода (кликов, наведений).

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

Проблема: метод `setAngle()` для Zone

Здесь и кроется суть примера. В отличие от Phaser.GameObjects.Rectangle или Image, у объекта Zone **нет визуального представления**. Метод setAngle() существует в его API, но он **не влияет на форму или положение хитбокса** (области взаимодействия).

Хитбокс зоны остается простым неповернутым прямоугольником, описываемым методом setSize(). Он не вращается вместе с визуальным индикатором (прямоугольником r2).

Проверьте это сами: кликайте вокруг видимого повернутого фиолетового прямоугольника. Перемещаться будет только вилка, и область клика будет строго прямоугольной, ориентированной по осям мира.

Обработка клика и демонстрация

В сцене слушается событие gameobjectdown, которое срабатывает при клике на любой интерактивный объект (в нашем случае — на зону zone1).

this.input.on('gameobjectdown', function (pointer, gameObject) {
    fork.x = pointer.x;
    fork.y = pointer.y;
});

Функция-обработчик перемещает изображение вилки в координаты клика (pointer.x, pointer.y). Это наглядно показывает, где именно система «видит» зону. Вы увидите, что вилка перемещается только при клике внутри неповернутого прямоугольника, а не внутри повернутого фиолетового контура.

Как создать повернутую зону взаимодействия?

Если вам необходима именно повернутая область для ввода, используйте другие объекты:

1. **Повернутый Rectangle с setInteractive():** Он имеет и визуал, и корректно повернутый хитбокс.

var interactiveRect = this.add.rectangle(400, 300, 300, 150, 0x9966ff).setAngle(40).setInteractive();

2. **Использование setHitArea для кастомной геометрии:** Для сложных форм можно определить полигональную область.

zone.setInteractive({ hitArea: myPolygon, hitAreaCallback: Phaser.Geom.Polygon.Contains });

Для Zone же основное назначение — логические, невидимые и обычно не вращающиеся области на сцене (например, триггеры входа в комнату).

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

Метод setAngle() объекта Zone не изменяет его область взаимодействия — она всегда остается axis-aligned (выровненной по осям) прямоугольной областью, заданной setSize(). Для создания интерактивных повернутых элементов используйте графические объекты (Rectangle, Image, Sprite) с включенным setInteractive(). Поэкспериментируйте: замените Zone на Rectangle в примере и убедитесь, что клик теперь корректно работает в повернутых границах.