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

Стандартные твины в Phaser предсказуемы и синхронны, что не всегда соответствует хаотичному игровому миру. Функция `delay` в конфигурации твина позволяет задать не фиксированную паузу, а динамически рассчитанную задержку для каждого запуска. Это открывает двери к созданию более живых, "неровных" и интересных анимаций, например, для появления врагов волнами, хаотичного мерцания объектов или случайного времени реакции. В этой статье разберем пример, где задержка твина рассчитывается случайным образом при каждом запуске, и объясним, как это работает изнутри.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('bg', 'assets/skies/sunset.png');
        this.load.image('ball', 'assets/sprites/ball-pink.png');
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        this.add.text(10, 10, 'This Tween has a random delay value. Click to start it.', { font: '16px Courier', fill: '#ffffff' });

        const text = this.add.text(10, 40, '', { font: '16px Courier', fill: '#ffffff' });

        const ball = this.add.image(100, 300, 'ball').setScale(0.5);

        const tween = this.tweens.add({
            targets: ball,
            x: 700,
            yoyo: true,
            duration: 1000,
            persist: true,
            paused: true,
            ease: 'bounce.out',
            delay: function (target, key, value, index, total)
            {
                const delay = Math.random() * 2000;

                text.setText(`Tween Delay: ${delay}`);

                return delay;
            }
        });

        this.input.on('pointerdown', function () {

            if (!tween.isPlaying())
            {
                tween.play();
            }

        });
    }
}

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

const game = new Phaser.Game(config);

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

Как и всегда, работа начинается с методов жизненного цикла сцены Phaser. В preload мы загружаем два изображения: фон и спрайт мяча. В методе create мы создаем визуальные элементы, с которыми будем работать.

this.add.image(400, 300, 'bg');
const text = this.add.text(10, 40, '', { font: '16px Courier', fill: '#ffffff' });
const ball = this.add.image(100, 300, 'ball').setScale(0.5);

Первой мы размещаем фоновое изображение. Затем создаем текстовый объект text для вывода информации о задержке. Его начальное значение — пустая строка. Объект ball — это наш мяч, который мы будем анимировать. Мы сразу уменьшаем его масштаб вполовину с помощью метода .setScale(0.5) и размещаем у левого края.

Создание твина с функцией задержки

Сердце примера — создание твина с помощью this.tweens.add(). Ключевой параметр здесь — delay. Вместо статичного числа мы передаем функцию.

const tween = this.tweens.add({
    targets: ball,
    x: 700,
    yoyo: true,
    duration: 1000,
    persist: true,
    paused: true,
    ease: 'bounce.out',
    delay: function (target, key, value, index, total) {
        const delay = Math.random() * 2000;
        text.setText(`Tween Delay: ${delay}`);
        return delay;
    }
});

Разберем важные параметры: * targets: ball: Анимация применяется к объекту ball. * x: 700: Конечная координата X для движения. * yoyo: true: После завершения движения мяч вернется в исходную точку. * duration: 1000: Длительность одного цикла движения (туда или обратно) — 1 секунда. * persist: true: Твин не будет автоматически уничтожен после завершения, что позволяет перезапускать его. * paused: true: Твин создается в приостановленном состоянии и не начнется сам. * ease: 'bounce.out': Функция плавности, создающая эффект отскока в конце движения.

Функция delay вызывается системой твинов в момент старта анимации. Она генерирует случайное число от 0 до 2000 миллисекунд, выводит его в интерфейс и возвращает как значение задержки. Именно столько времени твин будет ждать перед началом движения.

Запуск твина по клику

Поскольку твин создан с параметром paused: true, нам нужен способ его запустить. Мы навешиваем обработчик события клика (или касания) на всю сцену.

this.input.on('pointerdown', function () {
    if (!tween.isPlaying()) {
        tween.play();
    }
});

Обработчик проверяет, не воспроизводится ли твин уже сейчас, с помощью метода tween.isPlaying(). Если твин простаивает, мы вызываем tween.play(). При каждом клике функция delay выполнится заново, рассчитав новое случайное значение, и мяч начнет движение после новой, непредсказуемой паузы.

Сборка и запуск игры

Финальный шаг — конфигурация и инстанцирование игры Phaser. Эта часть кода стандартна и определяет базовые настройки приложения.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};
const game = new Phaser.Game(config);

Конфиг задает автоматический выбор рендерера (Phaser.AUTO), размеры холста, цвет фона (используется, пока не загрузились ресурсы), ID HTML-элемента для встраивания и нашу сцену Example как стартовую. Создание экземпляра new Phaser.Game(config) запускает весь процесс.

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

Использование функции для параметра delay превращает статичную задержку в мощный инструмент для генерации процедурного геймплея. Вы можете рассчитывать паузу не только случайно, но и на основе состояния игры: уровня здоровья врага, дистанции до игрока, количества объектов в пуле. Экспериментируйте: попробуйте сделать так, чтобы задержка зависела от index в массиве targets для создания эффекта "волны", или привяжите ее к громкости звука в игре для визуального feedback. Это простое изменение добавляет анимациям живости и неожиданности.