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

Движение объектов по заранее заданным траекториям — основа для создания патрулей, летающих врагов, плавных кат-сцен и UI-анимаций. Встроенная система Path Follower в Phaser 3 позволяет легко реализовать такое движение. В этой статье мы разберем, как загружать сложные составные пути из JSON-файла и запускать по ним целую эскадрилью объектов с задержкой, создавая впечатляющие динамичные сцены. Этот подход экономит время на ручное прописывание координат и дает полный контроль над траекторией.

Версия 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.json('all', 'assets/paths/types-test.json');
        this.load.image('ship', 'assets/sprites/bsquadron2.png');
    }

    create ()
    {
        const path = new Phaser.Curves.Path(this.cache.json.get('all'));

        const graphics = this.add.graphics().lineStyle(1, 0x2d2d2d, 1);

        path.draw(graphics);

        for (let i = 0; i < 20; i++)
        {
            const follower = this.add.follower(path, 0, 0, 'ship');

            follower.startFollow({
                duration: 8000,
                positionOnPath: true,
                repeat: -1,
                yoyo: true,
                ease: 'Linear',
                delay: i * 70
            });
        }
    }
}

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

const game = new Phaser.Game(config);

Загрузка данных пути и спрайта

Вся магия начинается с загрузки данных. В методе preload() мы загружаем два ключевых ресурса: JSON-файл с описанием пути и изображение для нашего движущегося объекта.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.json('all', 'assets/paths/types-test.json');
    this.load.image('ship', 'assets/sprites/bsquadron2.png');
}

Метод setBaseURL() задает базовый URL для всех последующих загрузок, что удобно, если ресурсы хранятся в одной директории. this.load.json() асинхронно загружает файл по указанному ключу 'all'. После загрузки данные будут доступны в кэше игры. Параллельно загружается спрайт 'ship'.

Создание и отрисовка кривой Path

В методе create() мы извлекаем загруженные данные и создаем на их основе объект Path. Это мощный объект Phaser, который может объединять несколько типов кривых (линии, сплайны, эллипсы) в один сложный путь.

create ()
{
    const path = new Phaser.Curves.Path(this.cache.json.get('all'));

    const graphics = this.add.graphics().lineStyle(1, 0x2d2d2d, 1);
    path.draw(graphics);
}

Строка this.cache.json.get('all') извлекает данные JSON из кэша и передает их в конструктор Path. Далее создается объект Graphics для визуализации. Метод lineStyle() задает стиль линии (толщина, цвет, альфа), а path.draw(graphics) отрисовывает всю траекторию на холсте. Это очень полезно для отладки и понимания формы пути.

Запуск последовательности Follower'ов

Самый интересный этап — создание последовательности объектов, которые будут следовать по пути. Мы используем цикл для создания 20 таких объектов, называемых "фолловерами".

for (let i = 0; i < 20; i++)
{
    const follower = this.add.follower(path, 0, 0, 'ship');

    follower.startFollow({
        duration: 8000,
        positionOnPath: true,
        repeat: -1,
        yoyo: true,
        ease: 'Linear',
        delay: i * 70
    });
}

Метод this.add.follower() создает новый объект-последователь. Первый аргумент — это наш path. Следующие два аргумента (0, 0) — начальные координаты X и Y, но они будут проигнорированы, так как мы используем опцию positionOnPath: true. Последний аргумент — ключ текстуры 'ship'.

Конфигурация в startFollow() задает поведение: - duration: время полного прохождения пути (8 секунд). - positionOnPath: если true, объект начинает движение с начала пути, игнорируя переданные координаты. - repeat: -1: бесконечное повторение анимации. - yoyo: true: при повторении движение будет происходить в обратном направлении. - ease: 'Linear': линейная интерполяция, постоянная скорость. - delay: задержка перед стартом для каждого последующего объекта. Умножение i * 70 создает эффект цепочки или шлейфа.

Конфигурация игры и запуск сцены

Весь описанный код находится внутри пользовательского класса сцены Example. Чтобы игра заработала, необходимо создать конфигурацию и инстанс игры Phaser.Game.

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

const game = new Phaser.Game(config);

В объекте config задаются базовые параметры: type рендерера, размеры холста, цвет фона, ID HTML-элемента parent, в который будет встроен canvas, и главный класс сцены. Создание new Phaser.Game(config) инициализирует игровой цикл и запускает сцену Example.

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

Использование Phaser.Curves.Path с данными из JSON и метода startFollow() позволяет легко создавать сложные, синхронизированные паттерны движения. Это отличная основа для игровых механик. Для экспериментов попробуйте: изменить форму пути в JSON-редакторе, задать для каждого follower уникальную текстуру или скорость (duration), использовать нелинейные ease-функции для эффектов ускорения/замедления, или управлять фолловерами динамически, останавливая и запуская их по игровым событиям.