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

Создание игровых механик часто требует точного контроля над временем — например, для периодического спауна врагов, мигания объектов или анимации по таймеру. Встроенная система времени Phaser (`Phaser.Time`) предоставляет мощный инструмент `TimeEvent` для решения этих задач. В этой статье мы разберем, как работает повторяющееся событие, как отслеживать его прогресс и использовать для управления игровыми объектами.

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

        this.timedEvent = this.time.addEvent({ delay: 2000, callback: this.onEvent, callbackScope: this, repeat: 4 });
    }

    update ()
    {
        this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}\nEvent.repeatCount: ${this.timedEvent.repeatCount}`);
    }

    onEvent ()
    {
        this.image.scaleX *= 0.90;
        this.image.scaleY *= 0.90;
        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);

Подготовка сцены и загрузка ассетов

Класс Example расширяет 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() мы создаем изображение и текстовый объект для отладки. Ключевой момент — создание TimeEvent через this.time.addEvent(). Конфигурационный объект принимает несколько параметров: - delay: интервал между вызовами в миллисекундах (2000 мс = 2 секунды). - callback: функция, которая будет вызываться по истечении каждого интервала. - callbackScope: контекст (this), в котором будет вызываться функция обратного вызова. - repeat: количество *дополнительных* повторений после первого срабатывания. Значение 4 означает, что событие произойдет 5 раз (1 начальное + 4 повторения).

create ()
{
    this.image = this.add.image(400, 300, 'einstein');
    this.text = this.add.text(32, 32);
    this.timedEvent = this.time.addEvent({ delay: 2000, callback: this.onEvent, callbackScope: this, repeat: 4 });
}

Отслеживание прогресса события

Метод update() вызывается каждый кадр. Здесь мы обновляем текстовую метку, чтобы визуализировать состояние таймера. Мы используем два свойства объекта timedEvent: - getProgress(): возвращает число от 0 до 1, представляющее общий прогресс всего события (всех повторений). Мы обрезаем строку для краткости отображения. - repeatCount: текущее количество оставшихся повторений. Обратите внимание, что это обратный отсчет. После каждого срабатывания callback значение уменьшается на 1.

update ()
{
    this.text.setText(`Event.progress: ${this.timedEvent.getProgress().toString().substr(0, 4)}\nEvent.repeatCount: ${this.timedEvent.repeatCount}`);
}

Логика обратного вызова

Функция onEvent() — это наша пользовательская логика, которая выполняется по таймеру. В данном примере при каждом вызове изображение немного уменьшается (scale умножается на 0.9) и поворачивается. Это демонстрирует, как можно использовать событие для постепенной трансформации объекта.

onEvent ()
{
    this.image.scaleX *= 0.90;
    this.image.scaleY *= 0.90;
    this.image.rotation += 0.04;
}

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

TimeEvent — это фундаментальный инструмент для создания интервальных действий в Phaser. Экспериментируйте: попробуйте изменить параметры delay и repeat, остановите событие методом timedEvent.remove(), перезапустите его или создайте цепочку событий с разной логикой в callback. Это основа для таймеров обратного отсчета, систем волн противников и цикличной анимации.