О чем этот пример
В процессе разработки игры часто возникает необходимость прервать анимацию объекта по какому-либо событию — например, при клике игрока или изменении состояния. Phaser предоставляет для этого метод `killTweensOf()`, но его поведение может оказаться неочевидным. В этой статье мы разберем, почему вызов этого метода непосредственно после создания твина не работает, и как правильно организовать управление анимациями в вашем проекте, чтобы избежать багов и неожиданного поведения.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
function create ()
{
var marker = this.add.image(100, 300, 'block').setAlpha(0.3);
var image = this.add.image(100, 300, 'block');
var tween = this.tweens.add({
targets: image,
x: 700,
delay: 1000,
duration: 6000,
ease: 'Power2'
});
// doesnt stop tween
this.tweens.killTweensOf(image);
this.input.on('pointerdown', ()=>{
// does stop tween
this.tweens.killTweensOf(image);
});
}
Проблема: твин не останавливается при создании
В исходном примере твин создается для перемещения спрайта image от координаты x=100 до x=700 с задержкой в 1 секунду. Сразу после создания вызывается метод this.tweens.killTweensOf(image), который, по идее, должен остановить все твины, связанные с этим объектом. Однако анимация продолжает выполняться после задержки.
Это происходит из-за того, что твин в Phaser имеет внутреннее состояние. При создании он еще не активирован (не начал выполняться) из-за указанной задержки (delay: 1000). Метод killTweensOf() на данном этапе не находит активных твинов для данного целевого объекта и, следовательно, ничего не останавливает.
var tween = this.tweens.add({
targets: image,
x: 700,
delay: 1000,
duration: 6000,
ease: 'Power2'
});
// Этот вызов не сработает, твин еще не активен
this.tweens.killTweensOf(image);
Решение: остановка по событию
Чтобы успешно прервать выполнение твина, нужно вызывать killTweensOf() когда твин уже активен. В примере это реализовано через обработчик события клика (pointerdown). В момент клика твин уже запущен (прошла задержка в 1 секунду), и метод корректно находит и останавливает его.
Этот подход следует использовать для управления анимациями в ответ на действия игрока или изменения игровой логики. Например, остановка движения персонажа при получении урона или прерывание анимации меню при переходе в другой режим.
this.input.on('pointerdown', () => {
// Теперь твин активен, и вызов остановит его
this.tweens.killTweensOf(image);
});
Альтернативы: полный контроль над твинами
Помимо killTweensOf(), Phaser предлагает другие методы для управления твинами, которые могут быть полезны в разных сценариях.
1. **Сохранение ссылки на твин:** При создании твина можно сохранить возвращаемый объект в переменную. Это позволяет управлять им напрямую через методы pause(), resume(), stop() или destroy().
2. **Глобальная остановка:** Метод this.tweens.killAll() останавливает все твины в текущей сцене. Полезно при смене сцены или полной перезагрузке игрового состояния.
3. **Проверка состояния:** У объекта твина есть свойства, такие как isPlaying(), которые позволяют проверить, активен ли он в данный момент.
// Создание твина с сохранением ссылки
var myTween = this.tweens.add({
targets: image,
x: 700,
duration: 3000
});
// Прямое управление через ссылку
myTween.pause();
myTween.resume();
myTween.stop(); // Немедленная остановка и возврат в начало
myTween.destroy(); // Полное уничтожение твина
// Остановка всех твинов в сцене
this.tweens.killAll();
Практические рекомендации
1. **Планируйте события:** Если вам нужно отменить твин сразу после его создания, возможно, стоит пересмотреть логику и не создавать его вовсе, либо создавать без задержки.
2. **Используйте обработчики событий:** Для интерактивной остановки всегда привязывайте killTweensOf() к конкретным игровым событиям (ввод, коллизия, таймер), а не к моменту создания.
3. **Очищайте твины при смене сцены:** Чтобы избежать утечек памяти и выполнения фоновых анимаций, вызывайте this.tweens.killAll() в методе shutdown() или destroy() вашей сцены.
4. **Документируйте сложные анимации:** Если в сцене много пересекающихся твинов, ведите список их целей и условий остановки для упрощения отладки.
// Пример очистки при уничтожении сцены
class GameScene extends Phaser.Scene {
...
shutdown() {
// Гарантированно останавливаем все анимации при выходе из сцены
this.tweens.killAll();
}
}
Что попробовать дальше
Корректное управление твинами — ключ к созданию отзывчивого и предсказуемого геймплея. Основной вывод: метод killTweensOf() работает только с активными твинами. Для надежного контроля сохраняйте ссылки на анимации или привязывайте их остановку к четким событиям в игре. Для экспериментов попробуйте создать цепочку твинов (chain) и реализовать систему приоритетной остановки одного из них, либо управлять анимациями через пользовательские события (this.events), чтобы разделить логику создания и прерывания.
