О чем этот пример
Управление ресурсами — ключевой навык при разработке игр. В Phaser можно не только создавать анимации, но и удалять их во время работы игры, чтобы освободить память или динамически менять контент. Эта статья покажет, как корректно удалить анимацию через глобальный менеджер `Animation Manager` и как подписаться на событие `REMOVE_ANIMATION`, чтобы реагировать на это действие. Это полезно для оптимизации и создания интерактивных сцен, где набор анимаций меняется в ответ на действия игрока.
Версия 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.atlas('gems', 'assets/tests/columns/gems.png', 'assets/tests/columns/gems.json');
}
create ()
{
const text = this.add.text(400, 32, 'Click to remove the Square animation', { color: '#00ff00' }).setOrigin(0.5, 0);
const diamond = this.anims.create({ key: 'diamond', frames: this.anims.generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 }), repeat: -1 });
const prism = this.anims.create({ key: 'prism', frames: this.anims.generateFrameNames('gems', { prefix: 'prism_', end: 6, zeroPad: 4 }), repeat: -1 });
const ruby = this.anims.create({ key: 'ruby', frames: this.anims.generateFrameNames('gems', { prefix: 'ruby_', end: 6, zeroPad: 4 }), repeat: -1 });
const square = this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
// square added twice just to make sure there are more of them
const keys = [ 'diamond', 'prism', 'ruby', 'square', 'square' ];
let x = 100;
let y = 116;
for (let i = 0; i < 35; i++)
{
this.add.sprite(x, y, 'gems').play(keys[Phaser.Math.Between(0, 4)]);
x += 100;
if (x === 800)
{
x = 100;
y += 100;
}
}
this.anims.on(Phaser.Animations.Events.REMOVE_ANIMATION, function (key, anim) {
text.setText('Animation ' + key + ' has been removed');
});
this.input.once('pointerdown', function () {
// We'll now remove the square animation from the global Animation Manager
this.anims.remove('square');
}, this);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Создание набора анимаций
В примере в методе create создаются четыре анимации на основе одного атласа gems. Ключевой момент — использование метода this.anims.create. Каждая анимация получает уникальный ключ (key), например, 'square'. Затем эти ключи помещаются в массив, и в цикле создаются спрайты, которые случайным образом проигрывают одну из анимаций.
const diamond = this.anims.create({ key: 'diamond', frames: this.anims.generateFrameNames('gems', { prefix: 'diamond_', end: 15, zeroPad: 4 }), repeat: -1 });
const square = this.anims.create({ key: 'square', frames: this.anims.generateFrameNames('gems', { prefix: 'square_', end: 14, zeroPad: 4 }), repeat: -1 });
Подписка на событие удаления анимации
Глобальный менеджер анимаций this.anims является экземпляром Phaser.Animations.AnimationManager и эмиттером событий. Чтобы отследить момент удаления анимации, используется событие Phaser.Animations.Events.REMOVE_ANIMATION. В обработчик события передаются два аргумента: ключ удалённой анимации и её объект. В примере это событие используется для обновления текста на экране.
this.anims.on(Phaser.Animations.Events.REMOVE_ANIMATION, function (key, anim) {
text.setText('Animation ' + key + ' has been removed');
});
Удаление анимации по событию ввода
Удаление анимации инициируется по клику мыши. Метод this.input.once регистрирует одноразовый обработчик для события pointerdown. Внутри него вызывается this.anims.remove('square'). Это удаляет анимацию с ключом 'square' из менеджера. Важно: все спрайты, которые в этот момент проигрывали данную анимацию, перестанут её отображать, так как ссылка на объект анимации будет удалена.
this.input.once('pointerdown', function () {
this.anims.remove('square');
}, this);
Поведение спрайтов после удаления анимации
После вызова remove('square') анимация square больше не существует в менеджере. Спрайты, которые её проигрывали, не получают автоматически новую анимацию — они просто перестают обновлять кадры. Визуально они "заморозятся" на том кадре, который был активен в момент удаления. Это поведение нужно учитывать: если требуется плавный переход, перед удалением стоит остановить анимацию на спрайтах или назначить им новую.
// Пример: перед удалением можно остановить анимацию на всех спрайтах
// Для этого потребуется хранить ссылки на созданные спрайты.
Что попробовать дальше
Удаление анимаций через this.anims.remove() и обработка события REMOVE_ANIMATION дают контроль над ресурсами в runtime. Это можно использовать для динамической выгрузки неиспользуемых анимаций в больших играх или для смены визуального стиля уровня. Поэкспериментируйте: попробуйте удалять анимации не по клику, а по таймеру, или создайте систему, которая автоматически удаляет анимации, не использовавшиеся определённое время. Также можно модифицировать пример, чтобы при удалении анимации square все affected спрайты плавно переключались на анимацию diamond.
