О чем этот пример
Создание нестандартных форм и контуров — частая задача при разработке игр: от хитовых боксов сложных объектов до декоративных элементов интерфейса. Встроенный в Phaser класс `Phaser.Geom.Polygon` позволяет легко работать с многоугольниками любой формы. Эта статья на практическом примере покажет, как создать полигон по набору точек и отрисовать его на канвасе, что станет основой для более продвинутых механик, связанных с геометрией и коллизиями.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
create ()
{
const polygon = new Phaser.Geom.Polygon([
0, 143,
0, 92,
110, 40,
244, 4,
330, 0,
458, 12,
574, 18,
600, 79,
594, 153,
332, 152,
107, 157
]);
const graphics = this.add.graphics({ x: 100, y: 200 });
graphics.lineStyle(2, 0x00aa00);
graphics.beginPath();
graphics.moveTo(polygon.points[0].x, polygon.points[0].y);
for (let i = 1; i < polygon.points.length; i++)
{
graphics.lineTo(polygon.points[i].x, polygon.points[i].y);
}
graphics.closePath();
graphics.strokePath();
}
}
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание геометрии: объект Polygon
Всё начинается с определения формы. Класс Phaser.Geom.Polygon принимает в конструктор плоский массив чисел, где каждая пара значений представляет координату (x, y) вершины многоугольника. Важно помнить, что точки задаются в локальной системе координат самого полигона, а его положение в мире сцены будет задано позже.
const polygon = new Phaser.Geom.Polygon([
0, 143,
0, 92,
110, 40,
// ... остальные точки
107, 157
]);
В этом примере массив описывает сложную неправильную форму. Порядок перечисления точек имеет значение — они будут последовательно соединены линиями.
Подготовка графического контекста
Чтобы что-то нарисовать, нужен инструмент для рисования. В Phaser за это отвечает объект Graphics. Мы создаём его через this.add.graphics(). Передавая объект с параметрами `xиy`, мы задаём позицию начала отрисовки на сцене. Все последующие операции с этим графическим объектом будут вычисляться относительно этой точки.
const graphics = this.add.graphics({ x: 100, y: 200 });
Далее настраиваем стиль линии, которая будет обводить наш полигон. Метод lineStyle() принимает толщину линии и цвет в числовом формате (hex).
graphics.lineStyle(2, 0x00aa00);
Отрисовка контура по точкам
Отрисовка происходит в несколько этапов, имитируя работу с контекстом канваса. Сначала мы начинаем новый путь командой beginPath().
graphics.beginPath();
Затем перемещаем «виртуальное перо» к первой точке полигона, используя её координаты из свойства polygon.points. Это массив объектов со свойствами `xиy`.
graphics.moveTo(polygon.points[0].x, polygon.points[0].y);
В цикле мы проходим по всем остальным точкам полигона и командой lineTo() рисуем к ним линии от предыдущей позиции.
for (let i = 1; i < polygon.points.length; i++)
{
graphics.lineTo(polygon.points[i].x, polygon.points[i].y);
}
Чтобы фигура была замкнутой, вызываем closePath(). Эта команда автоматически рисует линию от последней точки обратно к первой. После этого команда strokePath() применяет ранее заданный стиль линии и выводит контур на экран.
graphics.closePath();
graphics.strokePath();
Сборка и запуск сцены
Код примера оформлен как отдельная сцена Example. Для её запуска необходимо создать конфигурационный объект игры (config), указав тип рендерера, размеры холста, родительский контейнер и класс сцены. Инициализация игры с этим конфигом запускает весь процесс.
const config = {
width: 800,
height: 600,
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
Вы освоили базовый, но мощный паттерн: создание геометрического объекта данных (Polygon) и его отдельную визуализацию через Graphics. Это разделение логики и отображения открывает много возможностей. Для экспериментов попробуйте: анимировать точки полигона, создав движущуюся фигуру; использовать метод polygon.contains(x, y) для проверки попадания курсора в сложную область; залить полигон цветом с помощью graphics.fillPath(); или привязать физическое тело к форме полигона для сложных коллизий.
