Экспорт классов во второй кадр и создание прелоадера во 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
Leave a reply
Денис, отличная находка, хочу заметить чисто с юзерской точки зрения: немного не хватает вводного пояснения, описывающего сам принцип решения.
Пояснение к примеру – хорошее, но описание общего механизма было бы очень кстати. ИМХО
Это я напишу, наверное, сейчас.
Написал пояснения, откуда и каким образом возникает подобный баг.
Используя этот рецепт (п.п.1-5) в IDE Flash8 компилируя AS 2.0, не смог получить результата: экземпляр класса Button лежащий на третьем кадре maintimeline и продублированный на втором кадре мувика, размещённого во втором кадре maintimeline, не отобразился. Экспорт AS-классов во второй фрейм.
компонент Button AS 2.0 размещённый на временной шкале как визуальный элемент простым перетаскиванием в IDE из библиотеки.
Не смог повторить описанную проблему. Можно исходник?
Выслал по почте(?) etc {собак} mail.ru
Это потому что вы в Linkage не сняли галочку «Export in first frame».
Выявил своё упущение, возможно неочевидное, хотя в статье явно указанное: недостаточно в настройках публикации указать второй кадр экспорта AS-классов, необходимо также обязательно снять флажок экспорта в первый кадр в свойствах Linkage всех компонентов находящихся в библиотеке IDE. При соблюдении этого всё работает.
Да. Спасибо. Полезная информация.
Экземпляр класса Button? Наследник Button?
Или у вас так класс называется?
спасибо за статейку
Добрый день. Можно ли поподробнее объяснить следующее:
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.” Как получается, что типа ещё нет ,а конструктор срабатывает?
programClass — это имя переменной, содержащей ссылку на класс, а не тип. Например, вы можете создать спрайт вот так:
var sp:Class = Sprite;var o:Sprite = new sp() as Sprite;
«o» в данном случае не типа sp, а Sprite. Или можно DisplayObjectContainer.
Упоминать явно (не в виде строки) в классе ExportSecondFrameExample класс Program вы не можете, т. к. в таком случае его объявление попадет в первый кадр.
var sp:Class = Sprite;
var o:Sprite = new sp() as Sprite;
Получается,что мы вызываем конструктор класса обращаясь к нему по ссылке, чтобы избежать его явного упоминания?
Именно так.
Спасибо за помощь
Ещё вопросик: чекбокс “Export classes in frame” в AS3 Settings регулирует экспорт каких классов – только базовых или же ещё и пользовательских?
Базовых — это каких?
MovieClip например, или Sprite
Эти классы входят в состав плеера, а не swf-файла. Они доступны всегда.
Тогда получается, что эта опция касается только пользовательских классов.
Конечно.
Спасибо за статью и за исходник!
Чего-то никак не могу понять как же получить доступ к root в Program. Говорит, что он равен null.
Как быть?
И, еще вопрос – в чем преимущества этого способа перед, например, описанным тут – http://blog.funfacegames.com/2008/04/how-to-create-self-contained-as3-loader.html?
Да в общем-то та же техника, единственное, на что не обращено внимание — весь код с классами попадает в первый фрейм до прелоадера. Если кода мало, это особой проблемы не создаёт.
ясно. спасибо!
а как же быть с root?
root будет доступен после того, как основной класс Program будет добавлен в display list. Но ссылаться он будет не на Program, а на Document class.
Обращение к root в целом является ошибкой в проектировании приложения.
а разве код
var program:Sprite=new programClass as Sprite;
addChild(program);
не добавляет класс Program в display list автоматически?
Добавляет. Но уже после выполнения конструктора Program.
От root’a избавился.
А как обратиться к stage из Program? Или нужно все данные еще ExportSecondFrameExample прочитать?
Выполнять необходимый код после наступления события Event.ADDED_TO_STAGE.
хм. а если у меня весь дальнейший код основан на использовании stage, то мне его в обработчике события Event.ADDED_TO_STAGE писать? или есть какой-то более правильный вариант?
спасибо за ответы!
Можно сделать функцию init(event:Event=null) и в конструкторе написать:
if (super.stage) this.init();else super.addEventListener(Event.ADDED_TO_STAGE, this.init);
В init уже можн работать со stage и всем остальным.
[...] Первую запись хочу посвятить этой многозначительной и мучительной теме, сколько я не искал материалов в сети всегда натыкался только на одну ссылку. [...]
Мне нужно получить flashvars в класс Program, но как я понимаю они передаются в класс загрузчик?
Как мне их оттуда выцарапать?
Заранее спасибо
Собственно, они будут доступны у того же root, после добавления Program на сцену.
Почему после окончания загрузки нельзя сделать “gotoAndStop(3);”, а вместо этого используется “play();”?
Чтобы пройти через кадр, в котором лежат ресурсы. Хотя, это было необходимо в AS1/AS2, а в AS3 я не проверял. Возможно, достаточно сразу перейти на третий.
“gotoAndStop(3);” работает без видимых проблем, я поэтому и спросил
Ну значит это наследие AS2 помешало