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

Создание сложных, синхронизированных последовательностей событий и анимаций — частая задача в разработке игр. Phaser предлагает для этого мощный и удобный инструмент — Timeline (Таймлайн). В отличие от ручного управления множеством таймеров и твинов, таймлайн позволяет декларативно описать цепочку действий, которые должны произойти в определённые моменты времени относительно начала последовательности. Это делает код чище, понятнее и проще в отладке.

Версия 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.atlas('timeline', 'assets/atlas/timeline.png', 'assets/atlas/timeline.json');
        this.load.image('bg', 'assets/skies/spookysky.jpg');
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        this.add.text(10, 10, 'Click to start the Timeline', { font: '16px Courier', fill: '#ffffff' });

        const timeline = this.add.timeline([
            {
                at: 1000,
                tween: {
                    targets: this.add.sprite(400, 700, 'timeline', 'tombstone'),
                    y: 400,
                    duration: 3000,
                    ease: 'Power2'
                }
            },
            {
                at: 2000,
                run: () => { this.add.sprite(400, 200, 'timeline', 'spider').setScale(1.5) }
            },
        ]);

        this.input.once('pointerdown', () => {

            timeline.play();

        });
    }
}

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

const game = new Phaser.Game(config);

Что такое Timeline и зачем он нужен?

Timeline (Таймлайн) в Phaser — это контейнер для управления последовательностью событий, таких как запуск твинов (анимаций) или выполнение произвольных функций, привязанных к временной шкале. Основное его преимущество — централизованный контроль. Вы можете запустить всю последовательность одной командой play(), приостановить, возобновить или остановить её. Это идеально для кат-сцен, сложных вступительных анимаций, сцен с появлением врагов волнами или любых других процессов, где важен строгий временной порядок.

В примере мы создаём таймлайн, который по клику запускает два события: через 1 секунду начинает двигаться надгробие, а через 2 секунды появляется паук.

Создание и структура таймлайна

Таймлайн создаётся с помощью метода this.add.timeline(), который принимает массив объектов-событий. Каждое событие определяется двумя ключевыми свойствами:

* at: Время в миллисекундах *относительно старта таймлайна*, когда должно произойти событие. * tween или run: Определяет тип события. tween запускает анимацию с помощью системы твинов Phaser, а run выполняет переданную функцию.

Давайте посмотрим на код создания таймлайна из примера:

const timeline = this.add.timeline([
    {
        at: 1000,
        tween: {
            targets: this.add.sprite(400, 700, 'timeline', 'tombstone'),
            y: 400,
            duration: 3000,
            ease: 'Power2'
        }
    },
    {
        at: 2000,
        run: () => { this.add.sprite(400, 200, 'timeline', 'spider').setScale(1.5) }
    },
]);

Первый элемент массива (событие) запланирован на 1000 мс (1 секунду). В нём используется tween, который будет анимировать свойство `yспрайта надгробия от начального значения 700 до 400 в течение 3000 мс (3 секунды) с плавностьюPower2`.

Второе событие сработает на 2000 мс (2 секунды). Здесь используется run, который просто добавляет на сцену спрайт паука и увеличивает его масштаб в полтора раза. Обратите внимание: время at отсчитывается не от окончания предыдущего твина, а от общего момента старта таймлайна. Таким образом, паук появится ровно через 2 секунды после вызова timeline.play(), независимо от того, закончила ли к этому моменту двигаться первая анимация.

Запуск и управление таймлайном

Созданный таймлайн не запускается автоматически. Это позволяет вам подготовить сложную последовательность и активировать её в нужный момент игры — по клику, после загрузки уровня, при столкновении с объектом и т.д.

В примере запуск привязан к первому клику мыши (или касанию):

this.input.once('pointerdown', () => {
    timeline.play();
});

Метод play() начинает отсчёт временной шкалы. Помимо play(), объект таймлайна предоставляет и другие методы для управления:

* pause() — приостанавливает выполнение. * resume() — возобновляет с момента паузы. * stop() — полностью останавливает таймлайн. Последующий вызов play() начнёт последовательность заново. * isPlaying() — возвращает true, если таймлайн в данный момент воспроизводится.

Эти методы дают полный контроль над процессом, позволяя, например, поставить кат-сцену на паузу или пропустить её.

Практические советы и расширение примера

Таймлайны можно комбинировать и вкладывать для создания ещё более сложного поведения.

**Комбинирование событий:** Вы можете добавить в массив больше событий с разными задержками at. Например, чтобы паук не просто появлялся, но и начинал двигаться через 500 мс после своего появления, добавьте третье событие:

{
    at: 2500, // 2000 + 500
    tween: {
        targets: spiderSprite, // Нужно сохранить ссылку на спрайт паука
        x: 600,
        duration: 2000
    }
}

**Использование run для гибкости:** В событии типа run можно выполнить любой код: проиграть звук, изменить переменную игры, запустить другой таймлайн или даже создать новый твин вручную. Это делает таймлайн универсальным инструментом для скриптования игровых событий.

**Переиспользование:** Объект таймлайна можно запускать много раз (play() после stop()). Это полезно для циклических анимаций или поведения врагов, которое повторяется на каждом уровне.

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

Timeline в Phaser — это элегантное решение для управления временными последовательностями. Оно избавляет разработчика от хаоса из setTimeout и вложенных колбэков, предоставляя чистый, декларативный API. Поэкспериментируйте: создайте таймлайн для вступительной заставки уровня, где поочерёдно появляются элементы интерфейса с разной задержкой. Или используйте его для скриптования поведения босса, где атаки и смена фаз следуют строгому временному шаблону. Комбинируйте события tween и run для полного контроля над происходящим на сцене.