О чем этот пример
При разработке игр часто нужно, чтобы объект двигался по идеальной окружности — будь то вращение спутника вокруг планеты, траектория пули или орбитальная камера. Вручную рассчитывать координаты через синусы и косинусы каждый раз неудобно. Phaser предоставляет для этой задачи готовый и точный метод. В этой статье мы разберем, как с помощью `Phaser.Geom.Circle.CircumferencePoint` заставить объект плавно перемещаться по краю круга, и как это можно применить в ваших проектах.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
a = 0;
point;
circle;
graphics;
create ()
{
this.graphics = this.add.graphics({ fillStyle: { color: 0x00ff00 } });
this.circle = new Phaser.Geom.Circle(400, 300, 150);
this.point = new Phaser.Geom.Rectangle(0, 0, 8, 8);
}
update ()
{
this.a += 0.04;
if (this.a >= Phaser.Math.PI2)
{
this.a -= Phaser.Math.PI2;
}
Phaser.Geom.Circle.CircumferencePoint(this.circle, this.a, this.point);
this.graphics.clear();
this.graphics.fillRect(this.point.x - 4, this.point.y - 4, 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.add.graphics({ fillStyle: { color: 0x00ff00 } });
Здесь мы создаем объект Graphics для отрисовки. Мы задаем ему зеленый цвет заливки (0x00ff00), который будет использоваться для нашего движущегося объекта.
this.circle = new Phaser.Geom.Circle(400, 300, 150);
this.point = new Phaser.Geom.Rectangle(0, 0, 8, 8);
Создаем геометрическое представление круга с центром в точке (400, 300) и радиусом 150 пикселей. Объект this.point — это не точка, а прямоугольник (Rectangle). Почему? Потому что метод CircumferencePoint будет записывать результат (координаты X и Y) в свойства .x и .y переданного ему объекта. Удобно использовать Rectangle или Circle, так как они уже имеют эти свойства. Мы инициализируем его с нулевыми координатами и размером 8x8 пикселя — это будет размер нашего маркера на экране.
Магия метода CircumferencePoint
Вся логика движения происходит в методе update(). Ключевую роль играет статический метод Phaser.Geom.Circle.CircumferencePoint.
this.a += 0.04;
if (this.a >= Phaser.Math.PI2) {
this.a -= Phaser.Math.PI2;
}
Переменная this.a — это наш угол в радианах. Каждый кадр мы увеличиваем его на 0.04, создавая плавное изменение. Phaser.Math.PI2 — это константа, равная 2 * PI (примерно 6.283). Когда угол достигает полного круга, мы вычитаем PI2, чтобы сбросить его, предотвращая переполнение и бесконечный рост.
Phaser.Geom.Circle.CircumferencePoint(this.circle, this.a, this.point);
Это сердце примера. Метод принимает три аргумента:
1. Объект круга (`this.circle`), по окружности которого мы движемся.
2. Угол в радианах (`this.a`), определяющий текущую позицию на окружности (0 радиан соответствует точке справа от центра).
3. Объект (`this.point`), в свойства `.x` и `.y` которого будут записаны рассчитанные координаты точки на окружности.
Метод не создает новый объект, а модифицирует переданный, что эффективно с точки зрения производительности.
Визуализация результата
После расчета координат нужно их отрисовать.
this.graphics.clear();
this.graphics.fillRect(this.point.x - 4, this.point.y - 4, this.point.width, this.point.height);
Поскольку update() вызывается каждый кадр, мы сначала очищаем холст graphics от старого кадра с помощью clear(). Затем рисуем зеленый квадрат. Мы используем рассчитанные this.point.x и this.point.y как центр нашего квадрата. Вычитание 4 пикселя (this.point.width / 2) необходимо, чтобы квадрат размером 8x8 был отцентрирован относительно полученной точки на окружности. В результате мы видим плавно движущийся по кругу зеленый маркер.
Практическое применение в играх
Этот паттерн полезен не только для отрисовки точек. Вы можете применить его к любому игровому объекту (Sprite, Image).
// В create()
this.satellite = this.physics.add.image(400 + 150, 300, 'satellite');
this.circle = new Phaser.Geom.Circle(400, 300, 150);
this.angle = 0;
// В update()
this.angle += 0.01;
const position = new Phaser.Geom.Point();
Phaser.Geom.Circle.CircumferencePoint(this.circle, this.angle, position);
this.satellite.setPosition(position.x, position.y);
Таким образом, спрайт satellite будет вращаться вокруг точки (400, 300). Вы можете менять радиус и центр окружности динамически, создавая сложные орбитальные движения, или привязать к этому движению камеру для кругового обзора сцены.
Что попробовать дальше
Метод Phaser.Geom.Circle.CircumferencePoint — это чистый и производительный способ получить координаты точки на окружности. Он избавляет от ручных тригонометрических расчетов и легко интегрируется в игровую логику. Для экспериментов попробуйте: изменить скорость и направление вращения; привязать к движущейся точке луч или частицу (Emitter); использовать несколько точек для создания вращающихся паттернов атак; комбинировать движение по кругу с другими типами движения для создания сложных траекторий (например, по спирали).
