О чем этот пример
Создание сложных, синхронизированных последовательностей событий и анимаций — частая задача в разработке игр. 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 для полного контроля над происходящим на сцене.
