Записки о Flash

Экспорт классов во второй кадр и создание прелоадера во Flash CS3

Итак, в AS2 общая схема создания ролика all-in-one (с прелоадером) такова:
1) Все экспортируемые элементы не экспортируются в первый кадр (галочка Export in first frame снята);
2) Создается пустой мувик, содержащий два кадра. В первом только stop(); и больше ничего нет. Во втором кадре данного мувика размещаются все экспортируемые элементы (звуки, шрифты, мувиклипы). stop в первом кадре не позволяет данному мувику переходить на свой второй кадр, таким образом мы избегаем ненужной инициализации элементов, находящихся во втором кадре;
3) Данный мувик размещается во втором кадре проекта в любом месте сцены (все равно он в принципе невидим, т.к. в его первом кадре ничего нет);
4) В настроках AS2 проекта выставляется второй кадр для экспортирования классов;
5) В третьем (можно и во втором) кадре проекта можно пользоваться всеми классами и ресурсами.

Таким образом, первый кадр освобожден от различных ресурсов и мы можем написать там обычный AS1-код (увы, чистого AS2 в таком варианте добиться вы получиться) прелоадера.

Однако, применяя такую схему для AS3, вы можете столкнуться с тем, что клипы, у которых есть содержимое, создаются, но это содержимое отсутствует. Такая проблема возникает для различных спрайтов, мувиклипов, которые содержат, например, шейпы, нарисованные вручную в IDE. В случае же обычных классов, не являющихся визуальными (или происходит программная отрисовка) такой проблемы нет. Проблема, судя по всему, связана с тем, что компилятор, когда встречает обращение к подобным клипам до кадра экспорта (в данном случае — второго), переносит код такого класса в первый кадр, а вот его содержимое (шейпы, например) — «забывает».

Что нам нужно для того, чтобы решить данную проблему?

Отказаться от обращений к пользовательским классам в Document class.

Как?

Использовать метод loaderInfo.applicationDomain.getDefinition для создания экземпляра класса, который будет являться входной точкой нашего приложения. А уже в этом классе мы можем создавать все, что душе угодно. Но при этом нам нужно добиться, чтобы класс, являющийся входной точкой нашего приложения был экспортирован во второй кадр.

А как этого можно добиться, если мы не делаем прямых обращений к пользовательским классам в Document class?

Заставить компилятор экспортировать наш входной класс также просто: необходимо создать пустой мувиклип, с прописанным у него входным классом и поместить этот клип в тот самый двухкадровый мувиклип-экспортер, содержащий и все остальные ресурсы. Таким образом, компилятор создаст два объявления AS3-классов в нашем ролике. В первом объявлении будет содержаться только Document class (вы можете, конечно, создать какие-либо невизуальные классы, либо классы-спрайты, занимающиеся программной отрисовкой чего-либо, но таким образом вы основательно можете увеличить вес первого кадра), во втором (которое располагается во втором кадре) — все остальные классы, в т.ч. класс, являющийся входной точкой.

Представляю вашему вниманию простейший пример создания ролика в CS3 с экспортом классов во втором кадре и загрузчиком.

Некоторые пояснения к примеру:
Классы Box и Star — нарисованные вручную клипы.

Класс Program есть по сути Document class, он же входная точка.

Класс AnotherClass просто иллюстрирует работу экспорта во второй кадр всех нужных классов (не только физически размещенных во втором кадре).

Класс EmbedClip является сервисным классом-экспортером, во втором кадре которого мы будем размещать все наши нарисованные клипы. В этот кадр данный класс никогда не переходит, во избежание лишних инициализаций классов. Экземпляр данного класса находится во втором кадре нашего ролика.

Ну а ExportSecondFrameExample есть настоящий Document class, по совместительству выполняющий функцию загрузчика.


41 comments

41 Comments so far

  1. Rost August 3rd, 2007 17:49

    Денис, отличная находка, хочу заметить чисто с юзерской точки зрения: немного не хватает вводного пояснения, описывающего сам принцип решения.

    Пояснение к примеру – хорошее, но описание общего механизма было бы очень кстати. ИМХО :)

  2. __etc August 3rd, 2007 17:58

    Это я напишу, наверное, сейчас.

  3. __etc August 3rd, 2007 18:48

    Написал пояснения, откуда и каким образом возникает подобный баг.

  4. mushtra August 17th, 2007 17:05

    Используя этот рецепт (п.п.1-5) в IDE Flash8 компилируя AS 2.0, не смог получить результата: экземпляр класса Button лежащий на третьем кадре maintimeline и продублированный на втором кадре мувика, размещённого во втором кадре maintimeline, не отобразился. Экспорт AS-классов во второй фрейм.

  5. mushtra August 17th, 2007 17:21

    компонент Button AS 2.0 размещённый на временной шкале как визуальный элемент простым перетаскиванием в IDE из библиотеки.

  6. __etc August 17th, 2007 17:32

    Не смог повторить описанную проблему. Можно исходник?

  7. mushtra August 17th, 2007 17:47

    Выслал по почте(?) etc {собак} mail.ru

  8. __etc August 17th, 2007 17:51

    Это потому что вы в Linkage не сняли галочку «Export in first frame».

  9. mushtra August 17th, 2007 18:01

    Выявил своё упущение, возможно неочевидное, хотя в статье явно указанное: недостаточно в настройках публикации указать второй кадр экспорта AS-классов, необходимо также обязательно снять флажок экспорта в первый кадр в свойствах Linkage всех компонентов находящихся в библиотеке IDE. При соблюдении этого всё работает.

  10. mushtra August 17th, 2007 18:04

    Да. Спасибо. Полезная информация.

  11. __etc August 17th, 2007 17:17

    Экземпляр класса Button? Наследник Button?
    Или у вас так класс называется?

  12. dimpiax October 18th, 2007 14:32

    спасибо за статейку ;)

  13. MaxZ October 1st, 2008 11:03

    Добрый день. Можно ли поподробнее объяснить следующее:

    var programClass:Class =
    loaderInfo.applicationDomain.getDefinition(ExportSecondFrameExample.DOCUMENT_CLASS) as Class;
    var program:Sprite = new programClass() as Sprite;

    Вы пишете, что это определение класса, который будет являтся входной точкой нашего приложения. Получается что getDefinition() возвращает класс по его имени. Затем мы создаём экземпляр этого класса, точнее создаём спрайт при помощи конструктора этого класса. Почему в качестве типа указывается Sprite а конструктор используется от нашего класса? Логичнее было бы в качестве типа указать programClass, но вылезает ошибка что “1046: Type was not found or was not a compile-time constant: programClass.” Как получается, что типа ещё нет ,а конструктор срабатывает?

  14. etc October 1st, 2008 11:09

    programClass — это имя переменной, содержащей ссылку на класс, а не тип. Например, вы можете создать спрайт вот так:
    var sp:Class = Sprite;
    var o:Sprite = new sp() as Sprite;

    «o» в данном случае не типа sp, а Sprite. Или можно DisplayObjectContainer.

    Упоминать явно (не в виде строки) в классе ExportSecondFrameExample класс Program вы не можете, т. к. в таком случае его объявление попадет в первый кадр.

  15. MaxZ October 1st, 2008 11:32

    var sp:Class = Sprite;
    var o:Sprite = new sp() as Sprite;

    Получается,что мы вызываем конструктор класса обращаясь к нему по ссылке, чтобы избежать его явного упоминания?

  16. etc October 1st, 2008 11:42

    Именно так.

  17. MaxZ October 1st, 2008 11:50

    Спасибо за помощь

  18. MaxZ October 1st, 2008 15:03

    Ещё вопросик: чекбокс “Export classes in frame” в AS3 Settings регулирует экспорт каких классов – только базовых или же ещё и пользовательских?

  19. etc October 1st, 2008 15:09

    Базовых — это каких?

  20. MaxZ October 1st, 2008 15:27

    MovieClip например, или Sprite

  21. etc October 1st, 2008 15:38

    Эти классы входят в состав плеера, а не swf-файла. Они доступны всегда.

  22. MaxZ October 1st, 2008 16:00

    Тогда получается, что эта опция касается только пользовательских классов.

  23. etc October 1st, 2008 16:08

    Конечно.

  24. LA July 8th, 2009 22:19

    Спасибо за статью и за исходник!

    Чего-то никак не могу понять как же получить доступ к root в Program. Говорит, что он равен null.
    Как быть?

  25. LA July 8th, 2009 23:15

    И, еще вопрос – в чем преимущества этого способа перед, например, описанным тут – http://blog.funfacegames.com/2008/04/how-to-create-self-contained-as3-loader.html?

  26. etc July 9th, 2009 05:39

    Да в общем-то та же техника, единственное, на что не обращено внимание — весь код с классами попадает в первый фрейм до прелоадера. Если кода мало, это особой проблемы не создаёт.

  27. LA July 9th, 2009 07:25

    ясно. спасибо!
    а как же быть с root?

  28. etc July 9th, 2009 07:30

    root будет доступен после того, как основной класс Program будет добавлен в display list. Но ссылаться он будет не на Program, а на Document class.
    Обращение к root в целом является ошибкой в проектировании приложения.

  29. LA July 9th, 2009 19:18

    а разве код
    var program:Sprite=new programClass as Sprite;
    addChild(program);
    не добавляет класс Program в display list автоматически?

  30. etc July 9th, 2009 21:15

    Добавляет. Но уже после выполнения конструктора Program.

  31. LA July 9th, 2009 22:18

    От root’a избавился.
    А как обратиться к stage из Program? Или нужно все данные еще ExportSecondFrameExample прочитать?

  32. etc July 10th, 2009 04:08

    Выполнять необходимый код после наступления события Event.ADDED_TO_STAGE.

  33. LA July 10th, 2009 21:36

    хм. а если у меня весь дальнейший код основан на использовании stage, то мне его в обработчике события Event.ADDED_TO_STAGE писать? или есть какой-то более правильный вариант?

    спасибо за ответы!

  34. etc July 11th, 2009 12:30

    Можно сделать функцию init(event:Event=null) и в конструкторе написать:
    if (super.stage) this.init();
    else super.addEventListener(Event.ADDED_TO_STAGE, this.init);

    В init уже можн работать со stage и всем остальным.

  35. [...] Первую запись хочу посвятить этой многозначительной и мучительной теме, сколько я не искал материалов в сети всегда натыкался только на одну ссылку. [...]

  36. Alex December 1st, 2009 15:18

    Мне нужно получить flashvars в класс Program, но как я понимаю они передаются в класс загрузчик?

    Как мне их оттуда выцарапать?

    Заранее спасибо

  37. etc December 1st, 2009 22:39

    Собственно, они будут доступны у того же root, после добавления Program на сцену.

  38. Quadro9 February 11th, 2010 21:09

    Почему после окончания загрузки нельзя сделать “gotoAndStop(3);”, а вместо этого используется “play();”?

  39. etc February 12th, 2010 04:58

    Чтобы пройти через кадр, в котором лежат ресурсы. Хотя, это было необходимо в AS1/AS2, а в AS3 я не проверял. Возможно, достаточно сразу перейти на третий.

  40. Quadro9 February 12th, 2010 13:10

    “gotoAndStop(3);” работает без видимых проблем, я поэтому и спросил :)

  41. etc February 12th, 2010 13:16

    Ну значит это наследие AS2 помешало :)

Leave a reply