О чем этот пример
Создание игровых механик часто требует точного контроля над временем. Задержка перед появлением врага, перезарядка способности, периодическое начисление ресурсов – всё это реализуется с помощью таймеров. В Phaser 3 для этого есть мощная и простая в использовании система Time Events. В этой статье на примере из официальной документации разберём, как отложить выполнение функции и отслеживать прогресс таймера, чтобы делать ваши игры более динамичными и отзывчивыми.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
timedEvent;
text;
image;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('einstein', 'assets/pics/ra-einstein.png');
}
create ()
{
this.image = this.add.image(400, 300, 'einstein');
this.text = this.add.text(32, 32);
// timedEvent = this.time.addEvent({ delay: 2000, callback: onEvent, callbackScope: this });
// The same as above, but uses a method signature to declare it (shorter, and compatible with GSAP syntax)
this.timedEvent = this.time.delayedCall(3000, this.onEvent, [], this);
}
update ()
{
this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}`);
}
onEvent ()
{
this.image.setScale(0.5);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Вся работа начинается в классе сцены, унаследованном от Phaser.Scene. В методе preload() мы загружаем изображение, которое позже будет использоваться для визуальной демонстрации работы таймера. Важно установить базовый URL для загрузчика, чтобы указывать относительные пути к файлам.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('einstein', 'assets/pics/ra-einstein.png');
}
Создание объектов и запуск таймера
В методе create() происходит инициализация игровых объектов. Мы создаём изображение и текстовый объект для вывода информации. Самое важное здесь – создание отложенного вызова с помощью this.time.delayedCall(). Этот метод планирует выполнение указанной функции через заданное количество миллисекунд.
create ()
{
this.image = this.add.image(400, 300, 'einstein');
this.text = this.add.text(32, 32);
this.timedEvent = this.time.delayedCall(3000, this.onEvent, [], this);
}
Метод `delayedCall` принимает четыре аргумента:
1. `delay` (3000) – задержка в миллисекундах (3 секунды).
2. `callback` (`this.onEvent`) – функция, которая будет вызвана.
3. `args` (`[]`) – массив аргументов, которые будут переданы в callback-функцию (в данном случае пустой).
4. `callbackScope` (`this`) – контекст (`this`), в котором будет вызвана функция. Это критически важно, чтобы внутри `onEvent` мы могли получить доступ к свойствам сцены, таким как `this.image`.
Альтернативный способ – использование this.time.addEvent() с конфигурационным объектом, что более наглядно для сложных повторяющихся событий.
Отслеживание прогресса выполнения
Метод update() выполняется каждый кадр игры. Здесь мы используем его для того, чтобы в реальном времени отображать прогресс до срабатывания нашего таймера. Объект timedEvent имеет метод getProgress(), который возвращает число от 0 (только что создан) до 1 (таймер сработал).
update ()
{
this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}`);
}
Мы берём результат getProgress(), преобразуем его в строку и обрезаем до четырёх символов, чтобы получить читаемый вывод вида "0.56" в текстовом поле на экране. Это отличный способ визуализировать отсчёт времени для игрока, например, в виде полосы загрузки или анимации.
Обработка срабатывания таймера
Когда проходит 3 секунды, Phaser автоматически вызывает функцию, которую мы указали в delayedCall. В нашем примере это метод onEvent() класса сцены. Внутри него мы выполняем нужное действие – в данном случае изменяем масштаб изображения, уменьшая его вдвое.
onEvent ()
{
this.image.setScale(0.5);
}
Именно здесь реализуется основная логика, ради которой и создавался таймер. Вместо изменения масштаба это могло быть создание противника, нанесение урона, завершение уровня или любой другой игровой процесс.
Что попробовать дальше
Система таймеров Phaser 3 (this.time) предоставляет простой и эффективный способ управления временными интервалами в игре. Используя delayedCall для разовых событий или addEvent для повторяющихся, вы можете легко реализовать задержки, кд (кулдауны) и периодические действия. Для экспериментов попробуйте: создать цикличный таймер для спавна врагов, реализовать прогресс-бар перезарядки на основе getProgress() или построить цепочку последовательных событий, где завершение одного запускает следующее.
