О чем этот пример
При создании игр часто требуется синхронизировать игровые события с кадрами анимации. Например, чтобы персонаж оставлял следы, стрелял в такт движению или издавал звуки на определённых фазах. Phaser предоставляет для этого удобное событие `animationrepeat`. Эта статья покажет, как использовать его для создания эффектов, привязанных к циклам анимации, на примере мумии, оставляющей за собой след.
Версия 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('poo', 'assets/sprites/poo.png');
this.load.spritesheet('mummy', 'assets/animations/mummy37x45.png', { frameWidth: 37, frameHeight: 45 });
}
create ()
{
const mummyAnimation = this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('mummy'),
frameRate: 16
});
const sprite = this.add.sprite(50, 300, 'mummy').setScale(4);
sprite.play({ key: 'walk', repeat: 7 });
this.tweens.add({
targets: sprite,
x: 750,
duration: 8800,
ease: 'Linear'
});
sprite.on('animationrepeat', function () {
const poop = this.add.image(sprite.x - 32, 300, 'poo').setScale(0.5);
this.tweens.add({
targets: poop,
props: {
x: {
value: '-=64', ease: 'Power1'
},
y: {
value: '+=50', ease: 'Bounce.easeOut'
}
},
duration: 750
});
}, this);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Зачем нужно событие animationrepeat?
Событие animationrepeat срабатывает каждый раз, когда анимация спрайта завершает один цикл и начинает следующий. Это особенно полезно для анимаций, у которых задано свойство repeat. В отличие от событий animationstart или animationcomplete, оно позволяет выполнять код на каждом повторении, а не только в начале или конце всей последовательности.
В примере анимация 'ходьбы' мумии повторяется 7 раз. Мы можем привязать к каждому такту ходьбы создание нового объекта (например, следа), что создаёт ритмичный и синхронизированный с движением визуальный эффект.
Создание анимации и запуск с повторением
Первым делом создаётся сама анимация из спрайтшита. Ключевой момент — указание количества повторов при запуске анимации с помощью метода play().
const mummyAnimation = this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('mummy'),
frameRate: 16
});
const sprite = this.add.sprite(50, 300, 'mummy').setScale(4);
sprite.play({ key: 'walk', repeat: 7 });
Здесь repeat: 7 означает, что полная последовательность кадров проиграется 8 раз (1 начальный + 7 повторов). Параллельно с анимацией запускается tween, который плавно перемещает спрайт по горизонтали, создавая иллюзию ходьбы.
Подписка на событие и создание объектов
Ядро примера — подписка на событие animationrepeat у спрайта. Обработчик события будет вызываться 7 раз, по одному разу за каждый повтор после первого проигрывания.
sprite.on('animationrepeat', function () {
const poop = this.add.image(sprite.x - 32, 300, 'poo').setScale(0.5);
// ... tween для poop
}, this);
Важно передать контекст this (текущую сцену) третьим аргументом в on(). Это позволяет внутри функции-обработчика использовать методы сцены, такие как this.add.image и this.tweens.add. В данном случае при каждом повторе анимации позади мумии (на sprite.x - 32) создаётся уменьшенное изображение 'poo'.
Анимация вложенных объектов (tween)
Чтобы созданные объекты 'poo' не просто появлялись, а оживали, к каждому из них применяется отдельная твин-анимация. Она запускается сразу после создания объекта.
this.tweens.add({
targets: poop,
props: {
x: { value: '-=64', ease: 'Power1' },
y: { value: '+=50', ease: 'Bounce.easeOut' }
},
duration: 750
});
Этот твин делает две вещи: сдвигает объект на 64 пикселя влево (относительно текущей позиции) и бросает его вниз на 50 пикселей с 'пружинящим' эффектом (Bounce.easeOut). Длительность в 750 мс позволяет всем следам анимироваться почти одновременно с шагами мумии, создавая цельный эффект.
Что попробовать дальше
Событие animationrepeat — это мощный инструмент для синхронизации игровых событий с ритмом анимации. В рассмотренном примере оно использовалось для визуальных эффектов, но область применения шире: можно запускать звуки шагов, частицы, проверку столкновений или изменение состояния персонажа.
**Идеи для экспериментов:**
1. Привязать к событию не создание спрайта, а эмиттер частиц для создания пыли или следов.
2. Менять в обработчике frameRate анимации, чтобы создать эффект ускорения или замедления.
3. Использовать данные из event объекта в обработчике (например, event.frame), чтобы действие выполнялось только на определённых кадрах повтора.
