Просмотр полной версии : AS2: Получить (рекурсивный?) список мувиклипов с полным путем.
Здравствуйте!
Инструменты - mtasc, FDT.
В целях облегчения отладки, хочу сделать себе такую функцию, которая бы выводила в trace информацию о всех существующих в данный момент клипах, начиная с _root, с полным путем.
Пока что найденные решения (типа такого http://www.flasher.ru/forum/showthread.php?t=91727) не радуют, потому что
- не показывают полного пути (чтобы виден был _root или там _level0)
- показывают мувиклипы только текущего уровня. Если в мувиклипе содержится еще один мувиклип, внутри которого еще мувиклипы, то их не видно. (возможно я тут не прав, возможно я не вижу "внутреннего" мувиклипа потому что неправильно загружаю, но проверить не могу потому что нет функции отладки, о которой я как раз и говорю)
В общем, нужен аналог списка мувиков (или даже всех объектов), который можно получить в Flash IDE через менюшку List Objects.
Есть уже готовые наработки?
такое сгодится?
function giperTrace(o){
if(typeof(o)!='movieclip' || o.checked ) return;
trace(o);
o.checked = true;
for( var p in o )giperTrace ( o[p]);
}
giperTrace(this);
немного портит клипы.. добавляет свойство, чтобы по перекрестным ссылкам не бегать. Можно и без этого обойтись, создав объект:
var _checked_:Object = {};
function giperTrace(o){
if(typeof(o)!='movieclip' || _checked_[o._target] ) return;
trace(o);
_checked_[o._target] = true;
for( var p in o )giperTrace ( o[p]);
}
giperTrace(this);
Нет, не работает оно как надо.
Вот код который у меня получился. Я подгружаю swf-файл, в котором есть три мувиклипа (для каждого мувиклипа прописаны LinkageID и заданы InstanceName).
class Application
{
var _checked_:Object = {};
private var scopeRef:MovieClip;
function Application(scope:MovieClip)
{
Flashout.info("Application constructor start.");
scopeRef = scope;
// Загрузка ресурсов
var dpt=10;
scopeRef.createEmptyMovieClip("resource", dpt++);
scopeRef.resource._x=200;
scopeRef.resource.loadMovie("resource.swf");
// Пробуем сделать список что имеем в ресурсах в данный момент
// но ничего внутри ресурсов не видно
trace("List of resource start");
for(var prop in scopeRef.resource)
trace("Prop "+scopeRef.resource[prop]);
trace("List of resource end");
// Программно создаем текстовое поле
scopeRef.createTextField("tf", 0, 100, 100, 800, 600);
scopeRef.tf.text = "Hello flasher!";
}
// Функция рекурсивной печати имеющихся мувиклипов
public function giperTrace(o)
{
if(typeof(o)!='movieclip' || _checked_[o._target] ) return;
trace(o);
_checked_[o._target] = true;
for( var p in o )
giperTrace ( o[p]);
}
// --- Main Entry Point
static function main()
{
trace("Run main function");
// Запускаем инициализацию приложеня
var appinst:Application = new Application(_root);
// Печатаем список всех мувиклипов
appinst.giperTrace(_root);
}
}
В результате выполнения имеем лог такой
Run main function
Application constructor start.
List of resource start
List of resource end
_level0
_level0.resource
То есть виден только мувик "resource". Внутри него ничего не видим. А если скомпилированный swf-файл запустить в Flash IDE и посмотреть Object List, то увидим такое
Level #0: Frame=1
Edit Text: Target="_level0.tf" Variable= Visible=true Text = Hello flasher!"
Movie Clip: Frame=1 Target="_level0.resource"
Movie Clip: Frame=1 Target="_level0.resource.mcCellCommandPlayer"
Shape:
Movie Clip: Frame=1 Target="_level0.resource.mcCellEnemyPlayer"
Shape:
Movie Clip: Frame=1 Target="_level0.resource.mcCellBall"
Shape:
Shape:
Edit Text: Target="_level0.resource.instance1" Variable= Visible=true Text = CellCommandPlayer"
Edit Text: Target="_level0.resource.instance2" Variable= Visible=true Text = CellEnemyPlayer"
Edit Text: Target="_level0.resource.instance3" Variable= Visible=true Text = CellBall"
то есть на самом деле внутри мувика "resource" есть три мувиклипа, но они почему-то недоступны. Кстати, внутри конструктора Application я тоже пытаюсь распечатать содержимое приаттаченого swf-файла. Но даже с прямым указанием мувика, который нужно обработать, мувики внутри него не видятся. Мувик подгружается нормально, и его, и мувики внутри него из которых он состоит, я вижу в окне флешплейера при запуске. Но мувики внутри подруженного как мувик swf-файла - недоступны программно, хотя для них в serource-фале указаны (как писал выше) LinkageID и InstanceName.
Поэтому вопрос - почему Flash при печати Object List видит мувики внутри swf-файла, а программно они недоступны? И как сделать чтоб они стали доступными, например, для копирования? Чтобы можно было копировать эти встроенные мувики через attachMovie() или там duplicateMovieClip()? Или это принципиально в AS2 невозможно? И единственный выход - помещать каждый мувик в отдельный SWF-файл?
Функция рабочая (только добавьте проверку на нужные типы). Вы бы загрузки-то дождались, а потом и посмотрели, что у вас там.
Мда.. Еще бы еще ктонить рассказал, как делать проверку на загруженность в AS2 средствами mtasc онли. Или это есть зло?
В данный момент добавил пару методов
public function checkLoaded(target_mc:MovieClip)
{
var pctLoaded:Number = target_mc.getBytesLoaded()/target_mc.getBytesTotal()*100;
trace("target_mc "+target_mc);
trace("target_mc.getBytesLoaded() "+target_mc.getBytesLoaded());
trace("target_mc.getBytesTotal() "+target_mc.getBytesTotal());
trace("pctLoaded "+pctLoaded);
if (!isNaN(pctLoaded) && (pctLoaded==100))
{
trace("clearing interval");
clearInterval(myInterval);
target_mc.onLoad = doOnLoad;
}
}
public function doOnLoad()
{
trace("Movie load full");
}
Вызов загрузки делаю так
scopeRef.createEmptyMovieClip("resource", dpt++);
scopeRef.resource.loadMovie("resource.swf");
myInterval = setInterval(checkLoaded, 100, scopeRef.resource);
Получаю такой лог
Run main function
Application constructor start.
List of resource start
List of resource end
_level0
_level0.resource
target_mc _level0.resource
target_mc.getBytesLoaded() 1440
target_mc.getBytesTotal() 1440
pctLoaded 100
clearing interval
Как видно, назначить мувику метод onLoad() не получается. Лог доходит до строчки "clearing interval", дальше по идее должа появиться строчка "Movie load full". Но ее в логе нет.
Подозреваю, что назначить метод мувику нельзя потому, что функция onLoad() в моем коде является методом класса Application, который не является мувиклипом вообще. Но как по-другому назначить мувику onLoad-метод, сообразить не могу.
PS: Размер загружаемого swf в байтах - 1087. А в логе пишется что загружается 1440 байт. Запуск swf обычный, локальный. Откуда берутся лишние байты в размере загружаемого файла?
MovieClipLoader в помощь, без извращений и интервалами.
з.Ы. onLoad так не используется и работать не будет.
з.Ы.Ы. Байты берутся из расжатого swf.
Сделал через MovieClipLoader, но не хватает последнего штриха. А именно - не могу из onLoadInit() вызвать метод нужного мне объекта.
У меня есть инстанс объекта, который именуется appinst. У этого объекта есть метод onLoadResourceMovie(). Но когда я пытаюсь его вызвать из onLoadInit() моего листенера через команду
appinst.onLoadResourceMovie(target_mc);
то компиляция не проходит, и на этой строке мне выдается ошибка
type error Unknown variable appinst
Вот код двух моих классов, из которых и состоит проект.
class Application
{
var _checked_:Object={};
private var scopeRef:MovieClip;
function Application(scope:MovieClip)
{
Flashout.info("Application constructor start.");
scopeRef = scope;
}
function addTextLabel()
{
// Программно создаем текстовое поле
scopeRef.createTextField("tf", 0, 100, 100, 800, 600);
scopeRef.tf.text = "Hello flasher!";
}
function initLoadResouceMovie()
{
// Загрузка ресурсов
var dpt=10;
// Инитим загружающие мувик листенеры
var my_mcl:MovieClipLoader = new MovieClipLoader();
var listenerinst:LoadListener = new LoadListener(my_mcl);
my_mcl.addListener(listenerinst);
// Запускаем процесс загрузки ресурсов
scopeRef.createEmptyMovieClip("resource", dpt++);
my_mcl.loadClip("resource.swf", scopeRef.resource);
}
public function giperTrace(o)
{
if(typeof(o)!='movieclip' || _checked_[o._target] ) return;
trace(o);
_checked_[o._target] = true;
for( var p in o )
giperTrace ( o[p]);
}
public function onLoadResourceMovie(target_mc:MovieClip)
{
trace("Movieclip load complete "+target_mc);
giperTrace(_root);
}
// --- Main Entry Point
static function main()
{
trace("Run main function");
var appinst:Application = new Application(_root);
appinst.addTextLabel();
appinst.initLoadResouceMovie();
}
}
class LoadListener {
var mcl:Object;
public function LoadListener(target_mcl:Object)
{
mcl=target_mcl;
}
public function onLoadStart(target_mc:MovieClip)
{
trace("********* LoadListener Start *********");
trace("Your begin load movie clip = "+target_mc);
var loadProgress:Object = mcl.getProgress(target_mc);
trace(loadProgress.bytesLoaded+" = bytes loaded at start");
trace(loadProgress.bytesTotal+" = bytes total at start");
}
public function onLoadProgress(target_mc:MovieClip, loadedBytes:Number, totalBytes:Number)
{
trace("********* LoadListener Progress *********");
trace("onLoadProgress() called back on movie clip "+target_mc);
trace(loadedBytes+" = bytes loaded at progress callback");
trace(totalBytes+" = bytes total at progress callback");
}
public function onLoadComplete(target_mc:MovieClip)
{
trace("********* LoadListener Complete *********");
trace("Your load is done on movie clip = "+target_mc);
var loadProgress:Object = mcl.getProgress(target_mc);
trace(loadProgress.bytesLoaded+" = bytes loaded at end");
trace(loadProgress.bytesTotal+" = bytes total at end");
}
public function onLoadInit(target_mc:MovieClip)
{
trace("********* LoadListener Init *********");
trace("Movie clip = "+target_mc+" is now initialized");
// теперь можно применять любые установки
appinst.onLoadResourceMovie(target_mc); // <-- Эта строка не компилится
}
public function onLoadError(target_mc:MovieClip, errorCode:String)
{
trace("********* LoadListener Error *********");
trace("ERROR CODE = "+errorCode);
trace("Your load failed on movie clip = "+target_mc+"\n");
}
}
Вооот. Я честнагря в объектном программировании не силен, поэтому понять не могу, почему инстанс appinst объекта Application неизвестен в методе onLoadInit().
Посему тупой вопрос - как правильно вызвать метод одного объекта из другого?
Я могу ошибаться, но _checked_ = new Object(); надо писать внутри конструктора, а в шапке только объявить его тип:var _checked_:Object;
appinst в вашем втором классе не значится. Передавайте параметр при иннициации, вы же scoope передаете в конструктор первому классу.
Я честно говоря не понимаю, нафига вам вообще этот LoadListener отдельным классом. Дописать onLoadInit в базовый класс, добавить слушателем себя, добиться нормальной работы, а потом уже мудрить.
Я могу ошибаться, но
_checked_ = new Object();
надо писать внутри конструктора, а в шапке класса только объявить его тип:
var _checked_:Object;
Да, вы совершенно правы. Кроме того, метод giperTrace() пришлось доработать, так как воспользоваться им можно было только один раз. При следующем вызове этого метода, в объекте _checked_ уже отмечено, что данный мувик был обработан, и его имя повторно не выводится в лог. Я внес те исправления что выше написаны и сделал из одного метода giperTrace() два вот таких
public function giperTrace(o)
{
delete _checked_;
_checked_ = new Object();
giperTraceRecurse(o);
}
public function giperTraceRecurse(o)
{
if(typeof(o)!='movieclip' || _checked_[o._target] ) return;
trace(o);
_checked_[o._target] = true;
for( var p in o )
giperTrace ( o[p]);
}
Теперь вызов giperTrace() всегда работает как надо. Не знаю, красивое ли решение (может можно как-то очищать объекты, а не удалять и заводить новые), но оно работает.
appinst в вашем втором классе не значится. Передавайте параметр при иннициации, вы же scoope передаете в конструктор первому классу.
Да, спасибо за подсказку. Почему-то думал, что флеш хранит список инстансов, и к ним можно просто обращаться. А оказывается ООП во флеше почти такое же низкоуровневое как в сиплюсплюсе. Сделал с передачей параметра appinst, и вызов appinst.onLoadResourceMovie() заработал.
Теперь метод giperTrace(), вызваный из onLoadResourceMovie(), показывает все мувиклипы.
_level0
_level0.resource
_level0.resource.mcCellBall
_level0.resource.mcCellEnemyPlayer
_level0.resource.mcCellCommandPlayer
Я честно говоря не понимаю, нафига вам вообще этот LoadListener отдельным классом. Дописать onLoadInit в базовый класс, добавить слушателем себя, добиться нормальной работы, а потом уже мудрить.
Отдельным классом - это задел на будущее. Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов. А значит это отдельный класс.
Да, спасибо за подсказку. Почему-то думал, что флеш хранит список инстансов, и к ним можно просто обращаться. А оказывается ООП во флеше почти такое же низкоуровневое как в сиплюсплюсе.
А чем выше уровень ООП, то тем меньше в нем места для инкапсуляции? :bye:
Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов.
Да-да, в эту яму можно падать бесконечно.
Отдельным классом - это задел на будущее. Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов. А значит это отдельный класс.
Отдельный класс нахрен не нужен, но если садо-мазо и нужны проблемы с областями видимости — пожалуйста.
«Listener» — это просто объект с объявлеными методами-событиями, и не более того. Хелп флеша в изобилии набит этими листенерами, из-за чего в мозгу возникает стойкое убеждение, что для подписки на событие обязательно нужно создавать ещё один мусорный объект. А то, что можно подписать весь экземпляр текущего класса (методы-события должны быть объявлены, безусловно), как-то никто не догадывается.
В общем, послушайте Kikasso.
Работает на vBulletin ® версия 3.7.3. Copyright ©2000-2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Copyright © 1999-2008 Flasher.ru. All rights reserved.