понедельник, марта 31, 2008

Пофреймовый захват параметров трансформации клипов.

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

Решает он следующую задачу. На сцене есть некоторое множество клипов. Процесс работы приложения делится на этапы. На каждом этапе, клипы принимают различные положения, масштабируются и поворачиваются. Переходы между этапами - плавные. Клипы каким-либо образом плавно трансформируются занимают новое положение.

Итак, необходимо задать параметры трансформации клипов для каждого этапа. Напрашивается решение - создать массивы параметров трансформации для каждого этапа. При каждой смене этапа, выполнять твин для клипов, соответствующих элементам массива.

Но как создать такой массив с наименьшими затратами? Вручную высчитывать координаты, масштаб и угол поворота - задача не для слабонервных (к которым мы все относимся :) ).

Решение: Создаем таймлайн, в котором каждый фрейм соответствует этапу. Во фреймах располагаем наши клипы в надлежащих положениях. Важно, чтобы количество и имена клипов не изменялись (иначе на каких-то этапах клипы будут отображаться некорректно, хотя, эту особенность тоже можно использовать в своих целях).

Создаем массив для сбора трансформаций.
Каждый элемент массива, это характеристика одного этапа. Это может быть ассоциативный массив, у которого в качестве ключей используются идентификаторы этапов. Он содержит идентификатор этапа и массив трансформаций клипов на этом этапе.

Каждый элемент массива трансформаций содержит имя клипа параметры его трансформации. Это может быть ассоциативный массив, у которого в качестве ключей используются имена клипов.

В итоге получаем двумерный массив. По Y - этапы, по X - клипы.

Теперь Для каждого фрейма делаем сканирование for..in, получаем параметры трансформации клипов и заполняем наш массив. Можно контролировать сбор информации, указав функционально-специфичные имена для различных групп клипов.

Сканирование каждого фрейма можно реализовать вызовом из этого фрейма сканирующей функции с параметром-идентификатором этапа.

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

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

Изложенное на словах проще выразить в коде :). Постараюсь выложить.

Дублирование папки в библиотеке символов.

Идея в следующем:
Есть клип, содержащий ряд вложенных клипов, которые также могут содержать другие клипы. Клип и набор вложенных клипов находится в библиотеке в специально отведенной папке.
Задача - полностью дублировать клип и поместить всё дублированное содержимое в другую папку.
Недолго повозившись, пришел к следующему способу:
  1. Поместить все символы, подлежащие дублированию в отдельную папку.
  2. Поместить все общие, не подлежащие дублированию, символы в папку общих символов.
  3. Создать служебную папку, например "Duplication", для дублирования. Удобно выделить специальную папку, чтобы избежать путаницы при дублировании: когда мы будем вставлять скопированную папку, необходимо, чтобы вставка производилась обязательно в какую-либо папку, и кроме того, дублированные символы вне дублируемой папки (где бы они не были до этого) будут вставлены рядом с новой дублированной папкой.
  4. В контекстном меню (вызываемого правой кнопкой мыши) дублируемой папки выбрать Copy.
  5. В контекстном меню служебной папки папки выбрать Paste. В папке появится наша скопированная папка со всеми ее символами. Рядом с папкой будут помещены символы, которые были вложены в дублируемые символы, но находились в других папках библиотеки.
  6. Переименовываем новую папку.
  7. Перетаскиваем новую папку из служебной папки в нужное нам место. Если папка не была переименована и переносится в место, где лежит оригинал, появится окно, в котором надо выбрать "Don't replace ...".
  8. Теперь надо что-то сделать с общими символами, оставшимися в служебной папке. Если их удалить - они удалятся из таймлайна новых дублированных клипов.
    Поэтому, их нужно отправить в те же места, где располагались их оригиналы - в папку общих символов. При этом опять появится окно выбора, и в этот раз уже необходимо выбрать "Replace ...". Не нужно бояться замены - ведь это абсолютно те же самые символы. Но нужно соблюдать осторожность :)
  9. Теперь с дублированным клипом можно делать всё что угодно - менять текст, графику и т.д. Это никак не отразится на оригинале, и что важно - мы имеем копию структуры и особенностей таймлайна оригинала в новом клипе.
ВНИМАНИЕ: При дублировании нужно учесть, что повторение Linkage ID клипов недопустимо.

Дублировать папки библиотеки умеют так же некоторые экстеншены.

Попробуем, как работает Duplicate Library Folder. Это расширение бесплатно.
Качаем и ставим, рестартуем Flash.
Устанавливаем курсор в библиотеке на нужную папку и выбираем в меню "Commands -> Duplicate Folder".
Flash дает фатальную ошибку и глухо виснет.
Жаль. Удаляем.

Попробуем HOLO MultiPanel trial. На ознакомление дается всего 5 дней. Стоит свыше 21 зеленой единицы.
Качаем и ставим, рестартуем Flash.
Теперь у нас есть чудесная панелька (вызывается через "Window > Other Panels > HOLO MultiPanel Trial").
Впечатлило. Тут много всяких утилит, в том числе и "Library Utilities", где имеется нужный нам тул. Работает отлично - всё, что мы выше делали за 8 шагов, решается одним нажатием кнопочки "Duplicate".
Вроде бы стоит того, чтобы расстаться с небольшой денежкой. А кто не хочет платить - "ручками" копировать не так уж и сложно, особенно когда выработается навык.

Наследование от Button. AS2

Flash не перестает удивлять, хотя, казалось бы в AS2 всё уже изведано.

На сцене несколько кнопок, которые трансформируются простым таймлайновым моушн-твином. Задача - быстренько навесить на них функционал, и желательно не трогать тайм-лайн (просто много ключевых фреймов, которые не хочется тупо лопатить).
Первая мысль - сделать наследников класса Button, назначить их в Linkage для этих символов и радоваться жизни.

Не получилось. Даже трейс из конструктора не отрабатывает.
Возможно, есть способы это сделать оперируя прототипом или используя хаки. На поиски и шаманство, увы, времени небыло. Пришлось лопатить.

Итак, в AS2 строить логику с учетом модификации Button посредством наследования, лучше даже не пытаться - неблагодарное занятие.

суббота, марта 29, 2008

Первый законченый проект на Flex. Грабли и впечатления.

Вот закончен еще один проект. И отличие его от предыдущих - это чистый Flex-проект построенный на MXML-верстке.

О проекте

Вкратце - результат проедставляет собой презентацию-каталог (оффлайн, версия для CD/DVD и версия для TouchScreen), в котором основной элемент - интерактивная карта России, разделенная на регионы. По клику на регионы осуществляется его увеличение и вывод городов. По клику на город, выводится панель со списком типов объектов (презентуемых заказчиком). По клику на тип объекта, открывается список самих объектов с фото-превьюшками и описаниями. По клику на описание объекта выводится более подробное описание с теми же фото-превьюшками, по клику на которые показывается крупное фото. Кроме того - два доп-раздела "О компании" и "Контакты".

На flash-разработку проекта я выделил две недели, т.е. в реальных условиях менее 10 рабочих дней.

На распутье

Сначала возникло желание делать проект на моем старом (правильнее сказать - устаревшем) но отработанном презентационном движке AS2. Но структура проекта совсем не похожа на послайдовку, поэтому возник соблазн сделать презентацию другим способом, и полностью задействовать Flex.

Дизайн-макет, на первый взгляд, показался довольно сложным, но глаз уже уловил, насколько выигрышно было бы использовать Flex-верстку. Верстать и программировать динамические списки, поставляемые выборками из XML-базы, "ручками" на AS2 - тоска.

Опыт работы с Flex за плечами уже есть, AS3 освоен. Но имеют место сомнения: "А вдруг упрусь в какую-нибудь проблему или глюк, и сроки полетят?" "Сроки жесткие, может быть лучше по-старинке, AS2?" "Зато уверенность, стабильность и предсказуемость". После часа раздумий, решился рискнуть - Flex.

За работу

Моя рабочая платформа - Flex Builder 3 Plug-in for Eclipse.

Настало время применить теорию на практике. Для начала, "порезал" макет, подготовил все "ассеты" и начал верстать экраны.

Взаимодействие пользователя представляет собой сложную систему состояний экрана. Решил использовать систему состояний Flex (states). И сделать это так - сначала сверстать все элементы приложения в базовом состоянии, а потом создать ряд состояний для каждого этапа работы приложения, в которых скрывать/открывать и трансформировать элементы.

При верстке проблем не возникло. Очень напоминает верстку сайтов. При помощи стилей можно творить чудеса - использовать скины даже не потребовалось. Всё необходимое было сверстано совсем без затыков за один-два дня. Впечатления самые положительные.

Параллельно, моим коллегой готовилась флэшка с картой. Клип с картой подгружается компонентом mx:SWFLoader. Сначала мы решили сделать ее в виде большого таймлайна, и навигация по карте осуществлялась бы командами gotoAndPlay(""). Выбор такого решения (конечно не очень удачного) был обусловлен желанием сделать карту в виде видео-ролика с 3D-эффектами. В итоге сроки свели задачу к простой флэш-анимации :). Позже стало ясно, что способ тайм-лайновой анимации совсем не интересен и карту анимировали программно Tween-ом.

Затем, после отладки навигации по состояниям (которые пока сменялись резкими переходами без анимации), настало время наложить эффекты появления и трансформации элементов. При анимировании появления/скрытия, я столкнулся с ситуацией, изложенной ниже. До конца контролировать ситуацию на получилось, но компромиссное решение было найдено.

Зашивание проекта в Zinc особых трудностей не составило. Zinc спокойно интегрируется во Flex-проект. Использовались основные объекты глобального класса mdm:
mdm.Application - для получения директории, из которой запускается приложение,
mdm.Application.Library - для работы с библиотекой приложения.
mdm.FileSystem - для тестирования наличия файлов.

В итоге, хочется сказать, что проект завершился успешно. Скорость разработки на Flex превзошла мои ожидания, и сэкономленное время позволило дополнительно отладить и отточить приложение (переделать анимацию интерактивной карты коренным образом). Впечатления от работы с Flex остались самые положительные, и я рад, что рискнул.

* * *

Ниже изложено несколько нехороших ситуаций:

Неверно спроектированная верстка

Дизайн-макет был разработан на разрешение 1600х1200 - для TouchScreen. Позже, когда приложение было уже на этапе отладки, выяснилось, что нужна еще одна версия - предназначенная для распространения на CD/DVD, а значит, под меньшее разрешение. Пришлось срочно переверстать новую версию под 1024х768. Если бы я изначально заложился под трансформируемую верстку (благо, во Flex эта возможность реализована превосходно), лишней работы делать бы не пришлось. И версии можо было бы не плодить. На будущее - нужно изначально закладываться на гибкую верстку - стоит того.

Внедрение шрифта формата .OTF

При внедрении шрифта возникла следующая проблема. Мне необходимо внедрить шрифт MyriadPro. Это TrueType-шрифт формата .OTF.
Код внедрения в стили:


@font-face
{
font-family: MyriadPro;
font-weight: normal;
src: url("Assets/Fonts/MyriadPro-Regular.otf");
unicode-range:
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, /* UE */
U+0410-U+042F, /* Cyrillic Upper-Case */
U+0430-U+0451; /* Cyrillic Lower-Case */
}

В окне FB Design шрифт отображается некорректно, выдает ошибку транскодирования: "Exception during transcoding: Font for alias 'MyriadPro' with plain weight was not found at: ...MyriadPro-Regular.otf ..." И то же самое для версии "bold".
Однако, при компиляции проекта ошибки нет и в приложении шрифт отображается корректно на разных компьютерах. Отнес это к проблемам (читай - глюкам) средства визуальной разработки FB.

Эффект появления/скрытия и states

Пришлось повозиться с эффектом mx:Fade, используемого для появления/скрытия некоторых компонентов.

По началу я предположил, что если я создам эффекты Fade (один для появления и другой для скрытия) и укажу его для некоторых компонентов в стилях showEffect и hideEffect, то при смене состояния, при изменении свойства visible, компоненты будут плавно появляться/исчезать. Как бы не так. При формировании состояния, выполняются (тупо, без каких либо перепроверок и оптимизаций) все действия - начиная с базовых состояний. Если в базовом состоянии visible устанавливается в false, а в текущем, базирующемся на нем, в true, то будет выполнено два действия со всеми вытекающими последствиями. Если Fade-скрытие еще не успело завершится, а уже вызывается Fade-появление, то последнее будет просто проигнорировано. Короче - полный разлад и совсем не адекватный результат. То же самое относится и к другим видам эффектов.

Для анимации такого рода необходим другой прием. При использовании transitions всё сразу встало на свои места. Конечно, это принесло другие сложности, но зато эффект появления/скрытия работает как часы.

Маскирование контента SWFLoader

Проблема связана со следующей особенностью. Клип интерактивной карты в процессе работы приложения может трансформироваться (трансформируемый клип расположен в главном таймлайне загружаемой флэшки). Но он должен отображаться в строго отведенной прямоугольной области. Казалось бы, чего проще - поместить его в Box, у которого horizontalScrollPolicy="off" verticalScrollPolicy="off" clipContent="false". Не работает. Причем странно - пока клип карты перемещается, границы отсекаются. Как только клип останавливается, всё что вылезает за пределы области появляется.

Пришлось накладывать маску программно, высчитывая координаты и размер области.

Воспроизведение FLV

В самом конце столкнулись со следующей проблемой. Презентация начинается с видео-заставки. Заставка - файл FLV, который подгружается в mx:VideoDisplay. Проблема заключалась в том, что компонент отказался воспроизводить внешнее видео, если презентация находится на удаленном сервере (с этим то всё ясно - включена опция -use-network=false), или на сменном носителе - записанная на CD/DVD (а вот это - критично).

К сожалению, FLV нельзя внедрить посредством @Embed. Но это может сделать Zinc, чем я немедленно воспользовался. Но такое решение не самое красивое. В дальнейшем придется выяснить, почему не воспроизводится FLV со сменных носителей, и как этого избежать. Возможно, необходимо установить параметры безопасности, а может быть проблема связана с задержками доступа к CD/DVD приводу в связи с чем, что-то рассинхронизировалось в приложении.

четверг, марта 20, 2008

XMLList и его длина. AS3

Ужасные грабли. Для того, чтобы получить длину XMLList мы по привычке пишем xml_list.length;. Но это неверно, так как length является МЕТОДОМ!
Это удивительная и ужасная непонятность, создающая кучу проблем. Особенно, когда идет работа с объектами, генерируемыми байндингами и другими неявными ссылками, где length не подставляется автоматом.
Итак, обращаем особое внимание:
Не xml_list.length;, а xml_list.length();
То же самое относится и к классу XML.

вторник, марта 18, 2008

Как открыть ссылку, заданную в htmlText компонента Text. Flex

Если задать HTML-текст как мы это делали всегда, ссылка станет активной, но открываться не будет:
<a href='http://www.adobe.com' target='_blank'>Go Home</a>

На лайф-доках есть статья, которая открывает нам этот новый секрет Flex. Теперь необходимо создавать обработчик, который будет осуществлять переход по ссылке:
<?xml version="1.0"?>
<!-- textcontrols/LabelControlLinkEvent.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" borderStyle="solid" backgroundGradientColors="[#FFFFFF, #FFFFFF]">
<mx:Script>
<![CDATA[
import flash.events.TextEvent;
public function linkHandler(event:TextEvent):void {
myTA.text="The link was clicked."; // Open the link in a new browser
window. navigateToURL(new URLRequest(event.text), '_blank')
} ]]>
</mx:Script>
<mx:Label selectable="true" link="linkHandler(event);">
<mx:htmlText>
<![CDATA[<a href='event:http://www.adobe.com'>Navigate to Adobe.com.</a>]]>
</mx:htmlText>
</mx:Label>
<mx:TextArea id="myTA"/>
</mx:Application>

Таким образом, мы сами контролируем открытие ссылок из текстовых блоков.

среда, марта 12, 2008

Грабли с фокусом, при совместной работе TextField и активных клипов. AS2

При разработке небольшого фреймворка (без подробностей), столкнулся с проблемой. Заключалась она в следующем:
По нажатию на некоторые активные клипы, открывались окна с TextField.
Текстовые поля:

  • были в режиме selectable=true,
  • имели в себе HTML-ссылки,
  • были в режиме type="input"
После клика на них, нарушалось поведение активных клипов при отжатии. После отжатия активировалось событие rollOut, и в дальнейшем, это распространялось на все (или почти все - в неуловимой закономерности) активные элементы.

Решение проблемы оказалось простым:
Необходимо при обработке события onPress установить фокус на этот элемент:
Selection.setFocus(active_clip);

Для того, чтобы не появлялся желтый прямоугольник фокуса, необходимо определить: active_clip._focusrect=false;

* * *

Позже выяснилось, что в момент установки Selection.setFocus(active_clip);, возникает другой баг - при нажатии на active_clip в некоторых ситуациях после onPress срабатывает сразу onReleaseOutside (т.е. кнопка мыши нажата, но событие отжатия отрабатывает). Компромисс - проверять, является ли этот клип в фокусе, и если нет, то устанавливать активность на него.
if (eval(Selection.getFocus())!=this.__active_clip) Selection.setFocus(this.__active_clip);

вторник, марта 11, 2008

Грабли: styleSheet vs. Input. AS2

Столкнулся с особенностью.
Сначала устанавливаю параметры текстового поля type, html, т.п. Затем устанавливаю/модифицирую текст. После этого устанавливается стиль styleSheet.
После установки стиля, у текстового поля пропадает функция редактирования, хотя type="input".
Пробовал менять последовательность - либо тот же эффект, либо не устанавливается стиль.

понедельник, марта 03, 2008

Грабли при определении значения свойства-объекта по умолчанию. AS 2

В классе определил свойство следующим образом:
private var __states:Object = {normal:false,over:false,down:false};
После чего, если в каком-либо объекте, инстанцированном от этого класса, менялись свойства this.__states.normal, this.__states.over, this.__states.down, изменения отражались на всех остальных объектах, инстанцированных от этого класса.

Грабли еще раз доказывают, что указывать значения по умолчанию прямо в определении свойства, а не в конструкторе - плохая практика.

Указывать значения по умолчанию прямо в определении свойства, допустимо лишь для статических переменных, при использовании их в качестве констант, а так же в особых случаях, когда это действительно необходимо.