О чем этот пример
Создание сложных и плавных траекторий движения — частый запрос в играх. Это может быть полёт снаряда, патрулирование врага или анимация меню. Вручную рассчитывать такие пути через координаты каждый кадр неэффективно. В Phaser есть встроенный инструмент — `Phaser.Curves.Path`. Он позволяет описать путь из линий и кривых, а затем легко получить любую точку на этом пути для перемещения объекта. В этой статье разберём пример, где красный шарик движется по гибридному пути: от прямой линии до сложной кривой Безье.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
graphics;
path;
follower;
create ()
{
this.graphics = this.add.graphics();
this.follower = { t: 0, vec: new Phaser.Math.Vector2() };
// Path starts at 100x100
this.path = new Phaser.Curves.Path(50, 500);
this.path.lineTo(150, 200);
// cubicBezierTo: function (x, y, control1X, control1Y, control2X, control2Y)
this.path.cubicBezierTo(400, 500, 200, 100, 400, 100);
this.tweens.add({
targets: this.follower,
t: 1,
ease: 'Sine.easeInOut',
duration: 4000,
yoyo: true,
repeat: -1
});
}
update ()
{
this.graphics.clear();
this.graphics.lineStyle(2, 0xffffff, 1);
this.path.draw(this.graphics);
this.path.getPoint(this.follower.t, this.follower.vec);
this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillCircle(this.follower.vec.x, this.follower.vec.y, 12);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание пути: Path, lineTo и cubicBezierTo
Вся логика пути инкапсулирована в объекте Phaser.Curves.Path. Он создаётся из начальной точки, а затем к нему последовательно добавляются сегменты.
this.path = new Phaser.Curves.Path(50, 500);
Здесь путь начнётся в точке с координатами (50, 500). Далее мы добавляем два сегмента. Первый — прямая линия до точки (150, 200).
this.path.lineTo(150, 200);
Второй сегмент — кубическая кривая Безье. Для её построения нужны координаты конечной точки и двух контрольных точек, которые "притягивают" кривую, задавая её форму.
this.path.cubicBezierTo(400, 500, 200, 100, 400, 100);
В этом вызове: (400, 500) — конечная точка кривой, (200, 100) — первая контрольная точка, (400, 100) — вторая контрольная точка. Путь теперь представляет собой непрерывную ломаную-кривую линию.
Анимируем движение по пути с помощью Tween
Чтобы двигать объект по пути, нам нужен параметр `t, изменяющийся от 0 до 1, где 0 — начало пути, а 1 — его конец. Вместо того чтобы вручную менять этот параметр вupdate`, мы используем систему твинов Phaser.
this.follower = { t: 0, vec: new Phaser.Math.Vector2() };
Мы создаём объект-последователь (follower), который хранит текущее положение на пути (`t) и вектор (vec) для расчёта координат. Затем настраиваем твин для плавного изменения свойстваt` этого объекта.
this.tweens.add({
targets: this.follower,
t: 1,
ease: 'Sine.easeInOut',
duration: 4000,
yoyo: true,
repeat: -1
});
Твин будет 4 секунды двигать `tот 0 до 1 с плавным ускорением и замедлением (Sine.easeInOut), затем проиграет анимацию в обратном порядке (yoyo: true) и будет повторяться бесконечно (repeat: -1`).
Визуализация: рисуем путь и объект каждый кадр
Логика отрисовки находится в методе update(), который вызывается на каждом кадре игры. Сначала мы очищаем старое изображение с помощью clear().
this.graphics.clear();
this.graphics.lineStyle(2, 0xffffff, 1);
Затем задаём стиль линии (толщина 2px, белый цвет) и рисуем весь путь методом draw().
this.path.draw(this.graphics);
Теперь нужно получить текущие координаты для нашего последователя. Метод getPoint вычисляет точку на пути для заданного значения `tи записывает результат в переданный векторthis.follower.vec`.
this.path.getPoint(this.follower.t, this.follower.vec);
Осталось нарисовать в этой позиции наш движущийся объект, например, красный круг.
this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillCircle(this.follower.vec.x, this.follower.vec.y, 12);
Что попробовать дальше
Класс Phaser.Curves.Path — мощный инструмент для декларативного описания траекторий. Вы комбинируете простые примитивы (lineTo, cubicBezierTo), а система сама рассчитывает плавное движение. Для экспериментов попробуйте: изменить контрольные точки кривой Безье, добавить больше сегментов lineTo, прицепить спрайт вместо круга или создать несколько независимых путей для группы объектов.
