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

При создании сложных анимаций в игре часто возникает необходимость приостановить или возобновить все движения одновременно. Например, когда игра ставится на паузу или активируется эффект замедления времени. Вручную управлять десятками твинов неудобно и подвержено ошибкам. В этом примере мы рассмотрим, как использовать встроенные методы глобального управления всеми твинами сцены: `pauseAll()` и `resumeAll()`. Это позволит вам легко реализовать паузу в игре или спецэффекты, затрагивающие все анимации.

Версия 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/ui/undersea-bg.png');
        this.load.image('up', 'assets/ui/up-bubble.png');
        this.load.image('down', 'assets/ui/down-bubble.png');
        this.load.spritesheet('fish', 'assets/sprites/fish-136x80.png', { frameWidth: 136, frameHeight: 80 });
    }

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

        var image1 = this.add.image(0, 80, 'fish', 0);

        this.tweens.add({
            targets: image1,
            props: {
                x: { value: 700, duration: 4000, flipX: true },
                y: { value: 500, duration: 8000, },
            },
            ease: 'Sine.easeInOut',
            yoyo: true,
            repeat: -1
        });

        var image2 = this.add.image(400, 80, 'fish', 1);

        this.tweens.add({
            targets: image2,
            props: {
                x: { value: 500, duration: 2000, flipX: true },
                y: { value: 500, duration: 10000, },
            },
            ease: 'Sine.easeInOut',
            yoyo: true,
            repeat: -1
        });

        var image3 = this.add.image(800, 200, 'fish', 2).setFlipX(true);

        this.tweens.add({
            targets: image3,
            props: {
                x: { value: 70, flipX: true },
                y: { value: 250 },
            },
            duration: 3000,
            ease: 'Power1',
            yoyo: true,
            repeat: -1
        });

        var image4 = this.add.image(100, 550, 'fish', 2).setScale(0.75);

        this.tweens.add({
            targets: image4,
            props: {
                x: { value: 700, duration: 2000, flipX: true },
                y: { value: 50, duration: 15000, },
            },
            ease: 'Sine.easeInOut',
            yoyo: true,
            repeat: -1
        });

        //  Buttons to control the Tween timescale

        var text = this.add.text(180, 0, 'Click to Pause / Resume').setFont('32px Arial Black').setFill('#ffffff').setShadow(2, 2, "#333333", 2);

        var downButton = this.add.image(70, 530, 'down').setInteractive();
        var upButton = this.add.image(730, 530, 'up').setInteractive();

        var tweens = this.tweens;

        this.input.on('gameobjectup', function (pointer, gameobject)
        {
            if (gameobject === downButton && tweens.timeScale > 0)
            {
                tweens.pauseAll();

                text.setText('Pause All');
            }
            else if (gameobject === upButton && tweens.timeScale < 9.9)
            {
                tweens.resumeAll();

                text.setText('Resume All');
            }

        });
    }
}

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

const game = new Phaser.Game(config);

Создание и настройка твинов

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

Каждый твин создается с помощью метода this.tweens.add(). Внутри конфигурации задаются цели (targets), свойства для анимации (props), длительность, тип easing и поведение (повтор, отзеркаливание).

this.tweens.add({
    targets: image1,
    props: {
        x: { value: 700, duration: 4000, flipX: true },
        y: { value: 500, duration: 8000, },
    },
    ease: 'Sine.easeInOut',
    yoyo: true,
    repeat: -1
});

Здесь объект image1 будет двигаться по оси X до 700 пикселей за 4 секунды, одновременно по оси Y до 500 пикселей за 8 секунд. Параметр flipX: true автоматически переворачивает спрайт по горизонтали при достижении конечной точки. yoyo: true заставляет анимацию проигрываться в обратном порядке, а repeat: -1 делает её бесконечной. Все твины создаются аналогично, но с разными параметрами, чтобы рыбки двигались разнообразно.

Ссылка на менеджер твинов и создание UI

Для глобального управления всеми твинами сцены нужен доступ к менеджеру твинов. В примере он сохраняется в переменную tweens.

var tweens = this.tweens;

Также создается простой пользовательский интерфейс: две кнопки (вверх и вниз) и текстовое поле. Кнопкам назначается интерактивность с помощью метода .setInteractive(), что позволяет обрабатывать клики.

var downButton = this.add.image(70, 530, 'down').setInteractive();
var upButton = this.add.image(730, 530, 'up').setInteractive();
var text = this.add.text(180, 0, 'Click to Pause / Resume').setFont('32px Arial Black').setFill('#ffffff').setShadow(2, 2, "#333333", 2);

Обработка кликов и глобальное управление

Для обработки кликов по кнопкам используется событие gameobjectup системы ввода Phaser. Оно срабатывает, когда пользователь отпускает кнопку мыши над интерактивным игровым объектом.

this.input.on('gameobjectup', function (pointer, gameobject)
{
    if (gameobject === downButton && tweens.timeScale > 0)
    {
        tweens.pauseAll();
        text.setText('Pause All');
    }
    else if (gameobject === upButton && tweens.timeScale < 9.9)
    {
        tweens.resumeAll();
        text.setText('Resume All');
    }
});

При клике на нижнюю кнопку (downButton) вызывается метод tweens.pauseAll(). Он немедленно приостанавливает выполнение всех активных твинов в сцене. При этом их состояние (прогресс, позиции) сохраняется. При клике на верхнюю кнопку (upButton) вызывается tweens.resumeAll(), который возобновляет все твины с того места, где они остановились.

Проверка tweens.timeScale используется для предотвращения множественных вызовов pauseAll или resumeAll, которые могут привести к некорректному поведению. timeScale — это глобальный множитель скорости для всех твинов. При паузе он не меняется, но проверка > 0 и < 9.9 служит простой защитой.

Как это работает внутри

Методы pauseAll() и resumeAll() управляют внутренним состоянием каждого твина, созданного в менеджере сцены. Они не удаляют твины и не сбрасывают их прогресс.

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

// Это остановит все твины, созданные в этой сцене
this.tweens.pauseAll();

// А это возобновит их
this.tweens.resumeAll();

Эти методы идеально подходят для реализации паузы в игре, когда нужно заморозить все движения на экране, но сохранить возможность мгновенного восстановления геймплея.

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

Использование pauseAll() и resumeAll() — это простой и эффективный способ централизованного управления анимациями в Phaser. Это избавляет от необходимости отслеживать каждый твин отдельно. **Идеи для экспериментов:** 1. Добавьте третью кнопку для сброса всех твинов с помощью this.tweens.resetAll(). 2. Свяжите паузу твинов с системой паузы всей игры, например, при открытии меню. 3. Поэкспериментируйте с изменением tweens.timeScale для создания эффектов замедления или ускорения времени.