О чем этот пример
Визуализация и создание плавных траекторий — важная часть разработки игр. Это может быть путь для патрулирования врага, траектория полёта снаряда или маршрут кат-сцены. Класс `Phaser.Curves.Spline` позволяет легко создавать такие кривые, проходящие через заданные точки, и управлять движением объектов по ним. В этой статье разберём практический пример, который поможет вам освоить работу со сплайнами и интегрировать их в свои проекты.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
graphics;
points;
curve;
path;
create ()
{
this.graphics = this.add.graphics();
this.path = { t: 0, vec: new Phaser.Math.Vector2() };
this.points = [];
this.points.push(new Phaser.Math.Vector2(50, 400));
this.points.push(new Phaser.Math.Vector2(200, 200));
this.points.push(new Phaser.Math.Vector2(350, 300));
this.points.push(new Phaser.Math.Vector2(500, 500));
this.points.push(new Phaser.Math.Vector2(700, 400));
this.curve = new Phaser.Curves.Spline(this.points);
this.tweens.add({
targets: this.path,
t: 1,
ease: 'Sine.easeInOut',
duration: 2000,
yoyo: true,
repeat: -1
});
}
update ()
{
this.graphics.clear();
this.graphics.lineStyle(1, 0xffffff, 1);
this.curve.draw(this.graphics, 64);
this.graphics.fillStyle(0x00ff00, 1);
for (let i = 0; i < this.points.length; i++)
{
this.graphics.fillCircle(this.points[i].x, this.points[i].y, 4);
}
this.curve.getPoint(this.path.t, this.path.vec);
this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillCircle(this.path.vec.x, this.path.vec.y, 8);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и данных
В методе create() происходит начальная настройка. Сначала создаётся объект Graphics для рисования. Затем инициализируется объект path, который будет хранить текущую позицию на кривой (параметр `t` от 0 до 1) и вектор для вычислений.
this.graphics = this.add.graphics();
this.path = { t: 0, vec: new Phaser.Math.Vector2() };
Далее создаётся массив опорных точек (points), через которые будет проходить кривая. Каждая точка — это вектор с координатами X и Y.
this.points = [];
this.points.push(new Phaser.Math.Vector2(50, 400));
this.points.push(new Phaser.Math.Vector2(200, 200));
// ... и так далее
На основе этого массива создаётся сам объект сплайна.
this.curve = new Phaser.Curves.Spline(this.points);
Анимация движения по кривой
Чтобы точка двигалась по сплайну, используется твин из системы Tweens. Он циклически меняет значение this.path.t от 0 до 1 и обратно, что соответствует движению от начала кривой к её концу и назад.
this.tweens.add({
targets: this.path,
t: 1,
ease: 'Sine.easeInOut',
duration: 2000,
yoyo: true,
repeat: -1
});
Ключевые параметры:
- targets: объект, свойство которого будет анимировано.
- `t`: целевое значение (1 — конец кривой).
- ease: функция плавности 'Sine.easeInOut' для мягкого старта и остановки.
- yoyo: true: заставляет твин проигрываться в обратном направлении.
- repeat: -1: бесконечное повторение.
Визуализация в реальном времени
В методе update() происходит отрисовка кадра. Первым делом очищается холст Graphics от предыдущего кадра.
this.graphics.clear();
Затем задаётся стиль линии и рисуется сама кривая с помощью метода draw. Второй аргумент (64) определяет количество отрезков, из которых будет состоять сглаженная кривая — чем больше, тем она плавнее.
this.graphics.lineStyle(1, 0xffffff, 1);
this.curve.draw(this.graphics, 64);
После этого отрисовываются зелёные точки — опорные узлы сплайна.
this.graphics.fillStyle(0x00ff00, 1);
for (let i = 0; i < this.points.length; i++)
{
this.graphics.fillCircle(this.points[i].x, this.points[i].y, 4);
}
Получение позиции на кривой
Самая важная для геймдева часть — получение координат точки на кривой в зависимости от прогресса `t. Это делает методgetPoint`.
this.curve.getPoint(this.path.t, this.path.vec);
Он принимает текущее значение `t(от 0 до 1) и вектор (this.path.vec`), в который запишутся вычисленные координаты X и Y. Эти координаты затем используются, чтобы нарисовать красный маркер, движущийся по пути.
this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillCircle(this.path.vec.x, this.path.vec.y, 8);
Именно этот механизм — getPoint — вы будете использовать, чтобы привязать к кривой спрайт врага, снаряда или камеры.
Что попробовать дальше
Класс Phaser.Curves.Spline — это мощный и простой инструмент для работы с плавными путями. Вы можете динамически менять массив опорных точек, создавая изменяемые маршруты, или использовать несколько кривых для сложных траекторий. Для экспериментов попробуйте:
1. Привязать к this.path.vec спрайт, а не точку отрисовки.
2. Изменять массив points в реальном времени в ответ на действия игрока.
3. Использовать getPoint для расчёта позиции нескольких объектов, создавая, например, строй врагов.
