О чем этот пример

При создании игр часто возникает необходимость заставить спрайт плавно следовать по заданному пути, будь то полёт снаряда, движение патрульного или траектория платформы. Phaser 3 предоставляет для этого мощный инструмент — Follower. Однако, при включении автоматического поворота (`rotateToPath`) спрайт может быть изначально сориентирован не так, как требуется. Параметр `rotationOffset` решает эту проблему, позволяя скорректировать начальный и последующий угол объекта относительно пути. Эта статья научит вас тонко управлять ориентацией объектов, движущихся по кривым, что критически важно для визуальной согласованности геймплея.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('lemming', 'assets/sprites/lemming.png');
    }

    create ()
    {
        const curve = new Phaser.Curves.Line(new Phaser.Math.Vector2(100, 100), new Phaser.Math.Vector2(600, 400));

        const graphics = this.add.graphics();

        graphics.lineStyle(1, 0xffffff, 0.5);

        curve.draw(graphics);

        const lemming = this.add.follower(curve, 100, 100, 'lemming');

        lemming.startFollow({
            duration: 5000,
            yoyo: true,
            repeat: -1,
            rotateToPath: true,
            rotationOffset: 90
        });
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Создание сцены и базовой кривой

Вся логика примера содержится в методе create сцены. Первым делом создаётся объект кривой — в данном случае это прямая линия (Phaser.Curves.Line), заданная двумя точками в мировых координатах.

const curve = new Phaser.Curves.Line(new Phaser.Math.Vector2(100, 100), new Phaser.Math.Vector2(600, 400));

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

const graphics = this.add.graphics();
graphics.lineStyle(1, 0xffffff, 0.5);
curve.draw(graphics);

Инициализация Follower и ключевые параметры

Спрайт-последователь создаётся с помощью метода this.add.follower(). В него передаются сама кривая, начальные координаты (которые будут переопределены кривой) и ключ текстуры.

const lemming = this.add.follower(curve, 100, 100, 'lemming');

Запуск движения осуществляется методом startFollow(), который принимает объект конфигурации. Разберём его основные свойства: - duration: Время в миллисекундах, за которое объект пройдёт от начала до конца кривой. - yoyo: Если true, объект, достигнув конца пути, развернётся и пойдёт обратно. - repeat: Количество повторений (-1 для бесконечного цикла). - rotateToPath: Самая важная настройка. При значении true спрайт будет автоматически вращаться, чтобы его "передняя" часть (положительное направление оси Y) была направлена по касательной к пути.

lemming.startFollow({
    duration: 5000,
    yoyo: true,
    repeat: -1,
    rotateToPath: true,
    rotationOffset: 90
});

Магия rotationOffset: корректировка угла

Параметр rotationOffset — это решение проблемы неверной начальной ориентации. По умолчанию, когда rotateToPath включён, Phaser считает, что "лицо" вашего спрайта смотрит вверх (в сторону положительной оси Y). Если же на спрайте, как в нашем примере с леммингом, персонаж нарисован смотрящим вправо, его направление не совпадёт с направлением пути.

rotationOffset позволяет добавить фиксированное смещение к вычисленному углу поворота. Значение указывается в градусах.

rotationOffset: 90

Установив смещение в 90 градусов, мы по сути говорим движку: "Поверни вычисленный угол ещё на четверть круга по часовой стрелке". Если спрайт изначально смотрит вправо (0 градусов в системе координат Phaser), то после применения смещения он будет корректно ориентирован вдоль пути. Без этого параметра лемминг двигался бы боком.

Важно: это смещение применяется постоянно на всём протяжении пути, обеспечивая корректную ориентацию как при движении вперёд, так и при использовании опции yoyo.

Полная конфигурация игры

Инициализация самого игрового экземпляра Phaser.Game происходит в конце кода. Конфигурационный объект задаёт основные параметры: тип рендерера, размеры холста, цвет фона, родительский HTML-элемент и стартовую сцену.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Эта базовая структура конфига является стандартной для большинства проектов на Phaser 3. Ключевой момент — передача класса нашей сцены (Example) в свойство scene.

Что попробовать дальше

Параметр rotationOffset в методе startFollow() — это небольшой, но крайне важный инструмент для тонкой настройки визуализации движения объектов по пути. Он позволяет согласовать "встроенную" ориентацию спрайта в вашем арт-ассете с требованиями игровой логики, не прибегая к ручному вращению текстуры в графическом редакторе. **Идеи для экспериментов:** 1. Попробуйте изменить значение rotationOffset на -90 или 180 и понаблюдайте за поведением спрайта. 2. Замените Phaser.Curves.Line на более сложную кривую, например, Phaser.Curves.Spline, и убедитесь, что смещение угла работает корректно на всём её протяжении. 3. Создайте цепочку из нескольких последователей (followers) с разными значениями rotationOffset, чтобы сформировать строй или патруль, где каждый объект смотрит в своём направлении относительно пути.