О чем этот пример
При работе с геометрией в играх часто возникает задача определить границы произвольной формы. Например, для проверки видимости объекта, грубой проверки столкновений или оптимизации рендеринга. Phaser предоставляет удобный метод `Phaser.Geom.Polygon.GetAABB()` для вычисления Axis-Aligned Bounding Box (AABB) — ограничивающего прямоугольника, выровненного по осям координат, для любого полигона. Эта статья на практическом примере покажет, как в реальном времени получать AABB для динамического полигона, вершины которого можно перемещать и добавлять. Вы научитесь эффективно работать с геометрией для создания интерактивных игровых механик.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create ()
{
const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0xaa6622 } });
const points = [
new Phaser.Math.Vector2(220, 450),
new Phaser.Math.Vector2(200, 200),
new Phaser.Math.Vector2(400, 300)
];
const polygon = new Phaser.Geom.Polygon(points);
const aabb = Phaser.Geom.Polygon.GetAABB(polygon);
this.input.on('pointermove', pointer =>
{
points[points.length - 1].copy(pointer);
polygon.setTo(points);
Phaser.Geom.Polygon.GetAABB(polygon, aabb);
redraw();
});
this.input.on('pointerdown', pointer =>
{
points.push(points[points.length - 1].clone());
});
redraw();
function redraw ()
{
graphics.clear();
graphics.strokePoints(polygon.points, true);
graphics.lineStyle(2, 0x0000aa);
graphics.strokeRectShape(aabb);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что такое AABB и зачем он нужен?
Axis-Aligned Bounding Box (AABB) — это минимальный прямоугольник, стороны которого параллельны осям X и Y, полностью содержащий внутри себя заданную геометрическую фигуру. Он является фундаментальной концепцией в компьютерной графике и игровой физике.
Основные применения в играх: * **Оптимизация столкновений:** Проверка пересечения AABB двух объектов выполняется гораздо быстрее, чем проверка столкновения сложных полигонов. Это идеальный первый, «грубый» проход. * **Определение видимости (Frustum Culling):** Камера может быстро отбросить объекты, чьи AABB находятся за пределами видимой области. * **Пространственное разбиение:** Используется в алгоритмах, таких как QuadTree или Grid, для эффективного поиска объектов в пространстве.
В Phaser AABB представлен объектом типа Phaser.Geom.Rectangle.
Создание полигона и вычисление AABB
В примере сначала создается полигон на основе массива точек (векторов). Затем для него вычисляется статический AABB. Ключевой метод — Phaser.Geom.Polygon.GetAABB(). Он может работать в двух режимах: создать новый объект прямоугольника или перезаписать существующий (что полезно для оптимизации, чтобы избежать создания новых объектов в цикле).
const points = [
new Phaser.Math.Vector2(220, 450),
new Phaser.Math.Vector2(200, 200),
new Phaser.Math.Vector2(400, 300)
];
const polygon = new Phaser.Geom.Polygon(points);
// Первый вызов: создаем новый объект AABB
const aabb = Phaser.Geom.Polygon.GetAABB(polygon);
Динамическое обновление и перерисовка
Интерактивность достигается за счет обработки событий указателя. При движении мыши (pointermove) последняя вершина полигона перемещается в позицию курсора. Важный момент: мы не создаем новый полигон каждый раз, а обновляем существующий с помощью метода polygon.setTo(). Это эффективнее.
Затем AABB пересчитывается. Обратите внимание на второй аргумент метода GetAABB — это уже существующий объект aabb, в который будет записан новый результат. Это предотвращает утечку памяти из-за постоянного создания объектов.
this.input.on('pointermove', pointer => {
// Перемещаем последнюю точку
points[points.length - 1].copy(pointer);
// Обновляем полигон новыми точками
polygon.setTo(points);
// Пересчитываем AABB, используя тот же объект 'aabb'
Phaser.Geom.Polygon.GetAABB(polygon, aabb);
redraw();
});
Добавление новых вершин и отрисовка
По клику мыши (pointerdown) в полигон добавляется новая вершина. Для этого в массив points клонируется последняя существующая точка. Клон создается, чтобы у новой точки была своя независимая ссылка.
Функция redraw() отвечает за визуализацию. Она очищает Graphics, рисует контур полигона методом strokePoints() и поверх него — синий прямоугольник AABB с помощью strokeRectShape().
this.input.on('pointerdown', pointer => {
// Добавляем новую точку, клонируя последнюю
points.push(points[points.length - 1].clone());
});
function redraw () {
graphics.clear();
// Рисуем полигон
graphics.strokePoints(polygon.points, true);
// Меняем стиль линии и рисуем AABB
graphics.lineStyle(2, 0x0000aa);
graphics.strokeRectShape(aabb);
}
Что попробовать дальше
Метод Phaser.Geom.Polygon.GetAABB() — это мощный и оптимизированный инструмент для работы с границами сложных форм. Используя перезапись существующего объекта прямоугольника, вы можете создавать высокопроизводительные интерактивные системы даже на мобильных устройствах.
**Идеи для экспериментов:**
1. Реализуйте простую проверку столкновений двух полигонов, сначала сравнив их AABB.
2. Создайте камеру, которая будет отсекать объекты за пределами экрана на основе их AABB.
3. Добавьте физическое тело (Physics Body) и свяжите его размеры с динамически обновляемым AABB вашего полигона для нетривиальной формы столкновений.
