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

При создании игр часто требуется эффективно проверять пересечения объектов сложной формы. Функция `Phaser.Geom.Intersects.RectangleToValues()` предлагает оптимизированный способ проверки коллизии между прямоугольником и ограничивающей рамкой (AABB) любой другой геометрической фигуры. Эта техника полезна для создания упрощённых, но быстрых проверок столкновений, когда точность геометрического пересечения не критична, а производительность важна.

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

Живой запуск

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

Исходный код


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

        const rect = new Phaser.Geom.Rectangle(325, 250, 150, 100);
        const triangle = Phaser.Geom.Triangle.BuildEquilateral(200, 50, 200);
        const circle = new Phaser.Geom.Circle(600, 130, 80);
        const ellipse = new Phaser.Geom.Ellipse(200, 450, 150, 90);
        const line = new Phaser.Geom.Line(550, 400, 650, 550);

        const shapes = [ triangle, circle, ellipse, line ];

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

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

            redraw();
        });

        redraw();

        function redraw ()
        {
            graphics.clear();

            graphics.lineStyle(2, 0xaaaa00);

            graphics.strokeTriangleShape(triangle);
            graphics.strokeCircleShape(circle);
            graphics.strokeEllipseShape(ellipse);
            graphics.strokeLineShape(line);

            graphics.lineStyle(2, 0x0000aa);

            for (let i = 0; i < shapes.length; i++)
            {
                const shape = shapes[i];
                if (Phaser.Geom.Intersects.RectangleToValues(rect, shape.left, shape.right, shape.top, shape.bottom))
                {
                    graphics.lineStyle(2, 0xaa0000);
                    break;
                }
            }

            graphics.strokeRectShape(rect);
        }
    }
}

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

const game = new Phaser.Game(config);

Как работает RectangleToValues?

Метод Phaser.Geom.Intersects.RectangleToValues проверяет, пересекается ли прямоугольник с другой областью, заданной не геометрическим объектом, а отдельными числовыми значениями её границ.

Этот подход отличается от других функций пересечения, таких как RectangleToRectangle, которые принимают готовые геометрические объекты. RectangleToValues требует явной передачи левой (left), правой (right), верхней (top) и нижней (bottom) границ проверяемой области.

if (Phaser.Geom.Intersects.RectangleToValues(rectA, leftB, rightB, topB, bottomB)) {
    // Обнаружено пересечение
}

Такой дизайн позволяет использовать функцию для проверки пересечения с любой сущностью, у которой можно вычислить её ограничивающий прямоугольник (bounding box), даже если сама сущность не является объектом Phaser.Geom.

Разбор примера кода

В предоставленном примере создаётся несколько геометрических фигур: треугольник, круг, эллипс и линия. Прямоугольник управляется курсором мыши. Задача — определить, пересекается ли этот прямоугольник с любой из фигур.

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

const shapes = [ triangle, circle, ellipse, line ];
// ...
const shape = shapes[i];
if (Phaser.Geom.Intersects.RectangleToValues(rect, shape.left, shape.right, shape.top, shape.bottom))

Здесь shape.left, shape.right, shape.top, shape.bottom — это автоматически вычисляемые границы ограничивающего прямоугольника для каждой фигуры. Цикл проверяет пересечение управляемого прямоугольника с каждой из этих рамок.

Визуализация и логика отрисовки

Функция redraw() отвечает за очистку холста и отрисовку всех фигур. Изначально все фигуры и прямоугольник рисуются синим цветом (0x0000aa).

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

graphics.lineStyle(2, 0x0000aa); // Синий цвет по умолчанию
for (let i = 0; i < shapes.length; i++) {
    const shape = shapes[i];
    if (Phaser.Geom.Intersects.RectangleToValues(rect, shape.left, shape.right, shape.top, shape.bottom)) {
        graphics.lineStyle(2, 0xaa0000); // Меняем на красный при пересечении
        break;
    }
}
graphics.strokeRectShape(rect); // Прямоугольник рисуется цветом, установленным в цикле

Важно: вызов graphics.lineStyle() изменяет стиль для всех последующих операций рисования, поэтому он вызывается до strokeRectShape().

Оптимизация и практическое применение

Использование RectangleToValues вместо точных проверок (например, RectangleToCircle) — это классический приём оптимизации. Сначала выполняется быстрая и дешёвая проверка по ограничивающим прямоугольникам (AABB), и только если она срабатывает, можно запускать более точный и ресурсоёмкий алгоритм.

В играх это можно применять для: 1. **Широкой фазы (broad phase) обнаружения столкновений:** Быстро отфильтровать объекты, которые заведомо не пересекаются. 2. **Проверки видимости/попадания в UI-элементы:** Если интерфейс имеет сложную форму, но для кликов используется упрощённая прямоугольная область. 3. **Привязки к тайлу или ячейке сетки:** Определение, в какую грубую зону карты попал объект.

// Пример: быстрая проверка перед точной
function checkCollision(playerRect, complexSprite) {
    // 1. Быстрая проверка по bounding box
    const bounds = complexSprite.getBounds();
    if (!Phaser.Geom.Intersects.RectangleToValues(playerRect, bounds.x, bounds.right, bounds.y, bounds.bottom)) {
        return false; // Нет пересечения — выходим досрочно
    }
    // 2. Точная (и дорогая) проверка пиксельной маски
    return this.physics.collide(playerRect, complexSprite);
}

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

Метод RectangleToValues — это эффективный инструмент для грубых, но быстрых проверок пересечений, основанных на ограничивающих прямоугольниках. Он идеально подходит для начальной широкой фазы расчёта коллизий или для работы с объектами, у которых нет встроенного геометрического представления в Phaser. **Идеи для экспериментов:** 1. Модифицируйте пример, чтобы каждая фигура подсвечивалась красным индивидуально при пересечении с ней прямоугольника. 2. Реализуйте систему, где проверка по RectangleToValues используется для предварительного отбора, а затем для действительно пересекающихся объектов вызывается Phaser.Geom.Intersects.RectangleToCircle для точной проверки. 3. Используйте этот метод для создания простого редактора уровней, где можно перемещать объект и видеть, с какими областями карты он потенциально сталкивается.