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

Работа с анимациями — ключевая часть создания динамичных игр. Phaser 3 предоставляет мощную систему твинов, а метод `tweens.chain()` позволяет объединять несколько анимаций в последовательную цепочку. Однако тонкости настройки задержки (`delay`) могут вызвать неожиданное поведение. В этой статье мы разберем конкретный пример, который демонстрирует, как правильно задавать общую задержку для всей цепочки, избегая типичных ошибок. Это знание поможет вам создавать более контролируемые и сложные анимационные последовательности.

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

Живой запуск

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

Исходный код


/* global colors, Phaser */

class Example extends Phaser.Scene
{

  preload ()
  {
    this.load.image('mySprite', 'https://labs.phaser.io/assets/particles/red.png');
  }

  create ()
  {
    // const sprite = this.add.image(400, 300, 'mySprite');

    // this.tweens.chain({
    //   delay: 1,
    //   tweens: [
    //     {
    //       targets: sprite,
    //       x: 500
    //     }
    //   ]
    // });

    this.objToTween = this.add.circle(this.scale.width / 2, this.scale.height / 2, 50, 0xff0000);

    const chain = this.tweens.chain({
      delay: 1,
      tweens: [
        { targets: this.objToTween, duration: 500, props: { alpha: 0 } },
        { targets: this.objToTween, duration: 500, props: { alpha: 1 } },
        { targets: this.objToTween, duration: 500, props: { alpha: 0 } },
        { targets: this.objToTween, duration: 500, props: { alpha: 1 } },
      ],
    });
  }
}

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

new Phaser.Game(config);

Создание объекта для анимации

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

Метод this.add.circle() создает круг с заданными координатами, радиусом и цветом. Центр круга размещается по центру игрового холста, используя свойства this.scale.width и this.scale.height. Ссылка на созданный круг сохраняется в свойстве сцены this.objToTween, чтобы быть доступной для твинов.

this.objToTween = this.add.circle(this.scale.width / 2, this.scale.height / 2, 50, 0xff0000);

Настройка цепочки твинов

Цепочка твинов создается с помощью метода this.tweens.chain(). Он принимает объект конфигурации. Ключевой параметр в нашем примере — delay. Он устанавливает задержку в миллисекундах **перед началом выполнения всей цепочки**. Это важно понимать: задержка применяется один раз к первому твину в последовательности, а не к каждому твину по отдельности.

Массив tweens содержит конфигурации для отдельных анимаций. Каждый элемент массива — это объект, описывающий один твин.

const chain = this.tweens.chain({
  delay: 1000, // Задержка 1 секунда (1000 мс) перед стартом цепочки
  tweens: [
    // Первый твин: плавное исчезновение круга за 500 мс
    { targets: this.objToTween, duration: 500, props: { alpha: 0 } },
    // Второй твин: плавное появление круга за 500 мс
    { targets: this.objToTween, duration: 500, props: { alpha: 1 } },
    // Третий твин: повторное исчезновение
    { targets: this.objToTween, duration: 500, props: { alpha: 0 } },
    // Четвертый твин: повторное появление
    { targets: this.objToTween, duration: 500, props: { alpha: 1 } },
  ],
});

Обратите внимание: в оригинальном примере значение delay равно `1. Это технически корректно (1 миллисекунда), но на практике такая задержка почти незаметна. В пояснении выше мы использовали значение1000` для наглядности.

Структура отдельного твина в цепочке

Каждый объект в массиве tweens настраивается по тем же правилам, что и обычный твин, создаваемый через this.tweens.add(). Основные свойства:

* targets: объект или массив объектов, к которым применяется анимация. * duration: длительность анимации в миллисекундах. * props: объект, ключи которого — это свойства targets, а значения — целевые значения для анимации.

В нашем случае анимируется только свойство alpha (прозрачность) от 1 (полностью видимый) до 0 (полностью прозрачный) и обратно.

{ targets: this.objToTween, duration: 500, props: { alpha: 0 } }

Твины в цепочке выполняются строго последовательно. Второй твин начнется только после полного завершения первого, и так далее.

Распространенная ошибка: задержка для каждого твина

Новички часто предполагают, что параметр delay в конфигурации цепочки добавит паузу между каждым твином. Это не так. delay работает только один раз — в самом начале.

Если вам нужна пауза **между** анимациями в цепочке, ее необходимо явно добавлять в конфигурацию каждого отдельного твина с помощью его собственного свойства delay. Либо можно создать отдельный твин-паузу, который ничего не анимирует.

Пример ошибочного ожидания (так НЕ работает):

// НЕПРАВИЛЬНО: задержка не будет повторяться между твинами.
const chain = this.tweens.chain({
  delay: 500, // Сработает только перед первым твином
  tweens: [tween1, tween2, tween3]
});

Правильный способ добавить паузы между твинами:

const chain = this.tweens.chain({
  tweens: [
    { targets: obj, duration: 500, x: 400 },
    // Пауза 300 мс перед следующим твином:
    { targets: obj, duration: 0, delay: 300 },
    { targets: obj, duration: 500, y: 300 },
  ],
});

Управление и переиспользование цепочки

Метод this.tweens.chain() возвращает объект TweenChain. Его можно сохранить в переменную (как chain в примере) для дальнейшего управления.

С помощью этого объекта вы можете: * Остановить всю цепочку: chain.stop(). * Перезапустить цепочку с начала: chain.restart(). * Установить флаг повторения для всей цепочки, добавив в изначальную конфигурацию свойство loop (или repeat с repeatDelay).

const chain = this.tweens.chain({
  delay: 1000,
  tweens: [ /* массив твинов */ ],
  loop: 3 // Вся цепочка повторится 3 раза
});

// Где-то в коде по условию:
if (playerHit) {
  chain.stop(); // Останавливаем анимацию при попадании
}

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

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

Использование tweens.chain() в Phaser 3 — это мощный инструмент для создания последовательных анимаций. Главный вывод: общий параметр delay задает задержку только перед стартом всей цепочки, а не между ее элементами. Для создания пауз внутри последовательности используйте свойство delay в конфигурации отдельных твинов. Для экспериментов попробуйте: 1. Создать цепочку, которая перемещает объект по сложной траектории (например, квадрату), добавляя паузы в каждой вершине. 2. Скомбинировать анимацию разных свойств: alpha, scale, angle. 3. Связать цепочку с игровыми событиями, например, запускать сложную анимацию уничтожения врага при его смерти, а затем останавливать ее, если враг неожиданно воскресает.