О чем этот пример
Создание плавных и контролируемых траекторий движения — одна из ключевых задач в разработке игр. Вместо того чтобы вручную вычислять координаты объекта в каждом кадре, можно использовать мощную систему кривых Phaser. В этой статье мы разберем, как с помощью `Phaser.Curves.Line` и твинов анимировать движение спрайта или точки по прямой линии, создавая эффекты патрулирования, перемещения снарядов или визуализации интерфейсов. Этот подход не только упрощает код, но и дает полный контроль над временем и характером движения.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
graphics;
curve;
path;
create ()
{
this.graphics = this.add.graphics();
this.path = { t: 0, vec: new Phaser.Math.Vector2() };
this.curve = new Phaser.Curves.Line(new Phaser.Math.Vector2(100, 100), new Phaser.Math.Vector2(600, 400));
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);
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, 16);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Создание линейной кривой
В основе анимации лежит линейная кривая — отрезок между двумя точками. Класс Phaser.Curves.Line создает такую кривую, принимая начальную и конечную точки в виде объектов Phaser.Math.Vector2.
this.curve = new Phaser.Curves.Line(
new Phaser.Math.Vector2(100, 100),
new Phaser.Math.Vector2(600, 400)
);
После создания кривая представляет собой математическое описание отрезка от (100, 100) до (600, 400). Мы не рисуем ее сразу, а используем как источник данных для вычисления позиций.
Подготовка данных для анимации
Для управления движением по кривой используется параметр `t(от 0 до 1), где 0 соответствует началу отрезка, а 1 — его концу. Вместо того чтобы изменятьtвручную вupdate()`, мы поручаем это системе твинов.
this.path = { t: 0, vec: new Phaser.Math.Vector2() };
Здесь создается объект path с двумя свойствами: `t(текущая позиция на кривой) иvec(вектор для хранения вычисленных координат x, y). Затем мы настраиваем твин, который будет циклично изменять значениеt` от 0 до 1 и обратно.
this.tweens.add({
targets: this.path, // Анимируемый объект
t: 1, // Конечное значение свойства `t`
ease: 'Sine.easeInOut', // Плавная функция easing
duration: 2000, // Длительность в миллисекундах
yoyo: true, // Возврат к начальному значению
repeat: -1 // Бесконечное повторение
});
Твин автоматически обновляет this.path.t в каждом кадре, создавая плавное движение.
Визуализация кривой и точки
Метод update() вызывается каждый кадр и отвечает за отрисовку. Сначала мы очищаем холст от графики предыдущего кадра с помощью this.graphics.clear().
Затем настраиваем стиль линии и рисуем саму кривую — визуальное представление отрезка.
this.graphics.lineStyle(1, 0xffffff, 1);
this.curve.draw(this.graphics);
Ключевой момент — получение текущих координат точки на кривой, соответствующих значению `tиз анимированного объектаthis.path`.
this.curve.getPoint(this.path.t, this.path.vec);
Метод getPoint() вычисляет координаты и записывает их в переданный вектор this.path.vec. После этого мы можем использовать эти координаты для отрисовки, например, красного круга.
this.graphics.fillStyle(0xff0000, 1);
this.graphics.fillCircle(this.path.vec.x, this.path.vec.y, 16);
Таким образом, в каждом кадре круг перерисовывается в новой позиции вдоль линии, создавая иллюзию движения.
От теории к практике: замена круга на спрайт
Вместо рисования круга графическим контекстом вы можете перемещать по кривой игровой спрайт. Для этого в методе create() создайте спрайт, а в update() обновляйте его позицию, используя вычисленный вектор.
// В create()
this.sprite = this.add.sprite(0, 0, 'player');
// В update(), после this.curve.getPoint(...)
this.sprite.setPosition(this.path.vec.x, this.path.vec.y);
Этот подход идеально подходит для движения врагов по заданному маршруту, полета снарядов или плавного перемещения элементов интерфейса.
Что попробовать дальше
Использование Phaser.Curves.Line в связке с системой твинов предоставляет элегантный и мощный способ анимации движения по прямой. Вы получаете контроль над скоростью, плавностью и повторяемостью траектории без необходимости управлять координатами вручную. Для экспериментов попробуйте: создать несколько кривых и переключать движение между ними; использовать другие типы кривых, например Phaser.Curves.Spline, для сложных путей; или привязать к движению по кривой не только позицию, но и угол поворота спрайта, используя производную getTangent().
