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

В игровой разработке часто требуется работать с геометрией: рассчитывать траектории, области поражения или точки спавна объектов. Одна из полезных, но неочевидных операций — нахождение центра треугольника. В отличие от простого среднего арифметического, инцентр (incenter) — это точка, равноудалённая от всех сторон фигуры. В этой статье разберём, как использовать `Phaser.Geom.Triangle.InCenter()` для точных геометрических расчётов в вашей игре, например, для размещения объекта в самом "безопасном" месте зоны или для построения AI, который обходит углы.

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

Живой запуск

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

Исходный код


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

        //  Create a random triangle

        const x1 = Phaser.Math.Between(100, 700);
        const y1 = Phaser.Math.Between(50, 550);

        const x2 = Phaser.Math.Between(100, 700);
        const y2 = Phaser.Math.Between(50, 550);

        const x3 = Phaser.Math.Between(100, 700);
        const y3 = Phaser.Math.Between(50, 550);

        const triangle = new Phaser.Geom.Triangle(x1, y1, x2, y2, x3, y3);

        graphics.strokeTriangleShape(triangle);

        //  Get the inCenter of the triangle

        const incenter = Phaser.Geom.Triangle.InCenter(triangle);

        //  Draw lines from each point of the triangle to the center

        graphics.lineStyle(1, 0x00ff00);

        graphics.lineBetween(x1, y1, incenter.x, incenter.y);
        graphics.lineBetween(x2, y2, incenter.x, incenter.y);
        graphics.lineBetween(x3, y3, incenter.x, incenter.y);

        //  Draw the center

        graphics.fillPointShape(incenter, 4);
    }
}

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

const game = new Phaser.Game(config);

Что такое инцентр треугольника?

Инцентр — это точка пересечения биссектрис всех трёх углов треугольника. Главное свойство: расстояния от инцентра до каждой из сторон фигуры равны. Это делает его идеальным кандидатом для размещения объекта, который должен находиться «внутри» зоны, не примыкая к краям.

В игровом контексте это может быть: * Точка для спавна босса в центре арены сложной формы. * Цель для камеры при обзоре треугольного участка карты. * Опорная точка для расчёта физических или визуальных эффектов.

Создаём случайный треугольник

Для демонстрации сначала нарисуем произвольный треугольник. В Phaser для этого используется класс Phaser.Geom.Triangle. Мы зададим три случайные вершины в пределах сцены с помощью Phaser.Math.Between.

const x1 = Phaser.Math.Between(100, 700);
const y1 = Phaser.Math.Between(50, 550);

const x2 = Phaser.Math.Between(100, 700);
const y2 = Phaser.Math.Between(50, 550);

const x3 = Phaser.Math.Between(100, 700);
const y3 = Phaser.Math.Between(50, 550);

const triangle = new Phaser.Geom.Triangle(x1, y1, x2, y2, x3, y3);

После создания объекта треугольника, его можно отрисовать с помощью Graphics API.

const graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 } });
graphics.strokeTriangleShape(triangle);

Вычисляем инцентр

Phaser предоставляет статический метод Phaser.Geom.Triangle.InCenter(). Он принимает объект треугольника в качестве единственного аргумента и возвращает объект точки (Phaser.Geom.Point) с координатами `xиy`.

const incenter = Phaser.Geom.Triangle.InCenter(triangle);

После этого вызова в переменной incenter хранятся точные координаты искомого центра. Это готовая точка для дальнейшего использования в логике игры.

Визуализируем результат

Чтобы наглядно убедиться, что точка найдена верно, нарисуем линии от вершин треугольника к инцентру и выделим саму точку.

Сначала меняем стиль линий и рисуем отрезки от каждой вершины до центра.

graphics.lineStyle(1, 0x00ff00);
graphics.lineBetween(x1, y1, incenter.x, incenter.y);
graphics.lineBetween(x2, y2, incenter.x, incenter.y);
graphics.lineBetween(x3, y3, incenter.x, incenter.y);

Затем меняем контекст заливки и рисуем саму точку инцентра.

graphics.fillStyle(0xffff00);
graphics.fillPointShape(incenter, 4);

Метод fillPointShape рисует закрашенный круг с центром в заданной точке. Второй аргумент (4) — это радиус точки в пикселях.

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

Как использовать этот расчёт в реальном проекте? Допустим, у вас есть зона в форме треугольника (например, безопасный сектор на карте). Вычислив её инцентр, вы можете разместить там важный объект — сундук, контрольную точку или NPC.

// Предположим, zoneTriangle — это Phaser.Geom.Triangle, описывающий зону
const safePoint = Phaser.Geom.Triangle.InCenter(zoneTriangle);

// Создаём спрайт объекта в найденной точке
this.physics.add.sprite(safePoint.x, safePoint.y, 'treasure');

Это гарантирует, что объект будет расположен геометрически центрально внутри области, а не в одном из её углов.

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

Метод Phaser.Geom.Triangle.InCenter() — это мощный и простой инструмент для точных пространственных расчётов. Он избавляет от необходимости писать сложную математику вручную. Для экспериментов попробуйте использовать инцентр в динамически меняющемся треугольнике (вершины которого движутся) или комбинируйте его с другими методами геометрии Phaser, например, для проверки, находится ли игрок ближе к центру зоны, чем к её границам.