О чем этот пример
Работа с геометрией — фундаментальная часть геймдева, будь то расчёт зон коллизии, определение границ объекта или генерация уровня. Ручной расчёт bounding box для набора точек — рутина, подверженная ошибкам. Встроенный метод Phaser.Geom.Rectangle.FromPoints автоматически создаёт минимальный прямоугольник, охватывающий все переданные точки, избавляя вас от лишнего кода и потенциальных багов. Эта статья на практическом примере покажет, как использовать этот метод для интерактивного создания прямоугольников прямо в игре. Вы научитесь динамически обрабатывать пользовательский ввод, работать с гибкими структурами данных и визуализировать результат, что пригодится при создании редакторов, инструментов отладки или игровой механики, основанной на выделении областей.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create ()
{
const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0x00aa00} });
// we can use either 2 dimensional array, or objects with x/y properties (or mix)
const points = [
[ 350, 250 ],
{ x: 450, y: 350 }
];
let rect;
this.input.on('pointerdown', pointer =>
{
points.push(pointer.position.clone());
redraw();
});
redraw();
function redraw ()
{
graphics.clear();
for (let i = 0; i < points.length; i++)
{
const p = points[i];
if (Array.isArray(p))
{
graphics.fillCircle(p[0], p[1], 4);
}
else
{
graphics.fillCircle(p.x, p.y, 4);
}
}
rect = Phaser.Geom.Rectangle.FromPoints(points, rect);
graphics.strokeRectShape(rect);
}
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Основа сцены и визуализация
Вся логика примера размещена в методе create сцены. Первым делом создаётся объект Graphics — мощный инструмент Phaser для рисования примитивов (линий, фигур, окружностей) напрямую на канвасе.
const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x0000aa }, fillStyle: { color: 0x00aa00} });
Здесь мы настраиваем его сразу: синяя обводка (lineStyle) для контуров и зелёная заливка (fillStyle) для точек. Далее объявляется массив points, который будет хранить координаты. Важный момент — метод FromPoints принимает гибкий формат данных: можно использовать как массивы вида [x, y], так и объекты вида {x, y}.
const points = [
[ 350, 250 ],
{ x: 450, y: 350 }
];
Обработка ввода и динамическое обновление
Чтобы сделать пример интерактивным, мы подписываемся на событие нажатия указателя (pointerdown). Каждый клик добавляет в массив points копию позиции курсора.
this.input.on('pointerdown', pointer => {
points.push(pointer.position.clone());
redraw();
});
Обратите внимание на использование .clone(). Позиция pointer.position — это объект Vector2, который может изменяться внутренними системами Phaser. Клонирование создаёт независимую копию, гарантируя, что наши сохранённые координаты останутся неизменными. После каждого добавления точки вызывается функция redraw() для перерисовки сцены.
Функция перерисовки: точки и прямоугольник
Функция redraw() — сердце примера. Она очищает предыдущие рисунки, отрисовывает все текущие точки и вычисляет новый ограничивающий прямоугольник.
Сначала мы проходим по массиву points. Так как формат точек может быть разным, используется проверка Array.isArray(p) для корректного доступа к координатам.
graphics.clear();
for (let i = 0; i < points.length; i++) {
const p = points[i];
if (Array.isArray(p)) {
graphics.fillCircle(p[0], p[1], 4);
} else {
graphics.fillCircle(p.x, p.y, 4);
}
}
Затем происходит магия — вызов Phaser.Geom.Rectangle.FromPoints. Метод принимает массив точек и опционально существующий объект прямоугольника.
rect = Phaser.Geom.Rectangle.FromPoints(points, rect);
Если передать вторым аргументом существующий объект rect (как в нашем коде), метод не создаст новый объект, а обновит координаты переданного. Это хорошая практика для оптимизации, позволяющая избежать лишних созданий объектов в цикле. Полученный прямоугольник отрисовывается с помощью graphics.strokeRectShape(rect).
Конфигурация и запуск игры
Код завершается стандартной для Phaser 3 конфигурацией игры. Мы задаём размеры холста, указываем тип рендерера (Phaser.AUTO выбирает между WebGL и Canvas) и передаём класс нашей сцены.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
После создания экземпляра Game Phaser автоматически инициализирует рендерер, системы ввода и вызовет жизненный цикл сцены, начиная с create.
Что попробовать дальше
Метод Phaser.Geom.Rectangle.FromPoints — это элегантное и производительное решение для работы с геометрическими границами. Он абстрагирует ручные вычисления минимумов и максимумов, предоставляя готовый результат.
Для экспериментов попробуйте
- Добавить очистку массива точек по нажатию клавиши
- Реализовать перетаскивание точек для изменения прямоугольника в реальном времени
- Использовать полученный
rectдля создания спрайта или зоны физического столкновения (this.physics.add.existing). Это отличный старт для создания собственных инструментов размещения объектов на карте
