Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   AS2: Получить (рекурсивный?) список мувиклипов с полным путем. (http://www.flasher.ru/forum/showthread.php?t=98069)

xintrea 05.07.2007 21:27

AS2: Получить (рекурсивный?) список мувиклипов с полным путем.
 
Здравствуйте!

Инструменты - mtasc, FDT.

В целях облегчения отладки, хочу сделать себе такую функцию, которая бы выводила в trace информацию о всех существующих в данный момент клипах, начиная с _root, с полным путем.

Пока что найденные решения (типа такого http://www.flasher.ru/forum/showthread.php?t=91727) не радуют, потому что

- не показывают полного пути (чтобы виден был _root или там _level0)
- показывают мувиклипы только текущего уровня. Если в мувиклипе содержится еще один мувиклип, внутри которого еще мувиклипы, то их не видно. (возможно я тут не прав, возможно я не вижу "внутреннего" мувиклипа потому что неправильно загружаю, но проверить не могу потому что нет функции отладки, о которой я как раз и говорю)

В общем, нужен аналог списка мувиков (или даже всех объектов), который можно получить в Flash IDE через менюшку List Objects.

Есть уже готовые наработки?

Kikasso 05.07.2007 22:03

такое сгодится?
Код:

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);


xintrea 06.07.2007 01:57

Нет, не работает оно как надо.

Вот код который у меня получился. Я подгружаю 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-файл?

lowka 06.07.2007 02:25

Функция рабочая (только добавьте проверку на нужные типы). Вы бы загрузки-то дождались, а потом и посмотрели, что у вас там.

xintrea 06.07.2007 04:18

Мда.. Еще бы еще ктонить рассказал, как делать проверку на загруженность в 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 обычный, локальный. Откуда берутся лишние байты в размере загружаемого файла?

etc 06.07.2007 08:47

MovieClipLoader в помощь, без извращений и интервалами.

з.Ы. onLoad так не используется и работать не будет.

з.Ы.Ы. Байты берутся из расжатого swf.

xintrea 06.07.2007 17:18

Сделал через 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().

Посему тупой вопрос - как правильно вызвать метод одного объекта из другого?

Kikasso 06.07.2007 17:50

Я могу ошибаться, но
Код:

_checked_ = new Object();
надо писать внутри конструктора, а в шапке только объявить его тип:
Код:

var _checked_:Object;
appinst в вашем втором классе не значится. Передавайте параметр при иннициации, вы же scoope передаете в конструктор первому классу.
Я честно говоря не понимаю, нафига вам вообще этот LoadListener отдельным классом. Дописать onLoadInit в базовый класс, добавить слушателем себя, добиться нормальной работы, а потом уже мудрить.

xintrea 07.07.2007 03:33

Цитата:

Сообщение от Kikasso
Я могу ошибаться, но

_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() всегда работает как надо. Не знаю, красивое ли решение (может можно как-то очищать объекты, а не удалять и заводить новые), но оно работает.


Цитата:

Сообщение от Kikasso
appinst в вашем втором классе не значится. Передавайте параметр при иннициации, вы же scoope передаете в конструктор первому классу.

Да, спасибо за подсказку. Почему-то думал, что флеш хранит список инстансов, и к ним можно просто обращаться. А оказывается ООП во флеше почти такое же низкоуровневое как в сиплюсплюсе. Сделал с передачей параметра appinst, и вызов appinst.onLoadResourceMovie() заработал.

Теперь метод giperTrace(), вызваный из onLoadResourceMovie(), показывает все мувиклипы.

Код:

_level0
_level0.resource
_level0.resource.mcCellBall
_level0.resource.mcCellEnemyPlayer
_level0.resource.mcCellCommandPlayer


Цитата:

Сообщение от Kikasso
Я честно говоря не понимаю, нафига вам вообще этот LoadListener отдельным классом. Дописать onLoadInit в базовый класс, добавить слушателем себя, добиться нормальной работы, а потом уже мудрить.

Отдельным классом - это задел на будущее. Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов. А значит это отдельный класс.

lowka 07.07.2007 04:02

Цитата:

Сообщение от xintrea
Да, спасибо за подсказку. Почему-то думал, что флеш хранит список инстансов, и к ним можно просто обращаться. А оказывается ООП во флеше почти такое же низкоуровневое как в сиплюсплюсе.

А чем выше уровень ООП, то тем меньше в нем места для инкапсуляции? :bye:

Kikasso 07.07.2007 04:18

Цитата:

Сообщение от xintrea
Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов.

Да-да, в эту яму можно падать бесконечно.

etc 07.07.2007 11:44

Цитата:

Сообщение от xintrea
Отдельным классом - это задел на будущее. Да и по логике вещей, листенеры - это вещь в себе, т.е. это такие объекты, которые не входят в состав других объектов. А значит это отдельный класс.

Отдельный класс нахрен не нужен, но если садо-мазо и нужны проблемы с областями видимости — пожалуйста.
«Listener» — это просто объект с объявлеными методами-событиями, и не более того. Хелп флеша в изобилии набит этими листенерами, из-за чего в мозгу возникает стойкое убеждение, что для подписки на событие обязательно нужно создавать ещё один мусорный объект. А то, что можно подписать весь экземпляр текущего класса (методы-события должны быть объявлены, безусловно), как-то никто не догадывается.
В общем, послушайте Kikasso.


Часовой пояс GMT +4, время: 15:08.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.