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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    points;
    lines;
    graphics;

    create ()
    {
        this.graphics = this.add.graphics({ lineStyle: { width: 4, color: 0xaa00aa }, fillStyle: { color: 0x0000aa } });

        this.lines = [
            new Phaser.Geom.Line(200, 400, 400, 400),
            new Phaser.Geom.Line(400, 400, 600, 400),
            new Phaser.Geom.Line(300, 100, 500, 100),
            new Phaser.Geom.Line(700, 200, 700, 400)
        ];

        this.points = [
            this.lines[0].getPointA(),
            this.lines[1].getPointB(),
            Phaser.Geom.Line.GetMidPoint(this.lines[2]),
            { x: 400, y: 300}
        ];
    }

    update ()
    {

        this.graphics.clear();

        for (let i = 0; i < this.lines.length; i++)
        {
            Phaser.Geom.Line.RotateAroundPoint(this.lines[i], this.points[i], 0.02);

            this.graphics.strokeLineShape(this.lines[i]);

            this.graphics.fillPointShape(this.points[i], 10);
        }
    }
}

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

const game = new Phaser.Game(config);

Сцена и хранение данных

В классе сцены Example объявлены три свойства для хранения состояния: points (массив точек вращения), lines (массив геометрических линий) и graphics (объект для рисования).

В методе create() инициализируется объект Graphics с заданными стилями линии и заливки. Затем создаются четыре линии (Phaser.Geom.Line), заданные координатами начальной и конечной точек. После этого формируется массив точек вращения. Для первых двух линий точки берутся напрямую из их концов с помощью методов getPointA() и getPointB(). Для третьей линии используется статический метод Phaser.Geom.Line.GetMidPoint() для получения центральной точки. Четвертая точка задана вручную как объект с координатами { x: 400, y: 300 }.

this.graphics = this.add.graphics({ lineStyle: { width: 4, color: 0xaa00aa }, fillStyle: { color: 0x0000aa } });

this.lines = [
    new Phaser.Geom.Line(200, 400, 400, 400),
    new Phaser.Geom.Line(400, 400, 600, 400),
    new Phaser.Geom.Line(300, 100, 500, 100),
    new Phaser.Geom.Line(700, 200, 700, 400)
];

this.points = [
    this.lines[0].getPointA(),
    this.lines[1].getPointB(),
    Phaser.Geom.Line.GetMidPoint(this.lines[2]),
    { x: 400, y: 300}
];

Цикл обновления и вращение

Метод update() выполняется каждый кадр. Первым делом очищается холст отрисовки с помощью this.graphics.clear(), чтобы анимация была плавной, без наложения старых кадров.

Далее в цикле for происходит основная логика. Для каждой пары "линия-точка" вызывается статический метод Phaser.Geom.Line.RotateAroundPoint(). Он принимает три аргумента: саму линию (объект, который будет изменен), точку вращения и угол поворота в радианах. В данном примере угол фиксированный — 0.02 радиана за кадр, что создает непрерывное вращение. Этот метод модифицирует координаты начальной и конечной точек линии, поворачивая ее вокруг заданной точки.

for (let i = 0; i < this.lines.length; i++)
{
    Phaser.Geom.Line.RotateAroundPoint(this.lines[i], this.points[i], 0.02);
    this.graphics.strokeLineShape(this.lines[i]);
    this.graphics.fillPointShape(this.points[i], 10);
}

Визуализация линий и точек

После вращения линии необходимо отрисовать. Для этого используется метод this.graphics.strokeLineShape(), который принимает объект линии и рисует ее контур согласно стилю, заданному при создании Graphics (фиолетовая линия толщиной 4 пикселя).

Чтобы точка вращения была видимой, она отрисовывается с помощью this.graphics.fillPointShape(). Этот метод принимает объект точки (или любой объект со свойствами `xиy) и радиус заливки (в примере — 10 пикселей). Точка заливается синим цветом, определенным вfillStyle`. Это позволяет наглядно видеть, вокруг какого центра происходит вращение каждой линии.

Итог: каждый кадр линия поворачивается, перерисовывается, и отображается ее точка-ось.

Конфигурация и запуск игры

Код завершается стандартной для Phaser 3 конфигурацией игры. В объекте config задаются размеры холста (800x600), автоматический выбор рендерера (Phaser.AUTO), ID родительского HTML-элемента и класс основной сцены.

Экземпляр игры создается с помощью new Phaser.Game(config), что инициирует запуск цикла рендеринга и вызов методов create() и update() нашей сцены.

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

const game = new Phaser.Game(config);

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

Метод Phaser.Geom.Line.RotateAroundPoint предоставляет простой способ анимировать геометрию. Вы можете экспериментировать: изменять скорость вращения в зависимости от времени или ввода игрока, вращать линии вокруг движущихся точек (например, следящих за курсором), комбинировать вращение нескольких линий для создания сложных механизмов или использовать этот принцип для вращения спрайтов и графических объектов, предварительно получая их границы в виде линий.