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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{

    create ()
    {
        const timeline = this.add.timeline();

        for (let i = 0; i < 50; i++)
        {
            timeline.add({
                at: i * 20,
                once: true, // comment out to get to fin
                run: () => console.log(i * 20)
            });
        }

        // timeline.add({
        //     at: 1000,
        //     run: () => console.log('fin')
        // });

        timeline.play();
    }
}

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

const game = new Phaser.Game(config);

Что такое Timeline и как его создать

Timeline — это встроенный в Phaser менеджер временных событий. Он позволяет планировать выполнение функций в определенные моменты времени относительно начала его воспроизведения.

Создается таймлайн через фабрику this.add.timeline(). Это метод сцены, который возвращает новый экземпляр класса Timeline.

const timeline = this.add.timeline();

После создания таймлайн находится в состоянии ожидания. Чтобы запустить отсчет времени и выполнение запланированных событий, необходимо явно вызвать метод .play().

Добавление событий: параметр `at` и функция `run`

Событие в таймлайн добавляется методом .add(). Он принимает объект конфигурации. Два ключевых свойства этого объекта: - at: Время в миллисекундах от начала воспроизведения таймлайна, когда должно сработать событие. - run: Функция-колбэк, которая будет выполнена в указанный момент времени.

В примере из исходного кода в цикле создается 50 событий. Каждое следующее событие запланировано на 20 мс позже предыдущего.

for (let i = 0; i < 50; i++)
{
    timeline.add({
        at: i * 20,
        once: true,
        run: () => console.log(i * 20)
    });
}

Таким образом, первое событие сработает в момент 0 мс, второе — в 20 мс, третье — в 40 мс и так далее. В консоль будет выведено соответствующее время события.

Управление жизненным циклом событий: флаг `once`

В конфигурации события есть важное необязательное свойство once. Оно определяет, должно ли событие быть удалено из таймлайна после своего единственного выполнения.

timeline.add({
    at: i * 20,
    once: true, // Событие удалится после запуска
    run: () => console.log(i * 20)
});

Если свойство once установлено в true (как в нашем примере), событие выполнится один раз в момент времени at и затем будет автоматически удалено из внутреннего списка таймлайна. Это предотвращает повторное выполнение, если таймлайн будет перезапущен.

Если закомментировать строку с once: true, событие останется в таймлайне. В текущем примере это не приведет к видимому эффекту, так как таймлайн проигрывается один раз. Однако если бы у нас был механизм перезапуска таймлайна (например, по нажатию клавиши), то все события без флага once выполнились бы снова.

Запуск таймлайна и логика выполнения

После того как все события добавлены, необходимо запустить таймлайн. Делается это методом .play().

timeline.play();

С этого момента начинается отсчет времени. Внутренний механизм Timeline проверяет, наступило ли время для выполнения какого-либо из запланированных событий. Когда системное время с момента вызова .play() достигает или превышает значение at для события, вызывается его функция run.

Важно понимать, что проверка происходит в рамках основного игрового цикла Phaser. Это обеспечивает стабильную работу и привязку к игровому времени, а не к реальному системному времени, что может быть важно при паузе или изменении скорости игры (timeScale).

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

Класс Timeline в Phaser — это мощный и простой инструмент для организации событий во времени. Он избавляет от необходимости вручную управлять таймерами и задержками, делая код для скриптовых последовательностей наглядным и линейным. **Идеи для экспериментов:** 1. Создайте таймлайн для кат-сцены: в момент 0мс выведите текст, в 2000мс — измените выражение лица персонажа, в 4000мс — воспроизведите звук, в 6000мс — перейдите к следующей сцене. 2. Используйте таймлайн для спавна врагов волнами, где каждая волна — это событие с набором действий по созданию мобов. 3. Скомбинируйте таймлайн с анимациями. Запланируйте запуск анимации объекта (sprite.play()) или твина через определенные интервалы. 4. Поэкспериментируйте с флагом once: false, создайте циклический таймлайн и реализуйте его перезапуск по какому-либо игровому событию.