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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    a = 0;
    point;
    circle;
    graphics;

    create ()
    {
        this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});

        this.circle = new Phaser.Geom.Circle(400, 300, 200);
        this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);
    }

    update ()
    {
        this.a += 0.005;

        if (this.a > 1)
        {
            this.a = 0;
        }

        this.circle.getPoint(this.a, this.point);

        this.graphics.clear();
        this.graphics.lineStyle(2, 0x00ff00);
        this.graphics.strokeCircleShape(this.circle);

        this.graphics.fillStyle(0xff00ff);
        this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание геометрических объектов

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

this.graphics — это холст для рисования примитивов. Мы задаем ему стили линии и заливки.

this.circle — экземпляр Phaser.Geom.Circle с центром в (400, 300) и радиусом 200 пикселей. Это наша траектория.

this.point — экземпляр Phaser.Geom.Rectangle. Хотя это прямоугольник, мы будем использовать его как контейнер для координат (x, y) точки на окружности. Его размеры (16x16) понадобятся позже для отрисовки.

this.graphics = this.add.graphics({ lineStyle: { width: 2, color: 0x00ff00 }, fillStyle: { color: 0xff0000 }});
this.circle = new Phaser.Geom.Circle(400, 300, 200);
this.point = new Phaser.Geom.Rectangle(0, 0, 16, 16);

Алгоритм движения: метод getPoint и параметр 'a'

Вся логика движения реализована в методе update(). Ключевую роль играет переменная this.a и метод getPoint.

Переменная this.a — это нормализованный параметр позиции на окружности. Ее значение плавно увеличивается от 0 до 1, а затем сбрасывается, создавая бесконечный цикл. Значение 0 соответствует точке на нулевом радиуне (справа от центра), 0.25 — сверху, 0.5 — слева, 0.75 — снизу.

Метод circle.getPoint(this.a, this.point) — сердце примера. Он вычисляет координаты точки на окружности для заданного параметра `aи записывает результат (x, y) в переданный объектthis.point`. Второй аргумент — это объект, который будет модифицирован, что позволяет избежать создания новых объектов в каждом кадре и оптимизирует производительность.

this.a += 0.005;
if (this.a > 1) {
    this.a = 0;
}
this.circle.getPoint(this.a, this.point);

Визуализация: отрисовка окружности и движущейся точки

После вычисления новой позиции точки, необходимо очистить холст и перерисовать сцену.

this.graphics.clear() — удаляет все, что было нарисовано в предыдущем кадре.

Затем устанавливается стиль линии и рисуется контур нашей окружности с помощью graphics.strokeCircleShape.

Наконец, меняется стиль заливки на розовый (0xff00ff), и рисуется квадрат в качестве движущейся точки. Важный момент: координаты прямоугольника this.point теперь содержат центр искомой точки на окружности. Чтобы квадрат размером 16x16 был отцентрирован на этой точке, мы рисуем его со смещением на половину его ширины и высоты (x - 8, y - 8).

this.graphics.clear();
this.graphics.lineStyle(2, 0x00ff00);
this.graphics.strokeCircleShape(this.circle);

this.graphics.fillStyle(0xff00ff);
this.graphics.fillRect(this.point.x - 8, this.point.y - 8, this.point.width, this.point.height);

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

Код завершается стандартной для Phaser конфигурацией и созданием экземпляра игры.

В объекте config задаются размеры холста (800x600), указывается автоматический выбор рендерера (Phaser.AUTO) и класс нашей сцены Example.

Создание экземпляра Phaser.Game с этой конфигурацией запускает игровой цикл.

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

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

Метод Phaser.Geom.Circle.getPoint предоставляет простой и производительный способ вычисления любой точки на окружности. Вместо ручных расчетов с помощью Math.sin и Math.cos вы получаете готовое решение, которое можно использовать для движения спрайтов, частиц или камеры. Идеи для экспериментов: 1. Замените прямоугольник this.point на Phaser.GameObjects.Sprite и двигайте его, используя вычисленные координаты. 2. Измените скорость движения, регулируя шаг инкремента переменной `a(например,0.01или0.001`). 3. Используйте несколько объектов с разным начальным значением `a`, чтобы создать эффект «орбитальной» группы. 4. Примените этот же принцип к другим геометрическим объектам Phaser, например, Phaser.Geom.Ellipse.getPoint для движения по эллиптической траектории.