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

Создание и динамическое изменение геометрических фигур — частая задача в игровой разработке, будь то зоны коллизий, области отрисовки или произвольные полигоны. В этом примере мы рассмотрим класс `Phaser.Geom.Polygon` и его метод `GetNumberArray`, который преобразует сложную структуру данных в простой массив чисел. Это полезно для передачи данных в другие системы, оптимизации или ручной отрисовки с помощью графического контекста. Мы создадим интерактивный многоугольник, вершины которого можно перемещать и добавлять в реальном времени.

Версия 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(420, 280),
            new Phaser.Math.Vector2(450, 250),
            new Phaser.Math.Vector2(470, 300)
        ];

        const polygon = new Phaser.Geom.Polygon(points);

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

            points[points.length - 1].copy(pointer);

            polygon.setTo(points);

            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);

            const numbers = Phaser.Geom.Polygon.GetNumberArray(polygon);

            graphics.beginPath();

            // draw as if x was y and y was x
            graphics.moveTo(numbers[1], numbers[0]);

            for (let i = 0; i < numbers.length; i += 2)
            {
                graphics.lineTo(numbers[i + 1], numbers[i]);
            }

            graphics.lineTo(numbers[1], numbers[0]);

            graphics.closePath();
            graphics.strokePath();
        }
    }
}

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

const game = new Phaser.Game(config);

Создание полигона из векторов

В основе примера лежит класс Phaser.Geom.Polygon. Он принимает массив точек для создания фигуры. Каждая точка — это экземпляр Phaser.Math.Vector2, что удобно для математических операций.

Инициализируем массив точек и создаём полигон.

const points = [
    new Phaser.Math.Vector2(420, 280),
    new Phaser.Math.Vector2(450, 250),
    new Phaser.Math.Vector2(470, 300)
];

const polygon = new Phaser.Geom.Polygon(points);

Динамическое обновление вершин

Чтобы сделать полигон интерактивным, мы навешиваем обработчики событий ввода. При движении указателя (pointermove) последняя вершина массива points копирует координаты курсора, а затем полигон полностью перестраивается методом setTo. При клике (pointerdown) в массив добавляется копия последней вершины, позволяя "зафиксировать" текущее положение и начать рисовать новую вершину с той же позиции.

this.input.on('pointermove', pointer => {
    points[points.length - 1].copy(pointer);
    polygon.setTo(points);
    redraw();
});

this.input.on('pointerdown', pointer => {
    points.push(points[points.length - 1].clone());
});

Преобразование в массив чисел

Ключевой метод в этом примере — Phaser.Geom.Polygon.GetNumberArray. Он извлекает все координаты вершин полигона и возвращает их в виде плоского одномерного массива чисел вида [x1, y1, x2, y2, ...]. Это низкоуровневое представление удобно для ручной передачи в другие API или для нестандартных операций с графикой.

Получаем массив и готовимся к отрисовке.

const numbers = Phaser.Geom.Polygon.GetNumberArray(polygon);

Отрисовка с инверсией координат

В примере происходит визуальная демонстрация работы с массивом numbers. Используя графический контекст (graphics), мы рисуем исходный полигон через strokePoints. Затем, для наглядности, рисуем второй контур, но с инверсией координат X и Y: берём numbers[i + 1] как X, а numbers[i] как Y. Это создаёт зеркальный эффект и показывает гибкость ручной работы с массивом.

Функция перерисовки очищает canvas и создаёт два контура.

function redraw ()
{
    graphics.clear();
    graphics.strokePoints(polygon.points, true);
    graphics.lineStyle(2, 0x0000aa);
    const numbers = Phaser.Geom.Polygon.GetNumberArray(polygon);
    graphics.beginPath();
    graphics.moveTo(numbers[1], numbers[0]);
    for (let i = 0; i < numbers.length; i += 2)
    {
        graphics.lineTo(numbers[i + 1], numbers[i]);
    }
    graphics.lineTo(numbers[1], numbers[0]);
    graphics.closePath();
    graphics.strokePath();
}

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

Метод GetNumberArray — это мост между высокоуровневым объектом Polygon и низкоуровневыми данными. Он полезен для сериализации фигур, передачи в WebGL-шейдеры или создания кастомных алгоритмов обработки. Для экспериментов попробуйте: сохранять массив numbers в localStorage, анимировать вершины через Tween, или использовать его для расчёта площади полигона. Инверсия координат в отрисовке — лишь один пример манипуляций с таким массивом.