О чем этот пример
При создании игр часто требуется эффективно проверять пересечения объектов сложной формы. Функция `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. Используйте этот метод для создания простого редактора уровней, где можно перемещать объект и видеть, с какими областями карты он потенциально сталкивается.
