Система анимаций в Phaser построена вокруг объектов
Animation и AnimationState, которые управляют
проигрыванием кадров, цикличностью, скоростью и жизненным циклом
анимации. Ключевую роль в интеграции анимаций с игровой логикой играют
события, генерируемые во время их выполнения.
События позволяют реагировать на различные этапы жизненного цикла анимации:
start)repeat)complete)animationupdate)Обработчики событий подключаются через систему событий
EventEmitter, встроенную в игровые объекты
(Sprite, Image, TileSprite и
др.).
Анимации в Phaser определяются через менеджер анимаций сцены:
this.anims.create({
key: 'run',
frames: this.anims.generateFrameNumbers('player', { start: 0, end: 5 }),
frameRate: 10,
repeat: -1
});
При воспроизведении:
player.play('run');
объект player (экземпляр
Phaser.GameObjects.Sprite) начинает генерировать события
анимации.
События испускаются самим игровым объектом, а не глобальным менеджером. Это позволяет создавать независимую реакцию для каждого экземпляра спрайта.
startСобытие animationstart (сокращённо start в
контексте анимации) возникает в момент начала воспроизведения анимации —
когда она фактически стартует, а не просто назначается.
player.on('animationstart', function (animation, frame) {
console.log('Анимация запущена:', animation.key);
});
animation — объект анимацииframe — первый активный кадрgameObject — объект, воспроизводящий анимациюПример с изменением состояния:
player.on('animationstart', function (animation) {
if (animation.key === 'attack') {
player.isAttacking = true;
}
});
repeatСобытие animationrepeat генерируется каждый раз, когда
анимация с параметром repeat > 0 или
repeat: -1 начинает новый цикл.
this.anims.create({
key: 'blink',
frames: this.anims.generateFrameNumbers('enemy', { start: 0, end: 2 }),
frameRate: 5,
repeat: 3
});
enemy.on('animationrepeat', function (animation, frame) {
console.log('Повтор анимации:', animation.key);
});
repeat: -1При бесконечном повторе событие repeat будет вызываться
при каждом переходе от последнего кадра к первому.
Пример подсчёта повторов:
let repeatCount = 0;
enemy.on('animationrepeat', function () {
repeatCount++;
});
completeСобытие animationcomplete вызывается при полном
завершении анимации, если:
repeat имеет конечное значениеstop()player.on('animationcomplete', function (animation, frame) {
console.log('Анимация завершена:', animation.key);
});
Phaser автоматически генерирует события вида:
animationcomplete-ключ
Пример:
player.on('animationcomplete-attack', function () {
player.isAttacking = false;
});
Такой подход исключает необходимость вручную проверять
animation.key.
Пример удаления врага:
enemy.on('animationcomplete-death', function () {
enemy.destroy();
});
animationupdateanimationupdate вызывается при каждом изменении
кадра анимации. Это наиболее часто генерируемое событие и
используется для синхронизации логики с конкретными кадрами.
player.on('animationupdate', function (animation, frame) {
console.log('Текущий кадр:', frame.index);
});
animationframegameObjectframeKey (в зависимости от типа кадров)player.on('animationupdate', function (animation, frame) {
if (animation.key === 'attack' && frame.index === 3) {
spawnHitbox();
}
});
Так реализуется точная синхронизация удара с визуальным моментом.
Поскольку событие вызывается на каждом кадре анимации, его использование требует аккуратности:
stop
и completeЕсли анимация останавливается методом:
player.anims.stop();
событие complete не будет вызвано. В этом случае можно
использовать событие animationstop:
player.on('animationstop', function (animation) {
console.log('Анимация остановлена вручную');
});
player.once('animationcomplete', function () {
console.log('Сработает один раз');
});
function onComplete(animation) {
console.log(animation.key);
}
player.on('animationcomplete', onComplete);
player.off('animationcomplete', onComplete);
Правильное управление подписками предотвращает утечки памяти и дублирование логики.
События анимации часто используются совместно с FSM (Finite State Machine). Например:
class Player {
constructor(sprite) {
this.sprite = sprite;
this.state = 'idle';
sprite.on('animationcomplete-attack', () => {
this.setState('idle');
});
}
setState(newState) {
this.state = newState;
this.sprite.play(newState);
}
}
В этом подходе завершение анимации напрямую инициирует переход состояния.
Если во время выполнения анимации запускается другая:
player.play('run');
текущая анимация:
completeanimationstopНовая анимация сгенерирует start.
Порядок событий:
animationstopanimationstartПонимание этого порядка критично для сложной логики поведения.
Каждый спрайт генерирует собственные события. Для массовой обработки:
this.enemies.children.iterate(enemy => {
enemy.on('animationcomplete-death', function () {
enemy.destroy();
});
});
События не распространяются автоматически по группе; обработчики назначаются индивидуально.
При использовании модуля физики (Arcade Physics):
player.on('animationupdate', function (animation, frame) {
if (animation.key === 'jump' && frame.index === 2) {
player.body.setVelocityY(-300);
}
});
Это позволяет запускать импульс строго в нужный момент визуальной фазы прыжка.
Анимация работает независимо от update() сцены. События
испускаются на основе внутреннего таймера анимации
(frameRate, timeScale). Это обеспечивает:
timeScaleМенеджер анимаций сцены также испускает события, но в большинстве случаев предпочтительна работа через конкретный объект.
Изменение скорости анимации во время выполнения:
player.anims.timeScale = 2;
События update, repeat,
complete будут происходить быстрее, но их логическая
последовательность сохранится.
1. Подписка до создания объекта
Обработчик должен назначаться после создания спрайта.
2. Множественная подписка в
update()
Недопустимо:
update() {
player.on('animationcomplete', handler);
}
Это приводит к лавинообразному росту обработчиков.
3. Игнорирование прерывания анимации
Логика, завязанная только на complete, может не
выполниться при смене анимации.
Эффективная модель работы с анимациями включает:
startanimationupdaterepeatcompletestopТакая архитектура делает систему поведения предсказуемой и масштабируемой при разработке сложных игровых механик.