Реверс и замедление анимации

Библиотека Phaser предоставляет гибкий механизм управления анимациями спрайтов. Помимо базового воспроизведения кадров, важное значение имеют реверс (обратное воспроизведение) и изменение скорости проигрывания. Эти инструменты позволяют реализовывать эффекты замедленного движения, «отмотки времени», зеркальных анимаций, динамического управления состояниями персонажа и визуальных акцентов.


Архитектура анимаций в Phaser

В основе системы лежат объекты:

  • Phaser.Animations.Animation — описание анимации (набор кадров, частота, режим повтора).
  • Phaser.Animations.AnimationState — состояние воспроизведения конкретного спрайта.
  • Phaser.GameObjects.Sprite — объект, на котором проигрывается анимация.

Создание анимации выполняется через this.anims.create():

this.anims.create({
    key: 'run',
    frames: this.anims.generateFrameNumbers('player', { start: 0, end: 7 }),
    frameRate: 12,
    repeat: -1
});

Параметр frameRate определяет количество кадров в секунду, а repeat задаёт число повторов (-1 — бесконечно).


Реверс анимации

1. Использование свойства yoyo

Простейший способ реализовать обратное воспроизведение — включить параметр yoyo.

this.anims.create({
    key: 'pulse',
    frames: this.anims.generateFrameNumbers('orb', { start: 0, end: 5 }),
    frameRate: 10,
    repeat: -1,
    yoyo: true
});

Принцип работы:

  • Анимация проигрывается вперёд.
  • После достижения последнего кадра направление меняется.
  • Кадры воспроизводятся в обратном порядке.
  • Цикл повторяется.

Этот метод подходит для циклических эффектов (пульсация, мигание, дыхание).


2. Принудительный реверс через reverse()

Метод reverse() объекта AnimationState позволяет динамически изменить направление:

let sprite = this.add.sprite(100, 100, 'player');
sprite.play('run');

// В какой-то момент:
sprite.anims.reverse();

Особенности:

  • Направление меняется без перезапуска анимации.
  • Текущий кадр сохраняется.
  • Повторный вызов возвращает исходное направление.

Это удобно для механик «перемотки времени» или смены состояния движения.


3. Запуск анимации сразу в обратном направлении

Метод playReverse() позволяет начать проигрывание с конца:

sprite.playReverse('run');

Поведение:

  • Старт происходит с последнего кадра.
  • Дальнейшее воспроизведение — в обратном порядке.
  • Учитываются параметры repeat и yoyo.

4. Отслеживание направления

Свойство sprite.anims.forward показывает текущее направление:

if (!sprite.anims.forward) {
    // Анимация воспроизводится в обратную сторону
}

Это важно при построении логики состояний и синхронизации физики с визуализацией.


Управление скоростью анимации

1. Изменение frameRate при создании

Статическая скорость задаётся при создании анимации:

this.anims.create({
    key: 'slowWalk',
    frames: this.anims.generateFrameNumbers('player', { start: 0, end: 7 }),
    frameRate: 6,
    repeat: -1
});

Меньший frameRate — более медленная анимация.


2. Свойство timeScale

Для динамического изменения скорости используется timeScale.

sprite.play('run');
sprite.anims.timeScale = 0.5;

Значения:

  • 1 — нормальная скорость
  • 0.5 — замедление в 2 раза
  • 2 — ускорение в 2 раза
  • 0 — полная остановка

Ключевая особенность: timeScale влияет только на конкретную анимацию спрайта.


3. Глобальное замедление всех анимаций

Менеджер анимаций сцены также имеет globalTimeScale:

this.anims.globalTimeScale = 0.3;

Эффект:

  • Все анимации в сцене замедляются.
  • Удобно для реализации режима «slow motion».
  • Не влияет на физику автоматически.

Реализация эффекта замедленного времени

Пример логики:

activateSlowMotion() {
    this.anims.globalTimeScale = 0.3;
    this.physics.world.timeScale = 0.3;

    this.time.delayedCall(2000, () => {
        this.anims.globalTimeScale = 1;
        this.physics.world.timeScale = 1;
    });
}

В данном случае:

  • Замедляются анимации.
  • Замедляется физический движок.
  • Через 2 секунды параметры возвращаются к норме.

Плавное изменение скорости

Мгновенное изменение timeScale создаёт резкий переход. Для плавного эффекта используется система tween.

this.tweens.add({
    targets: sprite.anims,
    timeScale: 0.2,
    duration: 1000,
    ease: 'Linear'
});

Результат:

  • Скорость постепенно уменьшается.
  • Визуально создаётся ощущение замедления времени.

Остановка и пауза

Пауза

sprite.anims.pause();

Возобновление

sprite.anims.resume();

Полная остановка

sprite.anims.stop();

Различия:

  • pause() сохраняет текущий кадр.
  • stop() завершает анимацию и может сбросить состояние.

Комбинация реверса и замедления

Интересные эффекты возникают при совместном применении:

sprite.play('run');
sprite.anims.timeScale = 0.5;
sprite.anims.reverse();

Возможные сценарии:

  • Замедленная «перемотка времени»
  • Медленный отскок
  • Эффект воспоминания
  • Визуализация отката действия

Работа с событиями анимации

Phaser генерирует события:

  • animationstart
  • animationupdate
  • animationrepeat
  • animationcomplete

Пример:

sprite.on('animationcomplete', (animation) => {
    if (animation.key === 'run') {
        sprite.playReverse('run');
    }
});

Так реализуется автоматический реверс после завершения.


Практическая схема управления направлением

Пример механики отката движения:

update() {
    if (this.input.keyboard.isDown(Phaser.Input.Keyboard.KeyCodes.R)) {
        this.player.anims.reverse();
        this.player.setVelocityX(-100);
    }
}

В результате:

  • Анимация бега меняет направление.
  • Персонаж начинает двигаться в противоположную сторону.
  • Визуальное поведение соответствует логике игры.

Особенности производительности

Реверс и изменение timeScale не создают новых массивов кадров. Phaser просто меняет:

  • индекс текущего кадра,
  • направление счётчика,
  • множитель времени.

Поэтому операции выполняются быстро и не требуют дополнительной памяти.


Ограничения и важные моменты

  1. timeScale не влияет на звук.
  2. Замедление анимации не замедляет таймеры автоматически.
  3. При timeScale = 0 анимация «замирает», но события сцены продолжают работать.
  4. При использовании yoyo следует учитывать параметр repeat, иначе анимация завершится после одного цикла.

Синхронизация с физикой Arcade

В проектах с Arcade Physics требуется синхронизация:

this.physics.world.timeScale = 0.5;

Если замедлить только анимацию, персонаж будет двигаться быстро, но визуально «бежать медленно», что создаёт рассинхронизацию.


Продвинутый сценарий: перемотка времени

Базовый алгоритм:

  1. Сохранение состояния позиции и кадров.
  2. Переключение направления анимации.
  3. Установка отрицательной скорости движения.
  4. Плавное изменение timeScale.

Пример:

rewind() {
    this.player.anims.playReverse('run');
    this.player.anims.timeScale = 0.4;
    this.player.setVelocityX(-200);
}

Такой подход позволяет создать кинематографичный эффект без сложной логики пересчёта кадров.


Итоговая модель управления

Для гибкого контроля анимаций используются:

  • play()
  • playReverse()
  • reverse()
  • timeScale
  • globalTimeScale
  • pause() / resume()
  • yoyo

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