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

Таймеры — это мощный инструмент в Phaser для организации событий, происходящих с заданной периодичностью или задержкой. В этой статье мы разберем пример использования нескольких таймеров одновременно. Это полезно для создания сложных анимаций, циклов спавна врагов, обновления интерфейса или любых других повторяющихся действий в игре. Вы научитесь создавать, управлять и визуализировать прогресс множества таймеров.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    timerEvents = [];
    hsv;
    graphics;
    text;

    create ()
    {
        this.text = this.add.text(32, 32);

        for (let i = 0; i < 32; i++)
        {
            this.timerEvents.push(this.time.addEvent({ delay: Phaser.Math.Between(1000, 8000), loop: true }));
        }

        this.hsv = Phaser.Display.Color.HSVColorWheel();

        this.graphics = this.add.graphics({ x: 240, y: 36 });
    }

    update ()
    {
        const output = [];

        this.graphics.clear();

        for (let i = 0; i < this.timerEvents.length; i++)
        {
            output.push(`Event.progress: ${this.timerEvents[i].getProgress().toString().substr(0, 4)}`);

            this.graphics.fillStyle(this.hsv[i * 8].color, 1);
            this.graphics.fillRect(0, i * 16, 500 * this.timerEvents[i].getProgress(), 8);
        }

        this.text.setText(output);
    }
}

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

const game = new Phaser.Game(config);

Настройка сцены и хранение данных

В начале класса сцены объявлены четыре свойства, которые будут использоваться для работы с таймерами и их отрисовки.

class Example extends Phaser.Scene
{
    timerEvents = [];
    hsv;
    graphics;
    text;

Массив timerEvents будет хранить ссылки на все созданные объекты таймеров. Объект hsv предназначен для палитры цветов, graphics — для рисования, а text — для вывода текстовой информации.

Создание множества таймеров в методе create

В методе create() происходит инициализация основных объектов. Сначала создается текстовый объект для отладки.

this.text = this.add.text(32, 32);

Затем в цикле создается 32 таймера. Каждый таймер создается с помощью this.time.addEvent(). Параметр delay определяет задержку между срабатываниями в миллисекундах. Здесь она задается случайным образом от 1 до 8 секунд с помощью Phaser.Math.Between. Параметр loop: true указывает, что таймер будет повторяться бесконечно. Каждый созданный объект события сохраняется в массив timerEvents.

for (let i = 0; i < 32; i++)
{
    this.timerEvents.push(this.time.addEvent({ delay: Phaser.Math.Between(1000, 8000), loop: true }));
}

Далее создается цветовая палитра HSVColorWheel и объект graphics для рисования примитивов.

this.hsv = Phaser.Display.Color.HSVColorWheel();
this.graphics = this.add.graphics({ x: 240, y: 36 });

Визуализация прогресса в методе update

Метод update() вызывается каждый кадр и отвечает за обновление визуального представления прогресса всех таймеров.

Сначала очищается предыдущее содержимое объекта graphics.

this.graphics.clear();

Затем для каждого таймера в массиве вычисляется его прогресс с помощью метода getProgress(). Этот метод возвращает число от 0 (начало цикла) до 1 (момент срабатывания). Прогресс добавляется в текстовый массив output.

output.push(`Event.progress: ${this.timerEvents[i].getProgress().toString().substr(0, 4)}`);

Для визуализации рисуется прямоугольник. Его ширина равна 500 пикселям, умноженным на текущий прогресс таймера, что создает эффект "наполняющейся" шкалы. Цвет для каждого прямоугольника берется из заранее созданной палитры hsv.

this.graphics.fillStyle(this.hsv[i * 8].color, 1);
this.graphics.fillRect(0, i * 16, 500 * this.timerEvents[i].getProgress(), 8);

В конце метод setText() обновляет содержимое текстового блока, выводя все строки прогресса.

this.text.setText(output);

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

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

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

const game = new Phaser.Game(config);

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

Использование TimerEvent в Phaser — это гибкий способ управления временными интервалами в игре. Вы можете создавать таймеры с разной периодичностью, отслеживать их прогресс и реагировать на их срабатывание. Для экспериментов попробуйте изменить логику срабатывания: сделайте таймеры не циклическими (loop: false), добавляйте обработчик callback в параметры события, чтобы выполнять код при каждом тике, или используйте прогресс для плавного интерполирования значений (например, движения объекта или изменения прозрачности).