О чем этот пример
Управление временем — основа игровой динамики. В Phaser для этого есть мощный инструмент `TimeEvent`, который позволяет запускать действия по таймеру. В этой статье мы разберем, как создать циклическое событие, которое будет плавно вращать изображение с заданным интервалом. Этот подход полезен для создания анимаций, периодического спавна врагов, обновления UI и любых других повторяющихся процессов без засорения метода `update`.
Версия 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 ()
{
console.log('create');
this.image = this.add.image(400, 300, 'einstein');
this.text = this.add.text(32, 32);
this.timedEvent = this.time.addEvent({ delay: 500, callback: this.onEvent, callbackScope: this, loop: true });
}
update ()
{
this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}`);
}
onEvent ()
{
this.image.rotation += 0.04;
}
}
const config = {
type: Phaser.CANVAS,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Инициализация сцены и загрузка ассетов
Как и в любой сцене Phaser, мы начинаем с методов жизненного цикла. В preload загружаем необходимое изображение, устанавливая базовый URL для удобства. Ключевые свойства класса (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.time.addEvent. Объект конфигурации принимает три ключевых параметра:
- delay: интервал между вызовами в миллисекундах.
- callback: функция, которая будет вызвана по истечении каждого интервала.
- callbackScope: контекст (this), в котором будет вызвана функция-колбэк. Без этого указания контекст будет потерян.
- loop: флаг, указывающий, что событие должно повторяться бесконечно.
create ()
{
console.log('create');
this.image = this.add.image(400, 300, 'einstein');
this.text = this.add.text(32, 32);
this.timedEvent = this.time.addEvent({ delay: 500, callback: this.onEvent, callbackScope: this, loop: true });
}
Колбэк события и отслеживание прогресса
Функция onEvent — это наш колбэк, который выполняется каждые 500 мс. В данном примере она инкрементирует свойство rotation изображения, заставляя его вращаться.
onEvent ()
{
this.image.rotation += 0.04;
}
В методе update, который вызывается на каждом кадре, мы выводим в текстовый объект текущий прогресс выполнения события. Метод getProgress() возвращает число от 0 (начало цикла) до 1 (момент вызова колбэка). Это полезно для создания плавных интерполяций или индикаторов загрузки.
update ()
{
this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}`);
}
Конфигурация и запуск игры
Финальный шаг — создание экземпляра игры Phaser.Game с конфигурационным объектом. В нем мы указываем тип рендерера, размеры холста, цвет фона, родительский HTML-элемент и главную сцену.
const config = {
type: Phaser.CANVAS,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
TimeEvent — это декларативный и эффективный способ работы со временем в Phaser. В отличие от ручного подсчета кадров в update, он позволяет создавать независимые временные линии. Для экспериментов попробуйте изменить параметр delay, чтобы ускорить или замедлить вращение. Используйте getElapsed() и getRemaining() для получения абсолютного времени. Остановите событие методом remove() или паузу через paused. Попробуйте привязать событие не к вращению, а, например, к изменению масштаба (scale) или прозрачности (alpha) спрайта.
