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

В игровой разработке часто требуется проверять столкновения объектов. Напрямую использовать физические движки для сценариев логики интерфейса, триггеров зон или упрощённых вычислений не всегда эффективно. Работа с геометрическими фигурами через `Phaser.Geom` предоставляет быстрый и лёгкий способ для таких проверок без затрат на полноценную физику. В этой статье мы разберём, как определить область пересечения двух прямоугольников, что полезно для создания зон активации, подсветки выбранной области или нефизических коллизий.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics();

        const rectA = new Phaser.Geom.Rectangle(0, 0, 300, 100);
        const rectB = new Phaser.Geom.Rectangle(150, 300, 500, 150);
        const rectC = new Phaser.Geom.Rectangle();

        graphics.lineStyle(1, 0xff0000);
        graphics.strokeRectShape(rectA);

        graphics.lineStyle(1, 0x00ff00);
        graphics.strokeRectShape(rectB);

        this.input.on('pointermove', pointer =>
        {

            graphics.clear();

            Phaser.Geom.Rectangle.CenterOn(rectA, pointer.x, pointer.y);

            Phaser.Geom.Rectangle.Intersection(rectA, rectB, rectC);

            graphics.lineStyle(1, 0xff0000);
            graphics.strokeRectShape(rectA);
        
            graphics.lineStyle(1, 0x00ff00);
            graphics.strokeRectShape(rectB);

            if (!rectC.isEmpty())
            {
                graphics.lineStyle(1, 0xffff00);
                graphics.strokeRectShape(rectC);
            }
        
        });
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание прямоугольников

В методе create() сцены мы сначала создаём объект Graphics для отрисовки фигур. Затем определяем два прямоугольника (rectA и rectB) и один пустой (rectC), который будет использоваться для результата.

Первый прямоугольник rectA изначально расположен в левом верхнем углу. Второй, rectB, находится ниже и правее. Третий, rectC, пока что пустой — его параметры будут вычислены позже.

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

const graphics = this.add.graphics();

const rectA = new Phaser.Geom.Rectangle(0, 0, 300, 100);
const rectB = new Phaser.Geom.Rectangle(150, 300, 500, 150);
const rectC = new Phaser.Geom.Rectangle();

graphics.lineStyle(1, 0xff0000);
graphics.strokeRectShape(rectA);

graphics.lineStyle(1, 0x00ff00);
graphics.strokeRectShape(rectB);

Обработка движения указателя и обновление позиции

Далее мы настраиваем обработчик события движения курсора мыши. При каждом движении указателя мы полностью очищаем холст graphics и заново перерисовываем фигуры с новыми параметрами.

Ключевое действие здесь — перемещение прямоугольника rectA в позицию курсора с помощью метода Phaser.Geom.Rectangle.CenterOn(). Это заставляет первый прямоугольник следовать за указателем мыши, что наглядно демонстрирует динамическое пересечение.

this.input.on('pointermove', pointer => {
    graphics.clear();
    Phaser.Geom.Rectangle.CenterOn(rectA, pointer.x, pointer.y);

Вычисление и отрисовка области пересечения

Сердце примера — вызов статического метода Phaser.Geom.Rectangle.Intersection(). Он принимает два исходных прямоугольника (rectA и rectB) и целевой прямоугольник (rectC), в который записывает результат. Если прямоугольники пересекаются, rectC получает координаты и размеры общей области. Если не пересекаются — он становится пустым.

После вычисления пересечения мы заново рисуем контуры исходных прямоугольников. Затем проверяем, не является ли rectC пустым, с помощью метода isEmpty(). Если пересечение существует, мы рисуем rectC жёлтым цветом поверх остальных.

Phaser.Geom.Rectangle.Intersection(rectA, rectB, rectC);

    graphics.lineStyle(1, 0xff0000);
    graphics.strokeRectShape(rectA);

    graphics.lineStyle(1, 0x00ff00);
    graphics.strokeRectShape(rectB);

    if (!rectC.isEmpty()) {
        graphics.lineStyle(1, 0xffff00);
        graphics.strokeRectShape(rectC);
    }
});

Конфигурация и запуск игры

Для запуска примера необходимо создать стандартную конфигурацию игры Phaser. В ней мы указываем размеры холста, тип рендерера и нашу сцену Example. После этого инстанциируем объект Game с этой конфигурацией.

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

const game = new Phaser.Game(config);

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

Использование Phaser.Geom.Rectangle.Intersection() — это эффективный способ для детекции пересечений прямоугольных областей в вашей игре. Этот подход идеален для создания невидимых триггерных зон, областей выбора или упрощённой логики столкновений, где полноценный физический движок был бы избыточен. **Идеи для экспериментов:** 1. Добавьте проверку пересечения для более чем двух прямоугольников. 2. Используйте результат пересечения (rectC) для активации игровых событий, например, показа подсказки или воспроизведения звука. 3. Попробуйте привязать прямоугольники не к курсору, а к движущимся игровым спрайтам, чтобы визуализировать их "хитбоксы".