Кривые Безье и сложные пути

Phaser — это мощная библиотека для создания 2D-игр на JavaScript, которая включает инструменты для работы с кривыми и сложными путями. Кривые Безье позволяют создавать плавные траектории движения объектов, а также динамические визуальные эффекты, такие как линии, растущие по кривой, или анимации камеры.

В Phaser для работы с кривыми используется объект Phaser.Curves.Path и связанные с ним классы, такие как Phaser.Curves.CubicBezier и Phaser.Curves.QuadraticBezier.


Создание кривых

Кривая второго порядка (Quadratic Bézier)

Кривая второго порядка определяется тремя точками: начальной, управляющей и конечной. В Phaser её создают следующим образом:

const startPoint = new Phaser.Math.Vector2(100, 300);
const controlPoint = new Phaser.Math.Vector2(200, 100);
const endPoint = new Phaser.Math.Vector2(400, 300);

const curve = new Phaser.Curves.QuadraticBezier(startPoint, controlPoint, endPoint);

Метод getPoint(t) возвращает координаты точки на кривой при значении t от 0 до 1. Например, curve.getPoint(0.5) вернёт координаты середины кривой.

Кривая третьего порядка (Cubic Bézier)

Кубическая кривая использует две управляющие точки, что даёт больше гибкости в формировании траектории:

const startPoint = new Phaser.Math.Vector2(50, 300);
const controlPoint1 = new Phaser.Math.Vector2(150, 50);
const controlPoint2 = new Phaser.Math.Vector2(300, 550);
const endPoint = new Phaser.Math.Vector2(400, 300);

const curve = new Phaser.Curves.CubicBezier(startPoint, controlPoint1, controlPoint2, endPoint);

Кубические кривые особенно полезны для сложных анимаций движения и плавных переходов между несколькими точками.


Path: объединение кривых в сложные траектории

Phaser.Curves.Path позволяет объединять несколько кривых в единый путь. Это необходимо для создания комплексных маршрутов движения объектов или рисования сложных форм.

const path = new Phaser.Curves.Path(50, 300);
path.splineTo([ { x: 150, y: 50 }, { x: 300, y: 550 }, { x: 400, y: 300 } ]);

Метод splineTo автоматически создаёт серию кривых Безье через заданные точки. Для более точного контроля можно использовать комбинацию add(new Phaser.Curves.CubicBezier(...)) и add(new Phaser.Curves.QuadraticBezier(...)).


Отрисовка кривых

Phaser предоставляет удобный способ визуализации кривых через графический объект Phaser.GameObjects.Graphics:

const graphics = this.add.graphics();
graphics.lineStyle(2, 0xff0000);

curve.draw(graphics);

Метод draw автоматически прорисовывает кривую с указанным стилем. Для сложных путей можно вызвать draw(graphics) для каждого сегмента или воспользоваться объектом Path:

path.draw(graphics);

Анимация объектов по кривым

Чтобы объект следовал кривой, используется метод getPoint(t) для вычисления координат в зависимости от времени:

const sprite = this.add.sprite(50, 300, 'player');
let t = 0;
this.tweens.add({
    targets: { t: 0 },
    t: 1,
    duration: 3000,
    onUpdate: function(tween) {
        const value = tween.targets[0].t;
        const point = curve.getPoint(value);
        sprite.setPosition(point.x, point.y);
    }
});

Для сложного пути через Phaser.Curves.Path можно использовать path.getPoint(t) аналогично. Это позволяет плавно перемещать объекты по нескольким сегментам кривых.


Длина кривой и точечная дискретизация

Метод getLength() возвращает длину кривой в пикселях. Для получения координат точек с равными интервалами можно использовать getPoints(divisions):

const points = curve.getPoints(20);
points.forEach(p => {
    graphics.fillCircle(p.x, p.y, 3);
});

Это важно для генерации сплайновых эффектов, частиц, и создания траекторий движения с равномерной скоростью.


Составные пути и сложные движения

Комбинирование нескольких кривых позволяет строить произвольные траектории. Пример создания пути из квадратичной и кубической кривой:

const path = new Phaser.Curves.Path(50, 300);
path.add(new Phaser.Curves.QuadraticBezier(
    new Phaser.Math.Vector2(50, 300),
    new Phaser.Math.Vector2(150, 100),
    new Phaser.Math.Vector2(300, 300)
));
path.add(new Phaser.Curves.CubicBezier(
    new Phaser.Math.Vector2(300, 300),
    new Phaser.Math.Vector2(350, 500),
    new Phaser.Math.Vector2(450, 100),
    new Phaser.Math.Vector2(500, 300)
));

Такой путь можно использовать как для анимации объектов, так и для динамической генерации линий и эффекта движения по сложным траекториям.


Использование кривых для интерактивных эффектов

Кривые Безье в Phaser применяются не только для движения объектов, но и для:

  • Анимации частиц вдоль сложной траектории;
  • Динамического рисования линий с помощью Graphics;
  • Сглаживания движения камеры по сцене;
  • Построения пользовательских сплайнов для игровых объектов и UI-элементов.

Применение кривых в этих сценариях позволяет добиться высоко качественных, плавных анимаций и контролируемого взаимодействия объектов с игровой средой.


Практические советы

  • Для точного контроля движения рекомендуется использовать getPoint(t) вместо линейного интерполирования между точками.
  • При объединении нескольких кривых важно следить за непрерывностью касательных в стыках сегментов, чтобы движение не выглядело рывками.
  • Для оптимизации визуализации сложных путей можно заранее генерировать массив точек через getPoints и использовать их вместо постоянного вызова getPoint в цикле анимации.

Кривые Безье и Path-объекты открывают возможности для создания гибких и плавных анимаций, обеспечивая высокий уровень контроля над траекториями движения и визуальными эффектами в Phaser.