О чем этот пример
В игровом движке Phaser траектории движения объектов часто создаются из нескольких кривых. Метод `moveTo` класса `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() };
this.path = new Phaser.Curves.Path(300, 300);
this.path.circleTo(100);
// We can move the path to 500x300 without creating any extra duration
this.path.moveTo(500, 300);
// Rotate this circle so it completes the loop
this.path.circleTo(100, true, 180);
this.tweens.add({
targets: this.follower,
t: 1,
ease: 'Linear',
duration: 2000,
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);
Создание основы пути и объекта-преследователя
В методе create() сцены инициализируются ключевые объекты: графика для отрисовки, сам путь (Path) и объект-преследователь (follower).
Объект follower — это простой JavaScript-объект, который будет хранить текущую позицию на пути (от 0 до 1) и вектор для вычисления координат. Вектор создается один раз для оптимизации, чтобы избежать создания новых объектов в каждом кадре.
this.graphics = this.add.graphics();
this.follower = { t: 0, vec: new Phaser.Math.Vector2() };
this.path = new Phaser.Curves.Path(300, 300);
Рисование первой кривой и магия метода moveTo
Начальная точка пути задается в конструкторе Path(300, 300). Метод circleTo добавляет к пути круговую кривую заданного радиуса, начиная от текущей позиции.
Затем вызывается ключевой метод path.moveTo(500, 300). Он не рисует никакой линии или кривой. Вместо этого он мгновенно перемещает внутреннюю 'текущую точку' пути на новые координаты. Это как поднять перо на графическом планшете, переместить его и начать рисовать с нового места. Благодаря этому следующий вызов circleTo нарисует новый круг, не связанный линией с предыдущим.
this.path.circleTo(100);
this.path.moveTo(500, 300);
this.path.circleTo(100, true, 180);
Второй круг рисуется с параметрами, которые переворачивают его (true) и задают начальный угол в 180 градусов, формируя петлю.
Анимация движения по составному пути
Для анимации движения объекта по всему пути используется твин Phaser. Он плавно изменяет свойство `tобъектаfollower` от 0 до 1 за 2 секунды и повторяется бесконечно.
Важно понимать, что значение t=0 соответствует началу пути (первая точка первого круга), а t=1 — концу пути (последняя точка второго круга). Движение по всем сегментам (двум кругам) происходит непрерывно и автоматически, несмотря на разрыв между ними, созданный moveTo.
this.tweens.add({
targets: this.follower,
t: 1,
ease: 'Linear',
duration: 2000,
repeat: -1
});
Обновление позиции и отрисовка в реальном времени
В методе update() происходит визуализация. Сначала графика очищается, задается стиль линии и отрисовывается весь путь (оба круга).
Затем, используя текущее значение follower.t, метод path.getPoint() вычисляет соответствующие координаты (x, y) на составном пути и записывает их в заранее созданный вектор follower.vec.
Эти координаты используются для отрисовки красного круга, который представляет движущийся объект.
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);
Что попробовать дальше
Метод Path.moveTo — это мощный инструмент для создания прерывистых или модульных траекторий, объединяющих геометрически не связанные сегменты в единый логический путь. Он позволяет легко проектировать сложные маршруты, разбивая их на простые части.
Для экспериментов попробуйте: добавить больше сегментов (например, lineTo или ellipseTo) после moveTo; изменить easing-функцию в твине для неравномерного движения по пути; привязать к вычисленным координатам follower.vec спрайт игрока или врага для создания патрульного маршрута.
