
Как сделать полный stop() мувиклипу
Однажды столкнулся я с проблемой — нужно остановить мувиклип перед тем, как положить его обратно в пул. Чтобы гад не крутился там в небытии и не жрал ресурсы. Однако метод stop() останавливает только таймлайн самого мувиклипа, а все мувиклипы-дети, которые на нем крутятся — продолжают крутиться. Например, если у вас есть клип «танк», в котором есть анимация кручения гусеницами, но дополнительно в нем есть клип «человечек в люке», который машет флажком. То после метода stop() на танке гусеницы остановятся. А человечек все машет и машет, машет и машет. Танк может уже удалили, но пока его не зачистил гарбадж коллектор — он машет и машет, проц напрягается и напрягается. А если у вас реализован пул танков, то сотни танков в пуле и на каждом человечек машет и машет флажком… Ужос!

Понятно, что надо делать метод, который иерархически обегает все это хозяйство и делает ему stop(). В случае танка, кстати, теоретически, если у вас архитектурно-оопешно в коде все правильно сделано, то, по идее, танк знает о человечке и стоп должен быть неуниверсальный для всех клипов, а реализован в классе танк. Ведь, возможно надо кроме стопа анимации человечка дополнительно отключить ему мозги (отвязаться от квантов или энтерфрейм у кого похуже сделано). Мозги то тоже жрут ресурсы в небытии.
Однако, есть масса мест, где хорошо бы иметь универсальный метод остановить намертво все анимации. Например, если у вас view для юнита не связано с логикой. Ну типа это художник так сделал, как удобно — не все анимации в одном таймлайне и гусеницы и флажок. А иерархически. Тут можно порассуждать про Graphic vs MovieClip во FlashIDE, но это отдельная тема. Достаточно того, что полно ситуаций когда вариант view сложносоставное, но с логикой не связанное. Например в сложной системе анимированных меню.
И вот, наконец. Мы можем сделать универсальный статический утилити метод в каком-нибудь классе MovieClipUtility который использовать каждый раз, когда надо намертво застопорить мувиклип. А можно добавить самому в класс MovieClip такой недостающий метод stopAll() (ау Адоби!). Я делаю это так — метод upgradeMovieClip дергаю в самом начале конструктора главного класса игры. И все. Теперь можно дергать у клипов метод stopAll().
Может кому-то пригодится. Или покритикуйте.

Понятно, что надо делать метод, который иерархически обегает все это хозяйство и делает ему stop(). В случае танка, кстати, теоретически, если у вас архитектурно-оопешно в коде все правильно сделано, то, по идее, танк знает о человечке и стоп должен быть неуниверсальный для всех клипов, а реализован в классе танк. Ведь, возможно надо кроме стопа анимации человечка дополнительно отключить ему мозги (отвязаться от квантов или энтерфрейм у кого похуже сделано). Мозги то тоже жрут ресурсы в небытии.
Однако, есть масса мест, где хорошо бы иметь универсальный метод остановить намертво все анимации. Например, если у вас view для юнита не связано с логикой. Ну типа это художник так сделал, как удобно — не все анимации в одном таймлайне и гусеницы и флажок. А иерархически. Тут можно порассуждать про Graphic vs MovieClip во FlashIDE, но это отдельная тема. Достаточно того, что полно ситуаций когда вариант view сложносоставное, но с логикой не связанное. Например в сложной системе анимированных меню.
И вот, наконец. Мы можем сделать универсальный статический утилити метод в каком-нибудь классе MovieClipUtility который использовать каждый раз, когда надо намертво застопорить мувиклип. А можно добавить самому в класс MovieClip такой недостающий метод stopAll() (ау Адоби!). Я делаю это так — метод upgradeMovieClip дергаю в самом начале конструктора главного класса игры. И все. Теперь можно дергать у клипов метод stopAll().
Может кому-то пригодится. Или покритикуйте.
protected function upgradeMovieClip() : void {
MovieClip.prototype.stopAll = function(dObjCont : DisplayObjectContainer = null) : void {
if (dObjCont != null) {
var mc : MovieClip = dObjCont as MovieClip;
if (mc != null) {
mc.stop();
}
} else {
stop();
dObjCont = this;
}
var contLength : int = dObjCont.numChildren;
for (var i : int = 0; i < contLength; i++) {
var dObjChildCont : DisplayObjectContainer = dObjCont.getChildAt(i) as DisplayObjectContainer;
if (dObjChildCont != null) {
this.stopAll(dObjChildCont);
}
}
};
}
- +10
- scmorr
Комментарии (28)
Кстати, буквально недавно сталкивался с подобной проблемой. Только там у меня ещё и звук в кадрах был. Не сразу понял, что за фигня. (:
Спасибо. бум знать.
Натыкался на проблему, что некоторые детки могут быть в состоянии «стоп» до нажатия паузы, и соответствено при при запуске клипа им нужно это состояние сохранить.
И еще: можно сделать все проще: в базовом классе всех игровых объектов подписаться на REMOVED_FROM_STAGE и там вызывать stop() (а на ADDED_TO_STAGE gotoAndPlay() если надо).
Про «проще сделать» тоже не понял. Пробежаться по всей иерархии и всех подписать на REMOVED_FROM_STAGE? Это-ж жесть.
2) Нет, просто наследовать все игровые объекты не от MovieClip, а от некоего BaseObject, который сам подписывается на REMOVED_FROM_STAGE при инициализации. Причем на базе общего предка можно организовать и универсальную автоматическую отписку от ENTER_FRAME.
2) Ок — пусть у меня есть TankMC — мувиклип из библиотеки. Там внутри художник в иерархии использовал мувиклип флага. Пусть как вы просите — у меня игровой объект Tank наследован от BaseObject, он подписывается на REMOVED_FROM_STAGE и все такое. При удалении из дисплейлиста Tank сделает stop() своему TankMC. А флаг продолжает махаться. То-есть все равно надо пробегаться по иерархии TankMC и гасить stop() всем кто попался. Либо заранее один раз пробежать и навесить каждому листенер на REMOVED_FROM_STAGE что жесть.
>достаточно быстры.
я конечно не проверял, но думаю что это весьма не быстрые операции, особенно если объектов много — и листенеров много. Кучи операций выделения памяти (не думаю что для листенеров есть пулы), вставка\удаление… всё это печалит процессор.
написать
var mc: MovieClip = dObjCont as MovieClip;
if (mc != null) {mc.stop();}
на
if (dObjCont is MovieClip) MovieClip(dObjCont).stop();
Может даже проверю на досуге.
Но я сомневаюсь, что скрытые анимационные клипы сами по себе нагружают процессор, т.к. нагружает процессор лишь отрисовка, а без неё там наверняка простой currentFrame++.
Код в кадрах не советую контроллировать таким методом. Наплодите лишних проверок (-перфоманс), легко ошибиться в любом из кадров и забыть проверить. Плюс куча граблей вас ждет по пути, ибо исполнение кода в кадре это довольно недетерменированная вещь.