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

При разработке игр часто требуется найти центр сложной фигуры или группы объектов для расчёта ударов, создания эффектов или AI. Встроенная функция `Phaser.Math.GetCentroid` мгновенно вычисляет геометрический центр (центроид) любого набора точек. Это избавляет от написания сложных математических расчётов и позволяет сосредоточиться на игровой логике. В этой статье мы разберём практический пример и покажем, как центроид может оживить вашу игру.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    create ()
    {
        const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x2266aa }, fillStyle: { color: 0x2266aa } });

        const points = [
            new Phaser.Math.Vector2(Math.random() * 300, Math.random() * 200),
            new Phaser.Math.Vector2(Math.random() * 400 + 400, Math.random() * 200),
            new Phaser.Math.Vector2(Math.random() * 400 + 400, Math.random() * 200 + 200),
            new Phaser.Math.Vector2(Math.random() * 400, Math.random() * 300 + 300),
            new Phaser.Math.Vector2(Math.random() * 400, Math.random() * 300 + 300)
        ];

        this.input.on('pointermove', pointer =>
        {
            points[0].copy(pointer);

            redraw();
        });

        redraw();

        function redraw ()
        {
            graphics.clear();

            graphics.strokePoints(points, true);

            const centroid = Phaser.Math.GetCentroid(points);

            graphics.fillPointShape(centroid, 20);

            graphics.lineStyle(1, 0x2266aa);

            for (let i = 0; i < points.length; i++)
            {
                graphics.lineBetween(points[i].x, points[i].y, centroid.x, centroid.y);
            }
        }
    }
}

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

const game = new Phaser.Game(config);

Что такое центроид и зачем он нужен?

Центроид — это средняя арифметическая позиция всех точек фигуры. Представьте, что вы размещаете одинаковые гирьки в каждой вершине многоугольника: точка, где эта конструкция будет балансировать, и есть центроид.

В играх центроид полезен для: - Определения центра массы объекта для реалистичной физики. - Привязки эффектов (взрыв, свечение) к центру группы спрайтов. - Нахождения усреднённой позиции для камеры или AI, следящей за несколькими целями.

Phaser предоставляет для этого готовую функцию Phaser.Math.GetCentroid, которая работает с массивом объектов Vector2.

Анализ примера: создание сцены и точек

Весь код выполняется внутри метода create сцены. Сначала создаётся объект graphics для рисования.

const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x2266aa }, fillStyle: { color: 0x2266aa } });

Затем определяется массив points, состоящий из пяти векторов (Phaser.Math.Vector2) со случайными координатами. Эти векторы представляют вершины нашей динамической фигуры.

const points = [
    new Phaser.Math.Vector2(Math.random() * 300, Math.random() * 200),
    new Phaser.Math.Vector2(Math.random() * 400 + 400, Math.random() * 200),
    new Phaser.Math.Vector2(Math.random() * 400 + 400, Math.random() * 200 + 200),
    new Phaser.Math.Vector2(Math.random() * 400, Math.random() * 300 + 300),
    new Phaser.Math.Vector2(Math.random() * 400, Math.random() * 300 + 300)
];

Первая точка в массиве привязана к движению курсора мыши с помощью слушателя события pointermove. Это делает фигуру интерактивной.

this.input.on('pointermove', pointer =>
{
    points[0].copy(pointer);
    redraw();
});

Магия одного вызова: расчёт центроида

Ключевая логика заключена в функции redraw. После очистки холста (graphics.clear()) она рисует контур фигуры по точкам.

Затем всего одним вызовом вычисляется центроид:

const centroid = Phaser.Math.GetCentroid(points);

Функция принимает массив точек и возвращает новый объект Vector2 — координаты центроида. Это мощный инструмент, скрывающий за собой все математические операции.

Визуализация результата

Чтобы результат был наглядным, пример не просто вычисляет центроид, но и отрисовывает его вместе с "лучами", соединяющими его с вершинами.

Сначала центроид рисуется как закрашенная точка:

graphics.fillPointShape(centroid, 20);

Затем стиль линии меняется, и в цикле рисуются соединительные линии:

graphics.lineStyle(1, 0x2266aa);
for (let i = 0; i < points.length; i++)
{
    graphics.lineBetween(points[i].x, points[i].y, centroid.x, centroid.y);
}

Такая визуализация помогает увидеть, как именно центроид связан с формой фигуры и как он перемещается при её изменении.

Практическое применение в играх

Вот несколько идей, как использовать центроид в реальном проекте:

1. **Групповой урон:** Если взрыв происходит в центроиде группы врагов, урон можно распределить правдоподобно.

// enemies - массив спрайтов с физическими телами
    const positions = enemies.map(e => new Phaser.Math.Vector2(e.x, e.y));
    const blastCenter = Phaser.Math.GetCentroid(positions);
    this.physics.add.explosion(blastCenter.x, blastCenter.y, 200);

2. **Фокусировка камеры:** Плавное движение камеры к центру массы выбранных юнитов. 3. **Создание сложных траекторий:** Центроид нескольких контрольных точек может задавать путь для патрулирования или красивых закруглённых движений.

Главное преимущество — не нужно вручную суммировать и делить координаты. Phaser делает это за вас.

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

Функция Phaser.Math.GetCentroid — это небольшой, но мощный инструмент для работы с геометрией в играх. Она мгновенно решает задачу нахождения центра, позволяя создавать более умные и визуально интересные механики. Поэкспериментируйте: привяжите центроид не к курсору, а к движущемуся спрайту-лидеру, используйте его для расчёта силы притяжения или создайте динамический интерфейс, который всегда указывает на центр группы выбранных объектов.