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

Создание игровых сцен часто требует точного контроля над временем. Например, нужно, чтобы враги появлялись с определёнными интервалами или анимации запускались в нужный момент. Встроенный механизм таймеров в Phaser (`this.time`) отлично подходит для простых задач, но для сложных последовательностей событий он может стать громоздким. Класс `Timeline` из модуля `time` предлагает элегантное решение. Он позволяет декларативно описывать цепочку событий, которые должны выполниться через заданное время после старта. Это делает код чище, понятнее и проще в управлении, особенно для сценариев, подобных кат-сценам или волновым атакам противников.

Версия 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');

        const timeline = this.add.timeline([
            {
                at: 2000,
                run: () => { this.add.sprite(200, 300, 'timeline', 'bat') }
            },
            {
                at: 4000,
                run: () => { this.add.sprite(400, 300, 'timeline', 'zombie') }
            },
            {
                at: 6000,
                run: () => { this.add.sprite(600, 300, 'timeline', 'spider') }
            },
        ]);

        timeline.play();
    }
}

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

const game = new Phaser.Game(config);

Создание и конфигурация таймлайна

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

* at — время в миллисекундах от момента старта таймлайна, когда должно произойти событие. * run — функция, которая будет выполнена в заданный момент.

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

const timeline = this.add.timeline([
    {
        at: 2000,
        run: () => { this.add.sprite(200, 300, 'timeline', 'bat') }
    },
    {
        at: 4000,
        run: () => { this.add.sprite(400, 300, 'timeline', 'zombie') }
    },
    {
        at: 6000,
        run: () => { this.add.sprite(600, 300, 'timeline', 'spider') }
    },
]);

Запуск таймлайна

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

timeline.play();

После этого движок начнёт внутренний отсчёт. События будут выполнены в порядке, определённом их свойствами at, но не в порядке объявления в массиве. Важно, что отсчёт времени начинается с момента вызова play(), а не с создания таймлайна. Это позволяет гибко управлять моментом старта сцены или последовательности действий.

В примере первый спрайт с летучей мышью появится через 2 секунды после старта, зомби — через 4 секунды, а паук — через 6 секунд.

Сцена и загрузка ресурсов

Для работы примера требуется стандартная структура сцены Phaser с методами preload и create. В preload загружаются необходимые ресурсы: атлас спрайтов timeline и фоновое изображение bg. Обратите внимание на использование this.load.setBaseURL() для указания базового пути, что упрощает загрузку из удалённого источника.

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.sprite(), создавая новые игровые объекты в указанные моменты времени. Ключ 'bat', 'zombie' или 'spider' — это имена кадров (frames) внутри загруженного атласа timeline.

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

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

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

const game = new Phaser.Game(config);

Важно, что экземпляр сцены Example передаётся в конфигурацию. При создании игры эта сцена автоматически инициализируется, вызываются её методы жизненного цикла preload и create, что в итоге приводит к запуску нашего таймлайна.

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

Timeline — это мощный и лаконичный инструмент для планирования событий в Phaser. Он идеально подходит для создания сценариев, где важна точная временная привязка: вступлений, волн врагов, анимационных последовательностей или синхронизации звука с визуальными эффектами. Для экспериментов попробуйте: 1. Добавить в таймлайн событие, которое не создаёт спрайт, а, например, запускает твин-анимацию уже существующего объекта. 2. Создать несколько независимых таймлайнов и управлять их запуском и остановкой (timeline.stop()) по разным игровым условиям. 3. Использовать свойство at не как абсолютное время, а как интервал от предыдущего события, создавая цепочки с помощью вычислений.