Предмет: Flash-технологии, программы, редакторы, классы, библиотеки. Методика: Изучение шаг за шагом, поиск новых решений, сбор ссылок, новостей и мнений, разбор примеров. Цель: Сбор, обработка и накопление тематической информации.
вторник, марта 23, 2010
Как получить заголовки ответа сервера
понедельник, октября 05, 2009
Копипаст фильтров из CS во Flex
- В тестовом файле создаем клип образца, визуально похожего на то что у нас должно быть во flex - например, текстовое поле или кнопку. Навешиваем на нее кучу фильтров, до получения нужной нам картинки.
- На слое с клипом кликаем правой кнопкой и выбираем "Copy Motion to ActionScript 3".
- Вставляем куда-нибудь то, что скопировалось в буфер - например, тут же в редактор Actions.
- Находим там блок <filters>...</filters>
- Копипастим его себе во Flex-код, в контейнер тега нужного нам визуального компонента.
- Заменяем filters на mx:filters и filters:BevelFilter на mx:BevelFilter. (у mx:filters может быть другой префикс - зависит от компонента)
- Компилируем и получаем картину, аналогичную CS. Дотюниваем, если необходимо, параметры.
воскресенье, марта 22, 2009
mx:Pause vs flash.utils.Timer. Flex
Легкое определение переменных в MXML значительно упрощает разработку:
- позволяет легко и наглядно определять их свойства и обработчики событий
- автоматически делает переменные Bindable
- позволяет их связать с другими переменными и выражениями
- делает наглядным код
Но, на сколько я понял, не все классы можно представить в декларативном виде.
Например, класс flash.utils.Timer невозможно представить в виде MXML. Компилятор выдает ошибку "Неправильное количество аргументов". Всё от того, что конструктор этого класса содержит один обязательный параметр. Как его указать, и возможно ли это, увы, я не понял.
Но есть простое решение - использовать другой класс, хорошо подходящий по своему функционалу - mx.effects.Pause:
id="somePause"
duration="2000"
effectEnd="somePause_effectEndHandler(event)"
/>
. . .
//Стартовать задержку
this.somePause.play();
. . .
private function somePause_effectEndHandler(event:EffectEvent):void {
//Обработать окончание задержки
}
четверг, марта 05, 2009
Дружим Flex с Flash. Заметки: загрузка, внедрение, шрифт. Flex
Для начала, несколько заметок:
- Перенос строки в строках MXML: символ 
 - мелочь, а приятно.
- Загрузка сложных Flash-приложений в SWFLoader должна производиться в выделенный домен приложения, т.к. могут быть конфликты классов:
. . .
private function creationCompleteHandler(event:Event):void {
swfLoader.loaderContext=new LoaderContext(false,new ApplicationDomain());
swfLoader.load();
}
- Если внешнее приложение подгружается в SWFLoader, есть вероятность, что в какой-то момент SWFLoader потеряет stage, что может пагубно отразиться на функциональности этого приложения. Если приложение где-то внутри обращается к stage и не обрабатывает его недоступность, то будут генерироваться ошибки. Побороть этот недостаток я не смог - только устранив все "не защищенные" stage из внешнего приложения.
- Внедрение шрифтов. Гораздо надежнее внедрять шрифт непосредственно из TTF файла. Внедрение из файла SWF, в котором, в свою очередь, внедрен необходимый шрифт лучше оставить для тяжелых случаев несовместимостей с Flex. Дело в том, что почему-то, внедренные в SWF разные стили (normal, bold) шрифта не корректно "извлекаются" Flex-ом. Он не дает назвать разные стили разными именами (как это можно сделать в первом случае), теряет одно из начертаний (жирный шрифт просто не выводится). Возможно, это из-за особенностей конкретных шрифтов, но первый метод срабатывает гораздо стабильнее.
{
fontFamily: "Century Schoolbook";
fontWeight: normal;
fontStyle: normal;
src: url("file://./assets/fonts/CENSCBK.TTF");
unicodeRange:
U+0020-U+0040, /* Punctuation, Numbers */
U+0041-U+005A, /* Upper-Case A-Z */
U+005B-U+0060, /* Punctuation and Symbols */
U+0061-U+007A, /* Lower-Case a-z */
U+007B-U+007E, /* Punctuation and Symbols */
U+00FC-U+00FD,
U+0410-U+042F, /* Cyrillic Upper-Case A-Z */
U+0430-U+0451; /* Cyrillic Lower-Case a-z */
}
@font-face
{
fontFamily: "Century Schoolbook Bold";
fontWeight: bold;
fontStyle: normal;
src: url("file://./assets/fonts/SCHLBKB.TTF");
unicodeRange:
U+0020-U+0040, /* Punctuation, Numbers */
U+0041-U+005A, /* Upper-Case A-Z */
U+005B-U+0060, /* Punctuation and Symbols */
U+0061-U+007A, /* Lower-Case a-z */
U+007B-U+007E, /* Punctuation and Symbols */
U+00FC-U+00FD,
U+0410-U+042F, /* Cyrillic Upper-Case A-Z */
U+0430-U+0451; /* Cyrillic Lower-Case a-z */
}
- Внедрять клип из внешней SWF так, чтобы работали его фреймовые скрипты можно следующим образом:
source="@Embed(source='assets/Index.swf')"
При внедрении отдельного символа, его фреймовые скрипты и скрипты всех вложенных объектов теряются:source="@Embed(source='assets/Index.swf'#Index)"
Игра с параметром mimeType не помогает.
На управлении внедренным контентом я бы хотел остановиться подробнее. Если у нас много однотипного материала для внедрения вышеописанным способом, то плодить SWF-файлы не удобно, плюс, внедряя каждый файл, мы не можем обобщать графику - она будет внедряться для каждого файла заново (не проверял, но догадываюсь).
Куда удобнее создать одну большую библиотеку и из нее внедрять символы. Но, к сожалению, их скрипты уже будут не доступны.
Но у нас есть в распоряжении метки фреймов и имена клипов. Совмещая возможности
MovieClip.currentLabels и MovieClip.addFrameScript можно получить контроль над внедренным клипом и заставлять его в нужный момент выполнять необходимые нам действия: останавливать клип на нужном фрейме, генерировать события и даже передавать данные в текстовые поля клипа.
Создаем компонент - наследник SWFLoader. После инстанцирования класса внедренного клипа (конец метода load(), можно так же добавить и в обработчик события загрузки), считываются все его метки и в их фреймы добавляются необходимые скрипты. Имя каждой метки имеет ключевую составляющую, которая и определяет тип действия добавляемого скрипта.
В нужный момент можно заставить клип остановиться, перейти на другую метку, генерировать событие (с идентификатором, так же зашитым в имя метки), просканировать клип и получить срез всех визуальных объектов, чтобы делать с ними всё что угодно. Главное - этот момент устанавливается прямо в таймлайне клипа, а не путем каких-либо расчетов количества фреймов или подобных методов.
Прекрасный момент - праздник еще не настал, а дидлайны уже позади! Отдыхать и набираться сил.
И конечно, наших прекрасных женщин поздравляю с праздником 8 марта!
понедельник, февраля 09, 2009
Прогресс-бар на любой вкус. Flex
Сделать прогресс-бар (ProgressBar) совершенно не похожим на постепенно заполняющуюся горизонтальную полосу.
Скинирование позволяет заменить лишь изображения не залитой и залитой полос. Ну а если мне не нужна полоса?
Порыскав по интернету, пришел к выводу, что все усиленно заморачивались на проблему подмены предзагрузчика flash/flex-приложений, а вот видоизменить ProgressBar, почему-то никому не понадобилось.
Ну что ж, раз готового материала не нашлось, придется мастерить ручками.
Продолжение следует...
пятница, января 09, 2009
Что можно сделать с классом из подгружаемой SWF-библиотеки
Если не ошибаюсь, в ActionScript 2 такая возможность была.
Цель моей задачи такова: в некотором таймлайне подгружаемого SWF периодически появляется клип. При его появлении, с ним необходимо проделать какие-то действия.
В обычных условиях, с этим клипом ассоциируется класс (лежащий по соседству с FLA), в конструкторе которого и производятся эти действия.
Но вся прелесть-то в том, чтобы не было никаких скриптов ни в таймлайне, ни рядом с FLA. А всё что нужно делало бы загружающее этот SWF приложение - добавляло необходимый функционал подгруженному клипу.
Перерыл хелп и гугл - безрезультатно... Может быть не там искал. В итоге, модифицировать класс внешней библиотеки во время исполнения (бестолковое свойство prototype не в счет), либо подменить его не получилось, и ничего подходящего найти не смог.
Пока пойду обычным путем - класс клипа в конструкторе будет кидать событие с бабблингом: "Как получать сообщения от внедряемых/подгружаемых SWF. AS3".
* * *
Огромное спасибо BlooDHounD (см. комментарии). Его совет действительно работает.
Опробовал два метода:
- Класс, в подгружаемом SWF, задается в поле "Class" диалога "Linkage properties" для нашего клипа:
classes.intrinsic.AssetCreationDispatcher
При этом, никаких файлов классов поблизости с FLA создавать не требуется - класс создается "по умолчанию" (intrinsic - я назвал пакет этим словом, т.к. представленный метод мне отдаленно напомнил одноименный механизм в ActionScript 2.0).
Затем, в загружающем приложении, я определяю классclasses.intrinsic.AssetCreationDispatcherно уже реальный, с необходимым кодом в AS-файле (в моем случае, это извещение приложения о создании клипа).
Приложение загружает SWF, и при каждом появлении клипа в таймлайне ловит события от создающегося клипа, что показываетtrace(:
ObjectUtil.getClassInfo(event.target).name)
classes.intrinsic::AssetCreationDispatcher - Класс, в подгружаемом SWF, задается в поле "Base class" диалога "Linkage properties" для нашего клипа:
classes.intrinsic.AssetCreationDispatcher
Поле "Class" содержит имя класса "TestClip1".
Создаю также другой клип с именем класса "TestClip2", и тем же "Base class".
Приложение загружает SWF, и при каждом появлении вышеперечисленных клипов в таймлайне, в ловит события от создающегося клипа. Trace показывает уже:
TestClip1
TestClip2
Еще одна приятная возможность, которую дает нам такой прием:
Мы можем определить в классе-заглушке клипа загружаемого SWF ряд пустых методов (можно сказать интерфейс), а в рабочем классе загружающего приложения - этот же набор методов со всем необходимым кодом. В таймлайне наших клипов мы можем вызывать эти методы в любом месте, где только захотим, и они будут отрабатываться нашим главным приложением в соответствии с его кодом.
Конечно, для случая №1, все-таки нужно будет создать соответствующий AS-файл, иначе компилятор не пропустит вызовы неопределенных методов. Однако, для случая №2, создавать методы-заглушки даже не потребуется - компилятор пропускает такие вызовы. Ошибка времени исполнения будет генерироваться только в случае автономного выполнения загружаемого SWF. Но при выполнении его, будучи загруженным в приложение (которое, конечно, реализует весь набор методов), всё работает корректно.
Кроме того, важно, чтобы "совмещаемые" классы имели полностью эквивалентные имена, пакеты и цепочки вложенности пакетов. Иначе, они будут расцениваться как разные классы и не будут "совмещаться". И, конечно, загрузка производится в ApplicationDomain.currentDomain.
Еще одно важное замечание. Версия класса, которая включается в приложение, должна быть задействована каким-либо образом в коде приложения, иначе класс при компиляции не будет включен в приложение. Для этого, я сделал статический метод register(), который вызываю при инициализации приложения. Этот метод может ничего не делать - важно, что при наличии его вызова, класс будет внедрен в приложение при компиляции.
Еще одна достопримечательность этого метода: различные приложения, загружающие подготовленные таким способом SWF, могут реализовывать заготовленные в нем интерфейсы по-своему.
Еще раз спасибо BlooDHounD :). Вот что интересно - ведь такой подход имеет место быть не случайно, иначе, наверняка бы было предусмотренно какое-нибудь исключение, сообщающее о конфликте имен классов. Скорее всего, эта возможность даже имеет какое-нибудь название. Объяснение работоспособности этого подхода объясняется в документации к LoaderContext.applicationDomain (возможно объяснение есть где-то еще):
"Loader's own ApplicationDomain.
You use this application domain when using ApplicationDomain.currentDomain. When the load is complete, parent and child can use each other's classes directly. If the child attempts to define a class with the same name as a class already defined by the parent, the parent class is used and the child class is ignored." Другими словами, если существует конфликт имен классов, класс из загружаемого контента игнорируется.
* * *
Любопытная бага (предвидел, что будет что-то неладное). Оказывается слово intrinsic во Flex всё еще является ключевым (хотя в ActionScript 2.0 Migration про него написано, что его удалили) и выделяется жирным шрифтом. Любопытно, что автокомплит никак не хочет нормально работать с пакетами, обозванными этим именем, а в import-ах вообще начинает творится бардак. Лучше от него избавиться - может оно и к лучшему - тут подойдет что-нибудь типа classes.templates.
Кстати, порой приходится долго ломать голову над тем, как назвать тот или иной пакет/класс/метод/переменную. Иногда, размышляя над какой-нибудь сущностью (и вкапываясь в Lingvo), можно убить больше часа. Но оно стоит того.
среда, декабря 17, 2008
Настройка стиля предзагрузчика Flex-приложения
Сегодня мне просто нужно изменить стиль предзагрузчика - изменить цвет фона и панельки. Ничего дополнительно скриптовать просто не требуется.
Начнем с цвета фона - тут всё просто: В инете невооруженным взглядом по первой ссылке находим: Изменение цвета прелоадера flex приложения.
Ключевая строка: "на вкладке Flex Compiler дописать строку “-default-background-color #336699″ в Additional compiler arguments."
Хорошо бы теперь изменить внешний вид панельки. Точнее - хотя бы просто убрать надпись "Loading".
Поиски приводят нас в классу DownloadProgressBar. Собственно, в нем и находится всё управление нашей панелькой.
Ищем дальше. Это же наш старый знакомый! А настраивается он элементарно: всего в два действия. Или более углубленно: How to customize the standard Flex 2 loader.
Пробуем:
package display
{
import mx.preloaders.DownloadProgressBar;
public class CustomDownloadProgressBar extends DownloadProgressBar
{
public function CustomDownloadProgressBar()
{ super();
initializingLabel="Инициализация";
downloadingLabel="Загрузка";
}
}
}
* * *
<mx:application
preloader="display.CustomDownloadProgressBar"
>
. . .
Таким образом, мы заменили надписи меток.
Однако, скрыть совсем метку, используя showLabel=false; не получается. Так же не оказывают никакого влияния и все остальные параметры. Они корректно трейсятся, но не их изменение не влияет на внешний вид. По-видимому эти параметры задействуются в других случаях.
А вот MINIMUM_DISPLAY_TIME работает забавно - можно подольше подержать панель прелоадера на экране. Для тестов удобно. До этого, я перетаскивал во Flash CS и делал Simulate Download.
В общем, своей цели мы добились. На крайняк, можно просто установить initializingLabel=""; downloadingLabel="";. Кстати, извратиться и задать надписи с использованием HTML-разметки не получилось (строка выводится как есть).
понедельник, сентября 22, 2008
Ввод текста не в TextField: реально ли такое? AS3
Необходимо в некотором текстовом поле отобразить нажатый на клавиатуре символ.
Первая мысль - просто слушаем событие клавиатуры KeyboardEvent от, к примеру, Stage. Однако, событие имеет только два свойства, предоставляющих информацию о нажатом символе (не считая свойств, информирующих о вспомогательных клавишах): это charCode и keyCode. Из них, так или иначе, можно узнать, какая буква была нажата но - без учета текущего языка ввода! Как получить нужный символ с учетом текущей языковой версии ввода?
Идей решения этой проблемы я практически не нашел. Только здесь предлагается использовать невидимое текстовое поле с установленным на нем фокусе. Аналогичное решение предлагается здесь.
Порывшись в хелпе, в исходниках Flash/Flex-компонентов осуществляющих ввод текста, выяснилось, что всё сводится именно к TextField. Но в сам TextField, естественно, влезть невозможно.
Пока вижу единственный вариант - использовать TextField как источник введенного символа.
Хелп по этому поводу говорит: "Because mappings between keys and specific characters vary by device and operating system, use the TextEvent event type for processing character input." Но никто кроме TextField не умеет слушать событие TextEvent. То есть имеется подтверждение тому, что без текстового поля не обойтись.
Итак. Алгоритм таков (работает отлично):
Создаем TextField и куда-нибудь его вставляем. Делаем его невидимым - устанавливаем его свойство visible в false. Удивительно, но невидимые текстовые поля всё равно получают фокус! Не забываем установить type = TextFieldType.INPUT;
Подписываемся на прослушивание его события TextEvent.TEXT_INPUT. В обработчике этого события извлекаем нужный нам символ: event.text.charAt(0); и используем его как нам заблагорассудится. И не забываем при этом очистить поле.
Кроме того, подписываемся к this.someDisplayObject.stage на прослушивание события : KeyboardEvent.KEY_DOWN. В обработчике этого события мы устанавливаем фокус на наш невидимый TextField.
Решение, безусловно, выглядит как "заплатка". За то работает.
Если предполагаются другие интерактивные элементы, то нужно будет продумать систему отключения и включения нашей системы в зависимости от текущего фокуса ввода.
среда, сентября 10, 2008
Рефлексия и взрыв мозгов
Поискав в Гугле, стало ясно, что в рунете более распространен термин "интроспекция".
Что же это за зверь? Пишут всякое:
Например: В повседневной жизни, интроспекция - это проявление самоанализа. Интроспекция основывается на изучении собственных мыслей, ощущений, мотивов и поступков. Великий философ Сократ провел большую часть своей жизни, занимаясь самоанализом и призывая своих сограждан-афинян следовать своему примеру. Он даже утверждал, что для него самого "непроанализированная жизнь не стоит существования".
В случае программирования интроспекция означает возможность изучать что-либо, чтобы определить, что это такое, что оно умеет и что может делать. Интроспекция предоставляет программистам огромные гибкость и контроль. Если вы хоть раз работали с языками программирования, которые поддерживают интроспекцию, вы, возможно, испытываете схожие чувства: "непроанализированный объект не стоит воплощения".
Взрыв мозгов: Сложность разработки программного обеспечения обусловлена когнитивными и социальными аспектами профессии. ...
Прикладное применение рефлексии в .NET: NET Reflection представляет собой классический пример некоторой низкоуровневой библиотеки, которая может быть использована при решении прикладных задач. Что же это такое?Рефлексия (ударение на последнем "и", синоним слова интроспекция), или, по-английски, reflection - система, предоставляющая выполняемому коду информацию о нем самом (взрыв мозгов №2).
Тут тоже говорят: Интроспекция (англ. Introspection) - возможность определения типов и получения описаний (метаданных) типов и интерфейсов во время выполнения программы.
Вот тут мы натыкаемся на следы интроспекции в AS3: for…in теперь не выводит свойства и методы, объявленные в классе. Он выводит лишь динамические свойства объекта. В AS3 введен более продвинутый механизм интраспекции объектов, называемый describeType. Используйте describeType для интроспекции объектов в AS3.
Превосходно! Посмотрим ка Доки:
public function describeType(value:*):XML
Ах ну конечно! Это же та самая функция, которая выдает полное описание класса в виде XML.
Кроме того, хорошая статейка Performing object introspection открывает еще один полезный для интроспекции класс mx.utils.ObjectUtil.
Поняв, в принципе, о чем речь, вернемся к исходной статье. Здесь презентация. Кроме того, можно посмотреть статью ее автора - ActionScript - Reflective Programming.
В итоге, как же применить рефлексию на практике? Для себя я отложил два применения:
1-е очевидное: Мы имеем дело с закрытой библиотекой недокументированных классов и имеем возможность исследовать их свойства и методы.
2-е концептуальное: Если я не ошибаюсь, на рефлексии можно строить совершенно альтернативные механизмы, реализующие те же возможности, которые предоставляют наследование и композиция. Причем, как утверждает автор статьи, этот подход может дать более изящные решения.
В общем, почва для размышлений есть.
* * *
Еще одно интересное решение недавно появилось в обсуждениях - как раз на тему "Код изучает сам себя": Определение родителя класса. Хотя тема не совсем соответствует содержанию (скорее "Определение имени класса, который вызвал метод рассматриваемого класса"), решение очень любопытное:
Если в дебаговом плеере, то можно распарсить (new Error()).getStackTrace() и получить имя класса.
Денис Коляко
К сожалению, оговорка про "дебаговый плеер" накладывает существенное ограничение на использование этого подхода...
среда, июня 18, 2008
Как получать сообщения от внедряемых/подгружаемых SWF. AS3
Она долго проигрывается, и после ее завершения, мы хотим перейти, к примеру, на другой стейт. Но как поймать момент окончания заставки? А если нам надо как-то среагировать на ее команды в процессе воспроизведения? На ум приходит единственный вразумительный способ - генерировать события из заставки.
В простом случае, делается это всего одной строчкой:
this.dispatchEvent(new Event("Done"));Но как, и кому подписываться на прослушивание этого события?
Да очень просто. В скрипте инициализации Flex-приложения вписываем:
this.addEventListener("Done", this.doneHandler, true);Постараюсь пояснить происходящее:
При параметре useCapture, установленном в true, мы будем ловить наше событие на фазе захвата. На этой фазе, событие пройдет через всю цепочку дисплей-объектов, в которой сидит наш клип, до самого Stage.
Если мы не установим useCapture в true, то событие не будет обработано, т.к. событие, генерируемое из контейнера не имеет фазы target, а фаза bubbling отсутствует, т.к. мы генерируем событие с параметром по умолчанию bubbles=false.
Можно сделать наоборот - ловить событие на фазе bubbling. Тогда, при генерации события указываем bubbles=false, и получаем:
this.dispatchEvent(new Event("Done", true)); и
this.addEventListener("Done", this.doneHandler); В процессе выяснений обстоятельств, я наткнулся на статейку: "Reader Question: Why isn’t event bubbling working" где хорошо разъясняется аналогичная ситуация.
пятница, апреля 25, 2008
"Ручной" cacheAsBitmap. AS2
Для оптимизации быстродействия flash-приложения, мы часто прибегаем к кэшированию:
- Устанавливается галка "Use runtime bitmap caching" - не очень удобный способ.
- В as-коде клипа пишется cacheAsBitmap=true - удобно, но при кэшировании мы теряем сглаживание. То есть перемещаться наша картинка будет "рывками".
Для того, чтобы лучше контролировать наше кэширование, попробуем сделать его вручную. Для этого сделаем снимок нашего клипа, удалим всё его содержимое и вставим снимок обратно в клип.
Код можно посмотреть здесь: "Ручной" cacheAsBitmap. AS2.
Особенности:
- Ограничения по размерам не более 2880х2880.
- Все визуальные элементы должны быть клипами, иначе не всё удалится, что ухудшит производительность.
- Несмотря на выставленные параметры в attachBitmap
pixelSnapping="auto"иsmoothing=true, каринка всё равно продолжает перемещаться рывками. Можно поменять pixelSnapping на "never" - не имеет значения. Однако, как только была добавлена строчка:this._height-=0.5;
сразу включилось сглаживание и картинка поплыла плавно. Почему именно 0.5? Это минимальное искажение было установлено экспериментально для моей конкретной задачи. Для разных размеров может быть разное значение. Главное, чтобы произошло незначительное искажение хотя бы одного из размеров (горизонтального или вертикального).
Возможно есть более элегантное решение.
понедельник, марта 31, 2008
Пофреймовый захват параметров трансформации клипов.
Решает он следующую задачу. На сцене есть некоторое множество клипов. Процесс работы приложения делится на этапы. На каждом этапе, клипы принимают различные положения, масштабируются и поворачиваются. Переходы между этапами - плавные. Клипы каким-либо образом плавно трансформируются занимают новое положение.
Итак, необходимо задать параметры трансформации клипов для каждого этапа. Напрашивается решение - создать массивы параметров трансформации для каждого этапа. При каждой смене этапа, выполнять твин для клипов, соответствующих элементам массива.Но как создать такой массив с наименьшими затратами? Вручную высчитывать координаты, масштаб и угол поворота - задача не для слабонервных (к которым мы все относимся :) ).
Решение: Создаем таймлайн, в котором каждый фрейм соответствует этапу. Во фреймах располагаем наши клипы в надлежащих положениях. Важно, чтобы количество и имена клипов не изменялись (иначе на каких-то этапах клипы будут отображаться некорректно, хотя, эту особенность тоже можно использовать в своих целях).
Создаем массив для сбора трансформаций.Каждый элемент массива, это характеристика одного этапа. Это может быть ассоциативный массив, у которого в качестве ключей используются идентификаторы этапов. Он содержит идентификатор этапа и массив трансформаций клипов на этом этапе.
Каждый элемент массива трансформаций содержит имя клипа параметры его трансформации. Это может быть ассоциативный массив, у которого в качестве ключей используются имена клипов.
В итоге получаем двумерный массив. По Y - этапы, по X - клипы.Теперь Для каждого фрейма делаем сканирование for..in, получаем параметры трансформации клипов и заполняем наш массив. Можно контролировать сбор информации, указав функционально-специфичные имена для различных групп клипов.
В последнем фрейме (последнего этапа) нужно вызвать функцию окончания сканирования. Эта функция должна позиционировать основной клип на начальный этап и остановить. В качестве начального, можно выбрать любой из этапов (идентификатор которого как раз можно передать в качестве параметра функции окончания сканирования).
На этом, навигация по таймлайну заканчивается. Вся анимация отдается в руки программного твина. При вызове функции перехода на новый этап, из массива этапов выделяется соответствующий элемент с массивом трансформаций. Всем клипам, полученным при переборе массива трансформаций назначается твин с соответствующими параметрами.
Изложенное на словах проще выразить в коде :). Постараюсь выложить.Дублирование папки в библиотеке символов.
Есть клип, содержащий ряд вложенных клипов, которые также могут содержать другие клипы. Клип и набор вложенных клипов находится в библиотеке в специально отведенной папке.
Задача - полностью дублировать клип и поместить всё дублированное содержимое в другую папку.
Недолго повозившись, пришел к следующему способу:
- Поместить все символы, подлежащие дублированию в отдельную папку.
- Поместить все общие, не подлежащие дублированию, символы в папку общих символов.
- Создать служебную папку, например "Duplication", для дублирования. Удобно выделить специальную папку, чтобы избежать путаницы при дублировании: когда мы будем вставлять скопированную папку, необходимо, чтобы вставка производилась обязательно в какую-либо папку, и кроме того, дублированные символы вне дублируемой папки (где бы они не были до этого) будут вставлены рядом с новой дублированной папкой.
- В контекстном меню (вызываемого правой кнопкой мыши) дублируемой папки выбрать Copy.
- В контекстном меню служебной папки папки выбрать Paste. В папке появится наша скопированная папка со всеми ее символами. Рядом с папкой будут помещены символы, которые были вложены в дублируемые символы, но находились в других папках библиотеки.
- Переименовываем новую папку.
- Перетаскиваем новую папку из служебной папки в нужное нам место. Если папка не была переименована и переносится в место, где лежит оригинал, появится окно, в котором надо выбрать "Don't replace ...".
- Теперь надо что-то сделать с общими символами, оставшимися в служебной папке. Если их удалить - они удалятся из таймлайна новых дублированных клипов.
Поэтому, их нужно отправить в те же места, где располагались их оригиналы - в папку общих символов. При этом опять появится окно выбора, и в этот раз уже необходимо выбрать "Replace ...". Не нужно бояться замены - ведь это абсолютно те же самые символы. Но нужно соблюдать осторожность :) - Теперь с дублированным клипом можно делать всё что угодно - менять текст, графику и т.д. Это никак не отразится на оригинале, и что важно - мы имеем копию структуры и особенностей таймлайна оригинала в новом клипе.
Дублировать папки библиотеки умеют так же некоторые экстеншены.
Попробуем, как работает Duplicate Library Folder. Это расширение бесплатно.
Качаем и ставим, рестартуем Flash.
Устанавливаем курсор в библиотеке на нужную папку и выбираем в меню "Commands -> Duplicate Folder".
Flash дает фатальную ошибку и глухо виснет.
Жаль. Удаляем.
Попробуем HOLO MultiPanel trial. На ознакомление дается всего 5 дней. Стоит свыше 21 зеленой единицы.
Качаем и ставим, рестартуем Flash.
Теперь у нас есть чудесная панелька (вызывается через "Window > Other Panels > HOLO MultiPanel Trial").
Впечатлило. Тут много всяких утилит, в том числе и "Library Utilities", где имеется нужный нам тул. Работает отлично - всё, что мы выше делали за 8 шагов, решается одним нажатием кнопочки "Duplicate".
Вроде бы стоит того, чтобы расстаться с небольшой денежкой. А кто не хочет платить - "ручками" копировать не так уж и сложно, особенно когда выработается навык.
понедельник, февраля 18, 2008
Синхронизация случайных чисел для клиент-серверных приложений.
Итак, есть задача случайным образом распределять какие-либо данные на клиентских приложениях. При этом должны генерироваться случайные, но одинаковые на всех клиентах числа. Для этого, при инициализации и синхронизации взаимодействия клиентов и сервера, сервер генерирует гамму случайных чисел и шлет ее всем клиентам. Клиенты сохраняют полученную гамму.
Клиенты имеют свои "прозрачные" методы
random();, которые выдают случайное число. На самом деле, метод random(); при вызове попросту выбирает каждый последующий элемент из гаммы и возвращает полученное значение. После выборки последнего элемента, указатель перемещается на начало гаммы.Для "подновления" генерируемых случайностей, можно (а во многих случаях нужно) подгружать новую гамму. При этом, процесс подновления можно легко встроить в протокол обмена данными. Периодически "пристраивая" свежую гамму в ответы сервера на запросы, требующие синхронизации клиентов, можно делать "свежие" вливания в вероятность случайных чисел.
Код класса псевдо-генератора прилагается.
четверг, января 31, 2008
Инструмент для администрирования SmartFoxServer
Чтобы избежать этой проблемы, я нашел два средства:
- Плохой способ - cделал загрузчик с loadMovie, который грузит AdminTool.swf в рут. Из-под FlashIDE можно спокойно запускать.
- Конечно же самый лучший способ - убрал SWF в Zinc. Облагородил его красочным скином и сделал EXE-файл.
Теперь можно комфортно администрировать сервер.
понедельник, января 21, 2008
Как лучше постить код в Bloggere
Итак, решение позволяет сделать так, чтобы код помещался в контейнере TextArea. Не более того.
Вот код преобразовывающего скрипта:
// CodeBlocksSubstitutor
var i=0;
var j=0;
while(_DIV = document.getElementById("code"))
{ _DIV.id="processed";
if ((_DIV.innerText==null)(_DIV.innerText=="")) continue;
AREA = document.createElement("TEXTAREA");
AREA.id = "codeArea"+i;
if (_DIV.rows==null) AREA.rows = 10; else AREA.rows = _DIV.rows;
AREA.cols = 53;
AREA.readOnly = true;
AREA.wrap = "off";
i++;
AREA.innerText=_DIV.innerText;
newdiv=document.createElement("DIV");
newdiv.appendChild(AREA);
div_parent=_DIV.parentNode;
div_parent.replaceChild(newdiv,_DIV);
}
</script>
В тексте, код необходимо поместить в контейнер:
</div>
Параметр id="code" указывает на то, что текст необходимо обработать.
Параметр rows задает количество строк поля TextArea.
Тег div можно заменить на любой другой, например, code. Это повлияет на внешний вид контейнера.
Код я вставил в виде модуля HTML/JavaScript в нижний блок шаблона моего блога.
Пример:
import flash.display.Sprite;
import flash.display.Bitmap;
[Frame(factoryClass="MyFactory")]
public class FrameTest extends Sprite
{
[Embed(source="big_asset.jpg")]
private var Asset:Class;
public function FrameTest()
{
init();
}
public function init():void
{
var asset:Bitmap = new Asset();
addChild(asset);
}
}
}
* * *
Обновил код: для пользователей альтернативных браузеров и Mac, текст в полях ввода не виден, всё из-за того, что на свойство innerText им совсем наплевать - оно не поддерживается DOM. Посему, не вдаваясь в подробности, я просто отключаю помещение кода в TextArea для всех браузеров, которые не IE. Возможно, позже найдется лучшее решение.
Да, знаю - камень в огород бесплатного блогирования.
пятница, января 18, 2008
Делаем прелоадер для Flex-приложения. AS3.
А что делать, если наш проект компилируется Flex SDK?
Можно сделать маленький модулек, который будет загружать и мониторить загрузку основного SWF. Ну а если требуется наличие только одного SWF?
Люди советуют почитать статью Preloaders in AS3. Читаем.
Основную мысль автору статьи, подсказал Ted Patrick, намекнув на мета-тег [Frame] и поглядеть исходник mx.core.Application.
Поглядим-ка
"...\Flex2SDK\frameworks\source\mx\core\Application.as ".
Как отметил 101 (тот что автор статьи) там и правда есть тег
[Frame(factoryClass="mx.managers.SystemManager")]. А в комментарии, по-моему, ключевой является фраза "Все фреймворки инициализируются SystemManager-ом".Идем смотреть
"...\Flex2SDK\frameworks\source\mx\managers\SystemManager.as".
И правда - видим интересные фразы типа "ВНИМАНИЕ: Минимизируйте не флэшовые классы, которые импортируете здесь, всё что связано с SystemManager будет загружено в 1й фрейм до того, как загрузится прелоадер, и вообще, что-либо отображающееся." Кроме того, несколько ниже, говорится, что "SystemManager - первый визуальный класс, который создается в приложении. Он так же отвечает за создание mx.preloaders.Preloader, который отображает mx.preloaders.DownloadProgressBar до конца загрузки приложения, после чего SystemManager создает mx.core.Application instance". Собственно, вызывается метод SystemManager.create, код которого приводит 101 (автор).
Он пришел к следующим мыслям:
- Сначала создаем основной класс MainClass как обычно и указываем компилятору чтобы он его компилил.
- Затем в этом классе вставляем тег [Frame(factoryClass="MyFactoryClass")], который указывает на некий другой класс MyFactoryClass.
Итак, нам остается всего-навсего создать класс обычного прелоадера, который:
- Делает stop();
- Мониторит загрузку любым удобным для нас способом.
- После полной загрузки делает nextFrame();
Еще одна любопытная особенность этого решения - основной таймлайн представляет MainClass, но в качестве "Document Class" теперь выступает не MainClass, а MyFactoryClass. Из этого следует:
- MyFactoryClass должен наследоваться от MovieClip. И не в коем случае не от Sprite.
- При инстанцировании MainClass, необходимо добавить (addChild) его в дисплей-лист MyFactoryClass.
- MainClass не будет являться корнем дисплей-листа. Он будет чайлдом MyFactoryClass.
- В своем конструкторе, MainClass не должен ссылаться на "stage", так как он будет доступен только после добавления (addChild) MainClass в дисплей-лист.
В основном классе FrameTest - это то что выше называлось MainClass - всё просто. Имбедится и выводится картинка "big_asset.jpg", желательно очень большого размера. Единственное необычное - это фраза
[Frame(factoryClass="MyFactory")].Класс MyFactory - это наш вышеописываемый MyFactoryClass.
- В конструкторе производится остановка тайм-лайна stop(), выставляются параметры stage и добавляется обработчик "ENTER_FRAME".
- Обработчик onEnterFrame() рисует полосу состояния загрузки вычисляя процент загрузки:
var percent:Number = root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal; - При выполнении условия framesLoaded == totalFrames, объект отписывается от события "ENTER_FRAME", осуществляет переход на следующий фрейм nextFrame() и производит инициализацию init().
- Метод инициализации init() получает определение основного класса
var mainClass:Class = Class(getDefinitionByName("FrameTest"));и, если такой класс существуетif (mainClass), инстанцирует его и добавляет в дисплей-лист:var app:Object = new mainClass(); addChild(app as DisplayObject);.
Всё. Переходим к практике.
* * *
Не забудем положить картинку "big_asset.jpg" в папку с классами.
Первая коррекция - getDefinitionByName вызывает исключение, в случае если класс не найден. Поэтому проверки if(mainClass) недостаточно. Нужна обработка исключения try ... catch.
* * *
Пробуем trace(this.currentFrame);. Он выдает правильно - 1 из конструктора MyFactory, 2 - из init();.
Попробуем, как это будет работать в интернете. Хм. Прелоадер отрабатывает, но как-то поздно. Мой Naviscope показывает, что SWF загружается больше чем на половину, когда только начинает происходить отрисовка полосы загрузки. Попробую еще утяжелить SWF-ку. Для этого добавляю картинок.
Интересное наблюдение - если накопировать одну и ту же картинку и имбедить копии, размер SWF не изменится - как будто внедрена одна картинка! Вот это сжатие!
Итак, утяжелил до 20 мБ. Теперь всё встало на свои места. Прелоадер аккуратно отрабатывает объем и затем отображается картинка! Всё дело было в слишком быстром интернете.
Итак, подход прост и практичен. Спокойно делаем правильные и эффектные флэшки любого размера!
четверг, ноября 29, 2007
Объект с глобальным доступом. Полезные свойства.
* * *
И синхронизировать!
* * * UPDATE * * *
Изменение заголовка:
Старый - "Singleton как средство передачи данных между объектами"
Новый - "Объект с глобальным доступом. Полезные свойства."
Причина - неверное использование термина "Singleton"
воскресенье, ноября 25, 2007
Загружаемый растр. Как включить сглаживание при трансформациях. AS2
Решил обойти эту проблему, используя класс BitmapData. Код здесь.
суббота, ноября 17, 2007
Об особенностях мониторинга загрузки, об экспорте для AS и об импорте классов. AS2
- Если клип экспортируется для ActionScript посредством Linkage > Export for ActionScript, при отмеченном параметре Export in first frame, этот клип будет доступен для "attachMovie" с первого же фрейма, но будет помехой для правильного мониторинга загрузки SWF-файла, т.к. первый фрейм не будет выведен до тех пор, пока все его клипы не загрузятся. При этом, загрузка некоторого (довольно приличного) объема данных не будет отображена, что не есть хорошо.
Для того, чтобы отложить загрузку такого клипа, необходимо снять параметр Export in first frame. Однако если явным образом такой клип не присутствует во временной шкале, он не будет экспортирован в SWF вообще. Поэтому, для экспорта таких клипов нужно отвести какой-нибудь фрейм, который никогда не будет показан при воспроизведении SWF. - Классы из Publish settings > Flash > Settings > Classpath и классы из текущего каталога импортируются во фрейм, указанный там же, в Export frame for classes. Для идеального мониторинга загрузки, лучше указать не 1-й фрейм, а какой-либо другой, располагающийся после модуля мониторинга загрузки .
Странно, но классы, импортируемые "вручную" также не могут быть использованы до этого фрейма. - Если с клипом ассоциирован класс по средством параметра Linkage > Export for ActionScript, и для клипа и для класса всё происходит как в 1-м и 2-м пунктах.
Особенности мониторинга загрузки (preloader):
- Модуль мониторинга загрузки должен располагаться до фрейма, в который импортируются классы и экспортируются клипы.
- Мониторинг не может быть описан классом.
- Модуль мониторинга загрузки должен иметь минимальный объем.
- При подсчете процента загрузки SWF, необходимо учитывать объем уже загруженных на момент активации мониторинга данных:
На момент инициализации мониторинга:
this.skipped=_root.getBytesLoaded();
this.total=_root.getBytesTotal()-this.skipped;
В процессе подсчета загруженного объема:
var progress:Number=(_root.getBytesLoaded()-skipped)*100)/this.total;
Код подключаемого кода здесь.