You are on page 1of 465

F L A S

100 советов и рекомендаций


профессионала

O'REILLY
С&ППТЕР Шам Бхангал
F L A S H

H A C K S

Sham Bhangal

O ' R E I L L T
Beijing • Cambridge • Farnham • Kbln • Paris • Sebastopol > Taipei • Tokyo
F L A S H .

ТРЮКИ
Шам Бхангал

Москва • Санкт-Петербург • Нижний Новгород • Воронеж


Новосибирск • Ростов-на-Дону • Екатеринбург • Самара
Киев • Харьков • Минск
2005
ББК 32.973-044
УДК 004.92
Б94

Бхангал Ш.
Б94 Flash. Трюки. 100 советов и рекомендаций профессионала — СПб.:
Питер, 2005. — 460 с : ил.
ISBN 5-469-00763-4
Сборник предложенных экспертами советов и трюков, предназначенных для оптимизации
ваших Flash-приложений, создания интересных эффектов, программ на ActionScript, звуковых
и видеоэффектов, и т. п. Трюки ранжированы по степени сложности.
В книге описаны технологии Flash MX, Flash MX 2004 и Flash MX Professional 2004. Для
широкого круга программистов: от любителей до профессионалов.

ББК 2.973-044
УДК 04.92

Права на издание получены по соглашению с O'Reilly.


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

© 2004 O'Reilly Media, Inc.


ISBN 0596006454 (англ.) © Перевод на русский язык, ЗАО Издательский дом «Питер», 2005
ISBN 5-469-00763-4 © Издание на русском языке, оформление, ЗАО Издательский дом «Питер», 2005
Краткое содержание

Предисловие 13

Благодарности 16

Введение 19

От издательства 26

Глава 1 . Визуальные эффекты 27

Глава 2. Цветовые эффекты 62

Глава 3. Рисование и маски 87

Глава 4. Анимация 134

Глава 5. Трехмерная графика и физика 168

Глава 6. Текст 203

Глава 7. Работа со звуком 252


Краткое содержание

Глава 8. Элементы пользовательского

интерфейса 289

Глава 9. Быстродействие и оптимизация 306

Глава 10. ActionScript 338

Глава 1 1 . Интеграция с браузером 386

Глава 12. Безопасность 429


Алфавитный указатель 454
Содержание

Предисловие 13

Благодарности 16
Участники проекта 16
Прочее 17

Введение 19
О чем эта книга? 19
Для кого написана книга 20
Как пользоваться книгой 21
Структура книги 22
Примеры кода 23
ActionScript 1.0 и ActionScript 2.0 24
От издательства 26

Глава 1. Визуальные эффекты 27


Трюк № 1. Имитация переходов на уровне пикселов 28
Трюк № 2. Текстовые эффекты на уровне пикселов 35
Трюк № 3. Имитация зернистости старой пленки . 39
Трюк № 4. Создание SWF на базе анимированного
формата GIF 45
Трюк № 5. Анимация PSD-файлов Photoshop в Flash 49
8 Содержание

Трюк № 6. Генератор деревьев 55


Трюк № 7. Имитация движения дерева 59

Глава 2. Цветовые эффекты 62


Трюк № 8. Применение цветовых эффектов к видео 63
Трюк № 9. Растворение видео на черном и белом фоне 68
Трюк № 10. Пользовательский класс цветового
преобразования 72
Трюк № 11. Создание и упорядочение пользовательских
каталогов цветов 76
Трюк № 12. Использование естественных цветовых схем 79
Трюк № 13. Имитация эффекта сепии 81

Глава 3. Рисование и маски 87


Трюк № 14. Быстрое построение кругов с заливкой 88
Трюк № 15. Синтетическая графика 93
Трюк № 16. Мозаичное заполнение плоскости 96
Трюк № 17. Узорные заливки 99
Трюк № 18. Имитация мозаик Эшера 103
Трюк № 19. Исправление неточности свойства _alpha 107
Трюк № 20. Использование сложных фигур в качестве масок .112
Трюк № 21. Интерференционные картины
и волновые эффекты 117
Трюк № 22. Сглаживание краев на растровых изображениях .119
Трюк № 23. Добавление векторного контура
к растровому изображению 122
Трюк № 24. Исправление ошибки сдвига 125
Трюк № 25. Эффект листания страниц 129
Содержание 9

Глава 4. Анимация 134


Трюк № 26. Плавное сценарное движение 135
Трюк № 27. Синхронизация анимации по времени 138
Трюк № 28. Быстрая и компактная анимация символов 141
Трюк №29. Альтернативные средства построения анимации . 145
Трюк № 30. Принцип «Deja New» 149
Трюк № 31. Как попасть в «Матрицу» 151
Трюк № 32. Анимация персонажа,
сгенерированного компьютером 154
Трюк № 33. Эффекты частиц 161
Трюк № 34. Морфинг сложных фигур 164
Глава 5. Трехмерная графика и физика 168
Трюк № 35. Имитация трехмерной графики 169
Трюк № 36. Панорамные изображения 174
Трюк № 37. Оптимизированный трехмерный плоттер 181
Трюк № 38. Гравитация и трение 186
Трюк № 39. Имитация броска 190
Трюк № 40. Обнаружение множественных столкновений . . . . 193
Трюк № 41. Поворот к заданной точке 198

Глава 6. Текст 203


Трюк №42. Сохранение разборчивости текста 205
Трюк №43. Автоматическое завершение текста 207
Трюк №44. Динамическое построение списка вводимых слов 214
Трюк №45. Перенос сложного форматирования в Flash 218
Трюк №46. Использование HTML и CSS в Flash 225
10 Содержание

Трюк № 47. Всплывающие подсказки 231


Трюк № 48. Текстовые эффекты 237
Трюк № 49. Эффект пишущей машинки 241
Трюк № 50. Текстовые эффекты, контролируемые по времени 243
Трюк № 51. Текстовые эффекты с применением морфинга . . 248

Глава 7. Работа со звуком 252


Трюк № 52. Создание синтезатора речи 253
Трюк № 53. Говорящий аватар 259
Трюк № 54. Синхронизация событийных звуков 263
Трюк № 55. Преобразование монофонического звука
в стереофонический 265
Трюк № 56. Звуковые эффекты в реальном времени 268
Трюк № 57. Быстрое создание звукового сопровождения
для пользовательского интерфейса 270
Трюк № 58. Оптимизация звука 275
Трюк № 59. Служебная информация для синхронизации . . . . 283
Трюк № 60. Пользовательский класс звуковых преобразований 286
Глава 8. Элементы пользовательского
интерфейса 289
Трюк № 61. Интерактивное тестирование 291
Трюк № 62. Правая и средняя кнопки мыши 296
Трюк № 63. Кнопочные клипы 298
Трюк № 64. Полосы прокрутки 302

Глава 9. Быстродействие и оптимизация 306


Трюк № 65. Борьба с разрастанием файлов Flash 308
Трюк № 66. Тестирование загрузки канала связи
для сложных сайтов 310
Трюк № 67. Маскировка последствий снижения качества . . . 313
Трюк № 68. Оптимизация графики , 317
Содержание 11

Трюк № 69. Хронометраж 320


Трюк № 70. Динамическая настройка скорости анимации . . . 322
Трюк № 71. Смета быстродействия 327
Трюк № 72. Использование растровой графики
вместо векторной 332
Трюк № 73. Оптимизация загрузки и использования
компонентов 335

Глава 10. ActionScript 338


Трюк № 74. Внешние редакторы сценариев 342
Трюк № 75. О пользе жесткой типизации 347
Трюк № 76. Кодовые подсказки 350
Трюк № 77. Клонирование объекта 352
Трюк № 78. Тайм-аут по бездействию пользователя 357
Трюк № 79. Быстрый поиск в ActionScript . . . 360
Трюк № 80. Блокировка слоя actions 363
Трюк № 81. Отладка и трассировка 365
Трюк № 82. Недокументированные возможности ActionScript . 368
Трюк № 83. «Черный ход» ASnativeQ 372
Трюк № 84. Нетривиальное применение операторов 373
Трюк № 85. Импортирование ASC-файлов как формата XML . 379

Глава 11. Интеграция с браузером 386


Трюк № 86. Решение проблем совместимости 388
Трюк № 87. Универсальный анализатор поддержки Flash . . . . 391
Трюк № 88. Тестирование с разными версиями Flash 396
Трюк № 89. Настройка конфигурации по умолчанию 399
Трюк № 90. Выравнивание SWF по центру
без изменения масштаба 402
Трюк № 91. Выравнивание по центру с применением CSS . . . 403
Трюк № 92. Динамическое масштабирование контента 410
12 Содержание

Трюк № 93. Создание ссылок HTML в Flash 414


Трюк № 94. Интеграция Flash с кнопкой возврата 416
Трюк № 95. Передача фокуса клавиатуры SWF 422
Трюк № 96. Клавиши ускоренного вызова 423

Глава 12. Безопасность 429


Трюк № 97. Восстановление контента по SWF 435
Трюк № 98. Защита и шифрование файлов Flash 441
Трюк № 99. Привязка к сайту 444
Трюк № 100. Просмотр откомпилированного
кода ActionScript 447

Алфавитный указатель 454


Предисловие
Лет семь назад я начал работать с Macromedia Flash - с версией 2.0, если уж
быть точным. Заказчиком моего первого Flash-проекта была фирма Levi's, все-
мирно известный производитель одежды. Она пожелала создать ставший прит-
чей во языцех «классный веб-сайт». Корпорации, как и живые существа, не хо-
тят умирать; фирма Levi's тоже желала обрести новые жизненные силы за счет
привлечения нового поколения покупателей (то есть подростков). Но, по мне-
нию Levi's, молодежи не нравятся сайты производителей одежды; для них такой
сайт - это всего лишь скучный каталог товаров с кнопкой Buy. Решение? Пре-
вратить новый сайт Levi's в интерактивный комикс, в котором истории отдель-
ных персонажей приводят посетителя к товарам Levi's. Остается наполнить ко-
микс действием, романтикой, драматизмом и интригами... молодежь это любит.
На первом совещании по проекту арт-директор представил концепцию аними-
рованного веб-сайта, а мы, специалисты по HTML и веб-дизайнеры, содрогну-
лись от одной мысли о попытках ее реализации. Предполагалось, что на сайте -
постарайтесь не упасть со стула! - будут озвучиваться голоса персонажей!
(Вспомните: это был 1997 год; анимация и звуковое сопровождение на веб-сай-
тах считались делом почти неслыханным.) В своем первом техническом описа-
нии мы предложили использовать анимированную графику в формате GIF, зву-
ковые файлы WAV и JavaScript rollovers. Естественно, сайт получился бы не
таким эффектным, как описывал арт-директор, но мы уже привыкли быть «коз-
лами отпущения» для заказчиков. Именно нам пришлось бы сообщить заказ-
чику неприятные новости: браузеры не подходят для просмотра мультфильмов.
Описание сайта, данное арт-директором, было сугубо концептуальным; оно
должно было вдохновить нас на дальнейшую работу, а не восприниматься
буквально.
Но арт-директор своими глазами видел анимацию в Веб. Он спросил, как были
сделаны мультфильмы на веб-сайте Диснея. Мы рассказали о Macromedia Flash.
Но для него название программы и технические подробности были делом второ-
степенным. Анимацию для сайта Levi's нужно было сделать любой ценой. Итак,
мы построили сайт Levi's на базе Flash (http://moock.org/webdesign/portfolio/levisite).
Вскоре после завершения работы над сайтом Levi's в отрасли веб-дизайна началось
массовое сумасшествие по поводу сайтов Gabocorp и EYE4U, двух веб-агентств
с анимированными Flash-интерфейсами. По сегодняшним меркам эти два сайта
выглядят до смешного простыми и наивными (убедитесь сами - в апреле 2004 го-
да исходный сайт EYE4U все еще был доступен по адресу http://www.eye4u.com).
14 Предисловие

Сайты Gabocorp и EYE4U были реализованы практически без программирова-


ния, отличались излишне крикливым дизайном; в них использовались движу-
щиеся фигуры, а по экрану летали разноцветные шарики. Что же сделало их
столь популярными?
Как и сайт Levi's, они раскрыли большие потенциальные возможности системы.
Технология Flash как дополнение к браузеру стала одним из самых многообеща-
ющих продуктов последнего десятилетия. С первых дней своего существования
она вдохнула жизнь в несколько однообразный браузер. Flash позволяет людям
с творческим складом мышления исследовать потенциал Всемирной паутины
как анимационной и игровой платформы, ОС-подобной среды для работы с уда-
ленными приложениями, галереи электронного искусства, видеочата, многополь-
зовательской среды совместной работы, технологии проведения удаленных кон-
ференций, проигрывателя для музыки в формате МРЗ - да в общем-то всего,
что может прийти в голову. Определив себе место в этой нише, компания
Macromedia несколько лет назад выбрала своим рекламным лозунгом фразу «Чем
может стать Веб».
Вполне естественно, технология Flash отличается исключительной гибкостью
и становится настоящим раем для творчески мыслящих энтузиастов. Вероятно,
именно «хакерская» сущность Flash стала одним из ключевых факторов успеха.
В данном случае речь идет о классическом понимании хакерства как творческо-
го исследования, использующего любые доступные (причем, порой неэтичные)
средства для получения желаемого результата. Технология Flash прошла путь
от простой анимационной «развлекалки» до всеобъемлющего «усовершенство-
вания Интернета», каковым она стала сегодня, в основном благодаря тому, что
ее создатели принимали во внимание. всевозможные хакерские трюки, приду-
манные сообществом разработчиков.
Я помню, как люди использовали Flash 3 для создания игр типа Whack-a-Mole1,
Leo's Great Day (http://www.pepworks.com/leoenglish.swf) и даже топорных прото-
типов Pacman и шахмат. Обратите внимание: все это без единой строки про-
граммного кода. В Flash 3 еще не было сценарного языка! В ответ на растущую
потребность в интерактивности фирма Macromedia включила в Flash 4 очень
простую версию ActionScript. Тогда еще никто не знал, что этот язык будет пи-
тать целое направление компьютерной графики, которая в течение нескольких
лет будет влиять на дизайн печатных изданий, телевизионных передач и филь-
мов. Через несколько месяцев после выхода Flash 4 такие сайты, как Mono-craft
(http://www.yugop.com), PrayStation (http://www.praystation.com), Levitated Design &
Code (http://www.levitated.net) и Presstube (http://www.presstube.com), прослави-
лись своими творческими изысканиями в области аудиовизуального представле-
ния информации в реальном времени (а проще говоря - хакерскими трюками!)
Мы используем Flash для решения задач, которые трудно или невозможно ре-
шить другими средствами. На базе одного лишь HTML трудно создать анима-
ционную графику, но благодаря Flash анимация в Веб получила широкое рас-
пространение. В традиционных приложениях для настольных систем трудно

1
Весьма интеллектуальное развлечение — игрок лупит молотком кротов, неожиданно выскакивающих
из пор. — Примеч. перев.
Предисловие 15

организовать выразительный, нестандартный пользовательский интерфейс, но


«фирменные» приложения на базе Flash сегодня работают на тысячах веб-сай-
тов. На момент написания предисловия я завершаю работу над веб-сайтом, ко-
торый позволяет наблюдать за тем, как другие подключенные пользователи вза-
имодействуют с интерфейсом сайта (http://moock.org/unity/clients/uPresence). Тем
временем Маркое Уэскемп (Marcos Wescamp) работает над версией 2 своего
приложения (http://www.marumushi.com/apps/remotedriver2), которое позволяет
любому желающему управлять реальной машиной дистанционно через веб-ин-
терфейс на базе Flash. Трудно представить, чтобы подобные приложения были
написаны с применением чего-то еще, кроме Flash.
Итак, Flash - настоящий рай для профессионала. Эта технология позволяет
экспериментировать и предоставляет свободу для выражения идей. При этом
для достижения желаемой цели иногда приходится прибегать к хитроумным
трюкам. В течение долгого времени трюки и фокусы Flash распространялись
в сетевом сообществе разработчиков. Многие из них (как старые, так и новые)
включены в эту книгу, причем качество и стиль изложения соответствуют стандар-
там O'Reilly.
Я считаю, что эта книга не только принесет практическую пользу, но и станет
испытанием для читателя.
Практическая польза: применяйте все, что вы найдете на ее страницах, в тех
проектах, над которыми работаете. Здесь можно найти массу замечательных све-
дений, которые пригодятся почти в любом реальном проекте. Вам пригодится
богатый практический опыт Шама Бхангала и четкость объяснений, которую,
как я искренне считаю, может обеспечить только Брюс Эпстейн (редактор книги).
Испытание: помните, что главные инструменты в вашем арсенале - это изобре-
тательность и эксперименты. Прежде чем были написаны первые книги по Flash,
прежде чем были выработаны стандартные трюки и методики, было видение
конечной цели и умное, упорное, терпеливое стремление во чтобы то ни стало
добиться ее.
Колин Мук
Апрель 2004 г.
Благодарности

Шам Бхангал сделал первые шаги к веб-дизайну в 1991 году, когда занялся про-
ектированием экранов для выдачи информации в компьютерных системах с осо-
быми требованиями к обеспечению безопасности (вроде тех, что используются
на диспетчерских пультах атомных электростанций). Вскоре он открыл для себя
более традиционные средства разработки интерфейсов, анимации и мультиме-
диа, такие как 3D Studio Max, Photoshop и Flash. Он пишет книги о них с начала
нового столетия.

Участники проекта
Ниже перечислены люди, которые делились идеями, участвовали в написании
книги или вдохновляли ее автора.
• Энтони «Ant» Идеи (a.k.a. arseiam) (Anthony Eden) работал на многих се-
рьезных заказчиков, в том числе Microsoft, Disney и Adobe. В свободное
время увлекается созданием причудливых и странных эффектов на Action-
Script. С примерами его работ можно ознакомиться на сайте http://
www.arseiam.com.
• Зе Фернандо (Zeh Fernando) работал с Macromedia Flash, начиная с версии
2. В настоящее время он трудится в бразильской дизайн-студии Grafikonstruct
(http://www.grafikonstruct.com.br), занимается созданием веб-сайтов на базе
Flash и придумывает новые способы заниматься тем же самым в свободное
время.
• Эдвин «XemonerdX» Хейджмен (Edwin Heijmen) - профессиональный Flash-раз-
работчик из Нидерландов; также является модератором на нескольких фору-
мах, посвященных ActionScript. Увлекается объединением математики с программи-
рованием, с результатами можно ознакомиться на сайте http://www.poeticterror.com.
Кроме ActionScript, также программирует на PHP, ColdFusion, Python и всех ма-
лопонятных языках, которые попадаются под руку. Другие увлечения - его заме-
чательная подруга, андеграундный металкор, программы с открытым кодом,
русская литература и друзья.
• Адам Филипс (Adam Phillips), обладатель призов за анимацию в сериях Flash-
роликов biteycastle.com, hitchHiker и Brackenwood. Победитель в номинации
Flash Forward Cartoon на NYC 2003, финалист SF 2004. После более 10 лет
работы в области традиционной 2О-анимации для Walt Disney Company Адам
продолжает создавать свои собственные короткие фильмы. Тринадцать из них
можно найти на сайте http://www.biteycastle.com.
Прочее 17

• Грант Скиннер (Grant Skinner) (http://www.gskinner.com), Flash-разработчик


международного уровня, успешно соединяет в своих работах программный
код, проектирование интерфейса, эргономичность, маркетинг и бизнес-логи-
ку. Работает с лучшими агентствами и прогрессивными корпоративными кли-
ентами над концептуализацией, архитектурой и реализацией Flash-приложе-
ний. Грант является обладателем множествам призов Flash, его работа была
представлена на выставке SIGGRAPH Web Expo в номинации «Лучшая веб-
графика 2003 года». Регулярно участвует во многих конференциях и является
автором ряда публикаций.
• Stickman попросил меня сохранить в тайне его настоящее имя, чтобы не созда-
вать себе лишних проблем, но я могу по секрету сообщить, что он занимается
веб-дизайном большого сайта в Великобритании, а также является независи-
мым писателем. С его виртуальной личностью можно пообщаться на сайте
http://www.the-stickman.com.

Прочее
Работ над книгой продолжалась довольно долго. Благодарю всех, кто был рядом
со мной все это время.
Разумеется, прежде всего я благодарю фирму Macromedia за создание Flash и уча-
стников проекта, поделившихся своими идеями.
Спасибо Колину Муку (Colin Moock) (http://www.moock.org) за его великолеп-
ные книги, техническую помощь и за введение к книге.
Спасибо группе рецензентов за замечания и исправления. В их числе: Марк Гар-
ретт (Mark Garrett), Дэвид Хамфрис (David Humphreys), Шафик Казун (Chafic
Kazoun), Марк Майхер (Mark Majcher), Сэм Нефф (Sam Neff), Дэррон Шалл
(Darron Schall), Джесси Уорден (Jesse Warden) и Эдуардо Зублер (Edoardo Zubler).
Спасибо всем сотрудникам O'Reilly, в том числе Тиму О'Рейли (Tim O'Reilly) за
первоначальные комментарии и Раэлу Дорнфесту (Rael Dornfest) за идею разде-
ления материала на «трюки». Я благодарен Брайану Сойеру (Brian Sawyer) и Клэр
Клутье (Claire Cloutier) за помощь в работе, Робу Романо (Rob Romano) за обра-
ботку многочисленных иллюстраций и Норме Эмори (Norma Emory) за подроб-
ную корректуру. Отдельное спасибо Брюсу Эпстейну (Bruce Epstein) за желез-
ную выдержку, за сверхъестественное искусство редактуры и за то, что у него
находилось время для дружеской беседы. Я также благодарен своему агенту Кэ-
рол Макклендон (Carole McClendon) из Waterside Production.
Спасибо всем разработчикам сообщества Flash, которые помогли мне советом по
работе со сторонним инструментарием: Игорю Когану (Igor Kogan), Дэйву Хей-
дену (Dave Hayden), Дэмьену Мортену (Damian Morten) (Flasm) и Алексу Блуму
(Alex Blum) (Flash Plugin Switcher). Благодарю Алессандро Капоццо (Alessandro
Capozzo) за разрешение воспроизвести некоторые изображения, созданные в Proces-
sing. Я также благодарен многочисленным разработчикам, проектировщикам и меч-
тателям, чья работа прямо или косвенно вдохновляла меня при работе над раз-
ными частями книги. Среди них стоит упомянуть Джоша Дэвиса (Josh Davis)
18 Благодарности

(http://joshdavis.com), Брэндена Холла (Branden Hall) (http://waxpraxis.org), Эрика


Нацке (Erik Natzke) (http://www.natzke.com), Джеймса Патерсона (James Paterson)
(http://www.presstube.com), Эмита Питару (Amit Pitaru) (http://www.pitaru.com)
и Хардино (Hardino) (http://www.hardino.com).
Напоследок хочу поблагодарить Брайана Молко и компанию (http://www.brian-
molko.com) за первые четыре строки «Pure Morning». Я продолжал улыбаться
весь день, пока писал эти строки. Ты настоящий гений.
Введение

Предок Macromedia Flash изначально создавался как базовый компонент план-


шетного компьютера - бесклавиатурной машины, в которой для ввода использо-
вался стилус (перо). Такая система была гораздо компактнее традиционных кла-
виатурных машин и идеально подходила для портативных устройств. В ней был
задействован механизм векторной графики, гораздо лучше подходивший для
перьевого ввода, чем традиционная растровая графика.
Идея не прижилась, но вскоре открылась новая область для ее применения - Веб.
Программа вывода векторной графики превратилась в программу FutureSplash,
изданную в 1995 году как специализированный инструмент векторной веб-гра-
фики. Права на FutureSplash вскоре были приобретены компанией Macromedia.
В 1996 году была издана первая версия программы с новым именем Flash.
В конце 2003 года компания Macromedia издала Flash MX 2004 (а также Flash
MX Professional 2004) с соответствующим модулем браузера Flash Player 7 и эле-
ментом ActiveX. За последние годы технология Fash обрела ряд новых важных
возможностей, включая мультимедийные средства (звуки, графика, видео) и пол-
ноценный язык сценариев (ActionScript) для создания нелинейных анимаций
и обработки на стороне клиента, а также взаимодействия с удаленными данными
и серверными сценариями.
Сейчас Flash представляет собой стандартную мультимедийную платформу в Веб.
Flash Player (модуль браузера для воспроизведения файлов Flash в формате swf)
установлен практически на любом компьютере, a Flash теперь позволяет созда-
вать приложения для настольных систем. Веб-дизайн постепенно отходит от тради-
ционной технологии HTML и отдает предпочтение интерактивности и мультиме-
дийным возможностям Flash. В свою очередь, Macromedia продолжает расширять
платформу Flash такими продуктами, как Macromedia Central (интерактивная
среда для поиска и воспроизведения Flash-приложений), Flash Communication
Server MX (видео- и аудиосервер реального времени) и Flash Remoting (усо-
вершенствованное удаленное подключение к веб-службам и серверным при-
ложениям).

0 чем эта книга?


В этой книге вы найдете новые идеи веб-дизайна сайтов, использующих Flash
и ActionScript.
Авторские разработки на базе Flash имеют сугубо творческий характер как в об-
ласти дизайна, так и в области программирования и постоянно расширяют наши
20 Введение

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


Хотя мультимедийное сценарное программирование стало более структуриро-
ванным и формализованным, в тех случаях, когда стандартные пути заводят в ту-
пик, по-прежнему остается множество возможностей для поиска нетрадицион-
ных, обходных путей.
Когда я впервые открыл Flash-приложение и начал читать официальную доку-
ментацию, мне пришлось довольно долго разбираться в том, как же на самом
деле следует использовать Flash. Судя по сообщениям, которые я получал с тех
пор, это весьма распространенная проблема.
Итак, Flash - та область, в которой эксперименты, трюки на грани возможного
и всевозможные хитроумные фокусы являются частью нормального рабочего про-
цесса, поскольку вашей целью обычно является создание чего-то нового и не-
обычного. Чтение документации Macromedia Flash позволит дойти лишь до опре-
деленного момента, после чего вам придется искать новые трюки и фокусы для
преодоления ограничений Flash.
Таким образом, эта книга должна не только научить вас нескольким интересным
трюкам, но и представить ряд неочевидных приемов и идей, благодаря которым
ваш Flash-дизайн станет более оригинальным, а приложения - более эффектив-
ными.
Конечно, это также означает, что многие из представленных приемов не будут
использоваться в первоначальном виде, а послужат отправной точкой для даль-
нейших исследований и разработок. Не бойтесь экспериментировать - на этом
принципе живет все сообщество Flash. В книге немало позаимствовано из бога-
тых традиций сообщества Flash, в ней также представлено множество оригиналь-
ных идей для вашего обучения, развлечения и вдохновения.

Для кого написана книга


Давайте признаем очевидный факт. Издательство O'Reilly лучше известно свои-
ми справочниками, нежели «трюковой» серией.
Как мне кажется, эта книга в корне отличается от них, потому что служит иной
цели, хотя круг ее предполагаемых читателей частично пересекается с аудитори-
ей, пользующейся справочниками. Серьезные, традиционные книги по програм-
мированию содержат хорошо структурированный код и соблюдают все класси-
ческие каноны, эта же книга полна исследовательского духа и причуд. Справочники
рассчитаны на опытных программистов, эта книга написана для юных сердцем
искателей приключений. Новичку в области Flash она покажется такой же маня-
щей, как аромат теплого яблочного пирога. Тем, кто уже успел поработать с Flash,
а возможно - начал находить это занятие немного скучным, она напомнит, поче-
му он когда-то влюбился во Flash. Наконец, программист-ветеран найдет в книге
много полезных рекомендаций из области программирования и оптимизации, а так-
же советов по разработке приложений.
Откровенно говоря, тем, кто вообще не работал с Flash, многие советы могут
показаться сложными, но другие будут вполне Понятны. Каждый найдет здесь
что-нибудь полезное для себя. В начальных главах я поясняю, как выполняются
Как пользоваться книгой 21

некоторые элементарные операции - такие, как создание нового слоя (команда


Insert • Timeline • Layer) и присоединение программного кода к фрейму (выделите
фрейм на панели Timeline и откройте панель Actions клавишей F9 или командой
Window • Development Panels • Actions). Большинство наших сценариев будет раз-
мещаться на специальном слое actions (трюк 80), но некоторые сценарии должны
храниться во внешних файлах .as (трюк 10).
Поскольку книга в целом предназначена для читателей, обладающих опытом ра-
боты с Flash, новичкам стоит выбрать один из многочисленных учебников, опуб-
ликованных - страшно сказать! - другими издательствами. Если у вас еще нет
инструментария Flash, загрузите пробную версию с сайта Macromedia (http://
www.macromedia.com/cfusion/tdrc/index.cfm?product=flash) и разберите учебные
примеры, дающие представление об основных принципах работы с продуктом.
Впрочем, многие трюки, приведенные в книге, будут понятны даже тем, кто ни
разу в жизни не сталкивался с Flash. Конечно, я надеюсь, что книга вдохновит
непосвященных, а посвященные смогут взглянуть на Flash с новой точки зрения.
Если вы принадлежите к кругу серьезных разработчиков или классических про-
граммистов, осваивающих Flash, будьте внимательны. В книге не говорится ни
о лучших методах организации работы, ни об объектно-ориентированном про-
граммировании, ни о разработке RIA (Rich Internet Application). Далее если вы
заранее предубеждены против Flash, многочисленные трюки из области анима-
ции и компьютерной графики могут навсегда перевести вас в стан поклонников
Flash; вам будет стыдно смотреть в глаза бывшим коллегам.
В книге представлен лишь небольшой уголок вселенной Flash - собственно, это
мой личный уголок (хотя и созданный с помощью друзей и помощников). Если
пошарить в нем, вы найдете не только симпатичные звуковые и визуальные эф-
фекты, но и множество примеров ActionScript. Попутно вы многому научитесь
(возможно, даже тому, о чем раньше не подозревали).
Вселенная Flash необъятна и разнообразна, и эта книга не пытается дать всю
необходимую информацию всем сразу. Но практически каждый разработчик, будь
то опытный Flash-мастер, новичок в сценарных языках или ветеран-программист,
найдет здесь массу информации к размышлению. Если вы когда-нибудь были
ребенком, если вы когда-нибудь влюблялись - книга напомнит вам эти волную-
щие моменты. По-моему, это просто замечательно.
Так что читайте все книги по Flash и ActionScript, которые окажутся у вас под
рукой, но обязательно оставьте место на полке или столе и для этой книги.

Как пользоваться книгой


Прочитав книгу от корки до корки, вы обнаружите массу интересной техниче-
ской информации в самых неожиданных местах. Если судить о трюках только по
их названиям, вы рискуете многое упустить. Тем, кто любит выбрать интересный
раздел по оглавлению и взяться прямо за него, определенно стоит пролистать
остальные разделы и увидеть, что вы могли упустить. Обязательно читайте ввод-
ные разделы глав, будь вы новичок или эксперт в этой теме; почти в каждой
строке вы наверняка найдете что-нибудь полезное и интересное.
22 Введение

В первых четырех главах рассматриваются основные концепции, определяющие


впечатления от сайта, - графика, анимация и эффекты. Главы 5, 6, 7 и 8 посвя-
щены выразительным средствам и содержанию - обращайтесь к ним за творчески-
ми идеями и информацией, относящимся к трехмерным эффектам, тексту, звуку
и элементам пользовательского интерфейса. В главах 9, 10, 11 и 12 рассматрива-
ются специальные темы: интеграция с браузером, оптимизация и безопасность
(а также ActionScript в умеренных дозах). В них можно найти ответы на вопросы
«Как выровнять Flash Stage по центру в браузере?» или «Дизайн моего сайта
украли! Можно ли сделать так, чтобы это не повторилось?»

Структура книги
Flash - универсальный инструмент творческой разработки, состоящий из целого
ряда аспектов, которые обычно приходится комбинировать для получения жела-
емого эффекта или результата, поэтому названия глав и краткие обзоры стоит
воспринимать в широком смысле. Например, анимация в той или иной степени виде
присутствует во многих главах, а большинство трюков содержит код ActionScript,
позволяющий сделать много интересного. Тем не менее, 100 трюков пришлось
организовать в более или менее разумную структуру. Так в книге появились гла-
вы, посвященные графике, звуку, оптимизации и другим темам.
• Глава 1. Визуальные эффекты. В этой главе показано, как сделать графичес-
кое оформление сайта более интересным за счет добавления впечатляющих
эффектов и переходов.
• Глава 2. Цветовые эффекты. Грамотный дизайнер использует не только ани-
мацию, но и цвет. Его часто недооценивают, но, как будет видно из этой главы,
при помощи цвета можно изменить общий настрой или реализовать такие
эффекты, как растворение и вытеснение.
• Глава 3. Рисование и маски. Объединение средств графической анимации
Flash с ActionScript существенно расширяет творческие горизонты. В этой
главе представлены графические эффекты, создаваемые как на стадии постро-
ения, так и на стадии использования сайта. Также объясняется принцип рабо-
ты масок, часто используемых во многих операциях с графикой.
• Глава 4. Анимация. Трюки этой главы демонстрируют пути ускоренного созда-
ния анимационных последовательностей, а также способы оптимизации ани-
мации, созданной под контролем ActionScript.
• Глава 5. Трехмерная графика и физика. В этой главе представлен ряд трю-
ков, позволяющих обойти ограничения Flash по быстродействию и включить
в ваш репертуар имитацию физических процессов и трехмерных эффектов.
• Глава 6. Текст. Глава посвящена способам хранения, отображения и обработ-
ки текста, а также применения к нему анимационных эффектов.
• Глава 7. Работа со звуком. Без звукового сопровождения даже тщательно
проработанный контент выглядит уныло и обыденно. В этой главе показано,
как создать и изменить звуковые эффекты и музыку.
Примеры кода 23

• Глава 8. Элементы пользовательского интерфейса. Трюки, относящиеся к со-


ставляющим пользовательского интерфейса (кнопкам, полосам прокрутки,
вводу с помощью мыши и т. д.).
• Глава 9. Быстродействие и оптимизация. Глава повествует о том, как умень-
шить размер файлов и обеспечить быструю работу приложения.
• Глава 10. ActionScript. Хотя практически каждый трюк в книге содержит
некоторую долю кода ActionScript, в этой главе показано, как извлечь из
ActionScript максимум пользы (включая применение недокументированных
возможностей).
• Глава 11. Интеграция с браузером. Глава показывает, как обеспечить макси-
мальную совместимость с браузером, чтобы как можно больше людей могли
получить доступ к вашему контенту.
• Глава 12. Безопасность. Данная глава объясняет, как защитить контент и ди-
зайн, несмотря на общую незащищенность формата SWF.

Примеры кода
Примеры текстов программ вы сможете найти на сайте O'Reilly (http://
www.oreilly.com). Для этого найдите ссылку на книгу (например, по названию
Flash Hacks или по оригинальному ISBN 0-596-00645-4) и следуйте гипер-
ссылкам на соответствующей книге веб-странице сервера.

Что делать, если пример не работает?


Чаще всего примеры не работают из-за того, что файл Flash не был настроен
в соответствии с инструкциями (если, конечно, вы не ошиблись при вводе кода).
Перечитайте близлежащий текст и тщательно повторите все предписанные действия.
Не забудьте разместить код там, где он должен находиться (обычно это первый
фрейм слоя actions или внешний файл .as). Также обязательно укажите версию ком-
пилятора ActionScript 2.0 в окне File • Publish Settings • Flash • ActionScript Version.
Любой фрагмент кода, работающий с анимационными клипами, кнопками или
текстовыми полями через ActionScript, нормально функционирует только в слу-
чае правильного задания имени экземпляра данного объекта. Чтобы задать имя
экземпляра для анимационного клипа, кнопки или текстового поля, выделите его
на сцене и введите имя экземпляра в левой части панели свойств (Window •
Properties), на месте заполнителя < Instance Name>.
Еще один частый источник проблем - отсутствие идентификатора компоновки
символа, необходимого для обращения к библиотечным символам из ActionScript.
Чтобы задать идентификатор компоновки для символа, установите флажки Export
for ActionScript и Export in First Frame в диалоговом окне Symbol Properties или Linkage
Properties; чтобы вызвать эти окна, выберите символ в библиотеке (Window • Library)
и выберите команду Properties или Linkage в контекстном меню панели Library.
Затем введите идентификатор в поле Identifier (это поле становится активным
лишь после установки флажка Export for ActionScript).
24 . Введение

Внимательно прочитайте инструкцию и убедитесь в том, что вы не перепутали


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

ActionScript 1.0 и ActionScript 2.0


Многие трюки, представленные в книге, написаны на языке ActionScript 2.0, для
которого необходима среда Flash MX 2004 или Flash MX Professional 2004. Чита-
тель может выбрать любую из этих сред (их сравнение приведено по адресу http:/
/www.macromedia.com/software/flash/productinfo/features/comparison), поскольку
в книге не используются специфические возможности, присущие только профес-
сиональному изданию продукта. Чтобы примеры успешно компилировались, не
забудьте выбрать версию ActionScript 2.0 в окне File • Publish Settings • Flash. Все
примеры были протестированы в Flash Player 7.
Там, где это особо оговорено, определения классов ActionScript 2.0 должны раз-
мещаться во внешних .as-файлах. Например, класс Transfoun из трюка 10 должен
размещаться во внешнем текстовом файле с именем Transform.as (точный регистр
символов в имени и расширение .as обязательны). Чтобы создать и отредактировать
файл в Flash MX Professional 2004, выполните команду File • New • ActionScript
File. В Flash MX 2003 для этого потребуется внешний редактор (трюк 74).
Нам не удастся привести на страницах книги полный курс объектно-ориентиро-
ванного программирования (ООП) и ActionScript 2.0, хотя некоторые пояснения
будут встречаться в тексте.
Большинство примеров экспортируется в формат Flash Player 6 из Flash MX
2004 (в стандартном или профессиональном издании), для чего в окне File • Publish
Settings • Flash следует выбрать формат Flash Player 6.
Тем не менее, при экспортировании в формат Flash Player 6 перестанут работать
новые методы Flash MX 2004 и Flash Player 7. Например, все вызовы метода
MovieClip.getNextHighestDepth() в примерах придется заменить вызовом метода для
конкретной глубины, иначе в Flash Player 6 этот пример работать не будет.
Предыдущая версия среды разработки Flash, Flash MX, не поддерживала Action
Script 2.0. Тем не менее, многие трюки и примеры программ будут нормально ра-
ботать в Flash MX. Если вы работаете с Flash MX и хотите опробовать какой-нибудь
трюк с использованием ActionScript 2.0, в большинстве случаев перевод приме-
ров на ActionScript 1.0 сводится к простому удалению типов данных ActionScript 2.0,
как показано далее.
Для примера возьмем фрагмент кода ActionScript 2.0 с использованием типов
данных (выделены жирным шрифтом):
// ActionScript 2.0 с типами данных
// Необходима среда Flash MX 2004
// Пример настроен для компиляции ActionScript 2.0
ActionScript 1.0 и ActionScript 2.0 25

function myFunction(x:Number):Number {
var у:Number = 2 * x:
return y;
}
var myString:String = "hello";
var myClip:MovieClip = this.createEmptyMoveClipC'myClip".0);
var double:Number = myFunction(2);
trace(double);
А вот как выглядит эквивалентная версия ActionScript 1.0 без типов данных:
// ActionScript 1.0 (без типов)
// Пример работает в среде Flash MX (и выше)
function myFunction(x) {
var у = 2 * х;
return у;
}
var myString = "hello":
var myClip = this.createEmptyMoveClipC'nyClip".0):
var double = myFunction(2):
trace(double);
В книге часто используется код временной диаграммы, поддерживаемый как
в ActionScript 1.0, так и в ActionScript 2.0 (хотя его применение не всегда явля-
ется оптимальным). Такое решение объясняется тем, что многие примеры плохо
преобразуются к схеме с пользовательскими классами ActionScript 2.0. Кроме
того, это упрощает анализ и реализацию примеров как в Flash MX, так и в Flash
MX 2004.
Некоторые объектно-ориентированные примеры на базе классов, написанные
на ActionScript 2.0, не компилируются в ActionScript 1.0 и требуют Flash MX
2004 (в стандартном или профессиональном издании). Если вы продолжаете
использовать ActionScript 1.0 в Flash MX 2004, подумайте, не пора ли расширить
свой кругозор. Дополнительная информация и перечень ресурсов, посвящен-
ных различиям между Flash Player 6 и Flash Player 7, приводится в главах
10 и 12.

Регистр символов
Многие разработчики до сих пор путаются в правилах регистра символов в Flash
MX 2004. Прежде всего следует понять, что речь идет о двух разных вещах: ре-
гистре символов на стадии компиляции и регистре символов на стадии выпол-
нения. Компилятор ActionScript 1.0 игнорирует регистр символов, тогда как
компилятор ActionScript 2.0 его учитывает. Тем не менее, учет регистра символов
на стадии выполнения определяется версией формата SWF, в который экспор-
тируются данные, и не зависит ни от версии ActionScript, использованной на ста-
дии компиляции, ни от версии модуля Flash Player, в которой файл воспроиз-
водится.
Сводка правил учета регистра приведена в табл. В.1, позаимствованной из отлич-
ной книги Колина Мука «Essential ActionScript 2.0» (с разрешения автора).
26 Введение

Таблица В.1. Учет регистра символов в зависимости от языка, формата файла


и версии Flash Player
Ролик откомпилирован ...воспроизводится ...воспроизводится
в ActionScript 1.0 в Flash Player 6 в Flash Player 7
или 2.0 и...
1
Файл .swf формата Без учета регистра Без учета регистра
Flash Player 6
Файл .swf формата Не поддерживается2 С учетом регистра
Flash Player 7

1
В идентификаторах (то есть именах переменных и свойств), именах функций, метках кадров и эк-
спортных идентификаторах символических имен в файлах .swf формата Flash Player 7 регистр сим-
волов не учитывается. С другой стороны, в зарезервированных словах вроде if регистр символов учи-
2
тывается даже в Flash Player 6.
Flash Player 6 не может воспроизводить файлы .swf формата Flash Player 7.

От издательства
Ваши замечания, предложения, вопросы отправляйте по адресу электронной почты
comp@piter.com (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства http://www.piter.com вы найдете подробную информа-
цию о наших книгах.
Г Л Д В Д 1

Визуальные эффекты
Трюки № 1-7
Предполагается, что читатель уже знаком с основными концепциями примене-
ния Flash для создания визуальных эффектов и анимации на временной диа-
грамме. Но даже если ваш опыт работы с Flash еще недостаточен, описанные
в настоящей главе приемы все равно покажутся вам интересными. После того
как вы освоите азы Flash (по учебнику или по электронной документации), по-
пробуйте вернуться к тем трюкам, которые вас особенно заинтересовали. Снача-
ла я хотел открыть книгу советами по оптимизации, безопасности и другим те-
мам того же плана. Но затем я решил отложить эти темы до более позднего
времени в надежде, что трюки этой главы заинтересуют читателя и расширят
его кругозор, не нарушая принципов хакерской этики: «Сначала показывать са-
мое интересное».
Итак, в настоящей главе собраны трюки, показывающие, как реализовать эф-
фекты, которых вы либо вообще не видели, либо видели, но не знали, как их
воспроизвести. Они, как и весь остальной материал книги, научат вас чему-то
новому, а в конечном счете и вдохновят - причем не так, как нас вдохновляют
бессмертные произведения искусства, а, скорее, стимулируют к дальнейшей ра-
боте. Надеюсь, что вам захочется опробовать их в деле и создать что-нибудь
похожее самостоятельно.
Трюки этой главы были объединены из-за того, что все они имеют отношение
к визуальным эффектам. В дальнейших главах будут описаны визуальные эф-
фекты, основанные на переходах и колоризации, трехмерности, применении ма-
сок и использовании API графического вывода. В данной главе рассматривают-
ся пиксельные эффекты, преобразования анимированных изображений GIF
и файлов Photoshop в файлы Flash .fla и .swf (исходные форматы документиро-
вания и распространения, используемые Flash). Глава завершается двумя трю-
ками, в которых мы сгенерируем дерево и заставим его качаться на ветру.
Хотя маски интенсивнее всего используются в главе 3, из-за своей исключитель-
но важной роли в Flash (см. трюк 1) они также неоднократно встречаются в дру-
гих главах. По этой причине я привожу краткое введение для читателей, не зна-
комых с масками.
Анимации Flash создаются посредством наложения одного или нескольких сло-
ев (аналогичных слоям Photoshop и других графических программ). На панели
28 Глава 1. Визуальные эффекты

Timeline расположена главная временная диаграмма, предназначенная для упо-


рядочения слоев и отображения их содержимого с течением времени. Маски
традиционно использовались для создания визуальных эффектов (например,
имитации луча прожектора), при которых один слой просматривается сквозь
«дыру» в слое маски. Таким образом, маскирующий слой определяет видимую
область нижележащего (маскируемого) слоя; остальные области считаются
«замаскированными», то есть невидимыми. Чтобы создать маскирующий слой
в инструментальной среде, вставьте новый слой на временную диаграмму
(команда Insert • Timeline • Layer) перед маскируемым слоем. Затем в диалого-
вом окне Layer Properties (Modify • Timeline • Layer Properties) задайте свойству
Type маскирующего слоя значение Mask. Далее на маскирующем слое создайте
фигуру, определяющую границы маски. В Flash области с пикселами на маски-
рующем слое считаются прозрачными, то есть сквозь них просматривается мас-
кируемый слой. Области без пикселов блокируют (закрывают) маскируемый
слой. Например, чтобы имитировать эффект прожектора, при котором маскиру-
емый слой виден сквозь круглое отверстие, можно при помощи инструментов
рисования (Window • Tools) создать черный круг и использовать его в качестве
маски.
В Flash MX появилась возможность создания сценарных масок, то есть
использования одиного анимационного клипа для маскировки содержимого дру-
гого клипа. Сценарная маска, как подсказывает само ее название, назначается
динамически на стадии выполнения вызовом метода ActionScript MovieClip.setMaskO.
Назначение маски на стадии выполнения почти не отличается от создания
маскирующего слоя на стадии разработки, но обеспечивает гораздо большую
гибкость. Маску, используемую для данного клипа, можно сменить на стадии
выполнения; также существует возможность создания новых масок. Хотя
маскирующий слой может анимироваться на стадии разработки, анимация мас-
ки на стадии выполнения средствами ActionScript позволяет создавать гораздо
более сложные эффекты. Надеюсь, это краткое введение поможет наиболее
эффективно использовать маски в различных трюках книги, в которых
задействованы как маски стадии разработки, так и маски стадии выполнения (то
есть сценарные). За дополнительной информацией о масках обращайтесь
к справочной системе (раздел How Do I • Basic Flash • Work with Layers • Add a Mask
Layer) или проведите поиск в электронной документации по ключевому слову
«Mask».
Но довольно теории! Переходим к самому интересному.

ТРЮКИмитация переходов на уровне


№ 1 пикселов
Имитация эффектов растворения и вытеснения на уровне пикселов (по
аналогии с Macromedia Director).
Flash не обладает встроенной поддержкой переходов на уровне пикселов. Этот
трюк может использоваться в сочетании с другими видеотрюками (см. трюк 8),
чтобы сделать статическую растровую картинку более интересной (см. трюк 3).
Имитация переходов на уровне пикселов 29

В Flash используется векторный механизм графического вывода, не предостав-


ляющий доступ к отдельным пикселам экрана. В основу трюка заложено то об-
стоятельство, что пикселы весьма малы, а все маленькие объекты похожи друг
на друга.
На рис. 1.1 изображен пример перехода на уровне пикселов.

Рис. 1 . 1 . Имитация перехода на уровне пикселов (шаги 1-4)

Переход постепенно скрывает (маскирует) пикселы первого изображения, что-


бы на каждом шаге исчезало всего несколько пикселов. В ходе маскировки про-
является второе изображение, находящееся под ним; так возникает эффект пе-
рехода от первого изображения ко второму. На рис. 1.2 изображены маски,
использованные для создания эффекта. Для черных пикселов маска демонстри-
рует первое (верхнее) изображение, а для белых пикселов - второе (нижнее).
Как будет показано далее, ценой небольших изменений можно создавать гораз-
до более сложные переходы.
1. Создайте фиктивный пиксел. В нашем примере будет использоваться малень-
кий квадрат А х 4.
2. Создайте большое количество фиктивных пикселов. В Flash эта задача легко
решается при помощи метода MovieClip.attachMovie().
3. Создайте сценарий, который убирает каждую точку по прошествии опреде-
ленного времени. Используя все точки большой маски, мы создаем переход
между двумя изображениями (или видеоклипами) наподобие показанного
на рис. 1.1.
30 Глава 1. Визуальные эффекты

Рис. 1.2. Маски для имитации перехода на уровне пикселов (шаги 1-4)

Основная проблема в том, что для реализации эффекта используются тысячи


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

Создание пикселов
Создать маску из пикселов ненамного сложнее, чем обычный прямоугольник.
1. Создайте новый документ Flash (File • New • Flash Document).
2. Выполните команду Modify • Document, задайте размеры сцены более чем
200 х 200 пикселов, выберите белый цвет фона (подойдет любой светлый отте-
нок, на котором будет хорошо виден черный прямоугольник из шага 3).
3. Нарисуйте черный прямоугольник без контура (контур все равно останется
незаметным, но замедлит обработку эффекта).
4. На панели свойств (Window • Properties) задайте высоту и ширину прямоу-
гольника равными 4. Задайте координаты X и Y равными 0. Итоговый вид
панели показан на рис. 1.3 рядом с точкой регистрации.
5. Преобразуйте прямоугольник в символ анимационного клипа. Для этого выде-
лите его (при помощи инструмента Selection) и нажмите клавишу F8 (Modi-
Имитация переходов на уровне пикселов 31

fy • Convert to Symbol). На экране появляется диалоговое окно Symbol Properties.


Присвойте символу клипа имя dot и проследите за тем, чтобы параметры
экспортирования были заданы в соответствии с рис. 1.4 (если параметры ком-
поновки Linkage не отображаются в окне, щелкните на кнопке Advanced).

Shape

+ II
0.0

L. Н; 4,0 "I 0.0

Рис. 1.3. Маска 4 x 4 с точкой регистрации

ПРИМЕЧАНИЕ
Эксперт ActionScript может предложить построение маски средствами Drawing
API, но у Flash уйдет слишком много времени на динамическую прорисовку всех
прямоугольников, необходимых для этого эффекта.

Рис. 1.4. Диалоговое окно свойств символа

Далее экземпляр анимационного клипа можно удалить со сцены, так как мы


будем использовать метод MovieClip.attachMovie() для динамического присоедине-
ния библиотечного символа к главной временной диаграмме на стадии выполне-
ния. Если вы предпочитаете обойтись без создания клипа с его последующим
32 Глава 1. Визуальные эффекты

удалением, воспользуйтесь командой Insert • New Symbol (клавиши Ctrl+F8 (Windows)


или 3S+F8 (Mac)) и создайте символ анимационного клипа прямо в библиотеке.
В эффекте используется большая маска, состоящая из квадратов 4 x 4 . Маска
применяется к первому изображению; эффект основан на маскировании допол-
нительных прямоугольников с течением времени, в результате чего второе изоб-
ражение (находящееся под первым) «проступает» сквозь новые отверстия.

Создание множества пикселов


Добавьте на главную временную диаграмму новый слой и присвойте ему имя
actions (см. трюк 80).
На слое actions главной временной диаграммы выделите кадр 1 и свяжите с ним
следующий фрагмент кода при помощи панели Actions (F9):
function drawGrid (theWidth:Number. theHeight:Number):Void {
var initDot:Object = new ObjectO;
var k:Number = 0;
for (var i:Number = 0: i < theWidth; i += 4) {
for (var j:Number = 0: j < theHeight: j += 4) {
var dotName:String = "dot" + i + "_" + j :
initDot._x = i ;
initDot._y = j :
this.attachMovieC'dot". dotName. k. initDot);

drawGrid(200. 200):
Приведенный фрагмент создает квадрат 200 х 200 пикселов, состоящий из «то-
чек» - анимационных клипов 4 x 4 (изменяя параметры drawGridQ, можно соз-
дать квадрат других размеров). Каждый экземпляр размещается в позиции (i, j)
на глубине k с именем dotz_j. Первому экземпляру (находящемся в левом верх-
нем углу квадрата) соответствует имя dotO_0, а последнему (в правом нижнем
углу) - имя dot199_199. Чтобы просмотреть созданные анимационные клипы,
выполните код в отладочном режиме (Control • Debug Movie), но учтите: для ото-
бражения всех клипов отладчику может потребоватьея некоторое время. Даже
если вам покажется, что Flash «висит», подождите несколько секунд.

ПРИМЕЧАНИЕ
Эффект создает большое количество анимационных клипов: (200/4) 2 = 2500.
Если на экране одновременно находится от 3000 до 4000 клипов (даже не пере-
мещаемых), работа Flash заметно тормозится, поэтому превышать порог в
2500 пикселов не рекомендуется. Если маскируемая область больше той, кото-
рая используется в нашем примере (квадрат со стороной 200 пикселов), то
вместо добавления новых прямоугольников лучше увеличить их размеры.

Управление пикселами
Возникает следующий вопрос: как заставить точки исчезать по нашему жела-
нию? Для этого лучше всего воспользоваться вызовом setlnterval {объект, «ме-
Имитация переходов на уровне пикселов 33

mod», период), который обеспечивает вызов функции объект.метод{) каждые


период миллисекунд. Включите следующую строку после команды initDot._y=j;
в предыдущем сценарии:
initDot.timer = 1000 + Math.ceil(Math.random()*800);
Свойство timer, создаваемое в этой строке, содержит целое число в интервале от
1000 до 1800 для каждого внутреннего клипа. Начальная граница 1000 опреде-
ляет паузу перед началом эффекта, а число 800 определяет его продолжитель-
ность. Оба значения задаются в миллисекундах - стандартных единицах изме-
рения времени в ActionScript.
Трюк основан на эффекте маски, однако Flash позволяет создать только одну
маску для каждого анимационного клипа. Чтобы обойти это ограничение, проще
всего создать все клипы-«точки» внутри другого клипа, выполняющего функ-
ции маски. Имя маскируемого клипа передается в параметре функции drawGrid()
(изменения выделены жирным шрифтом):
function drawGrid (theWidth:Number, theHeight:Number,
imagedip:MoveiClip):Void {
var initDot = new ObjectO;
var k:Number = 0:
// Создание клипа для хранения всех "точек"
this.createEmptyMovieClipC'mask", 1);
// Назначение созданного клипа в качестве маски
imagedip.setMask(mask):
for (var i:Number = 0: i < theWidth: i += 4) {
for (var j:Number = 0: j < theHeight; j += 4) {
var dotName:String = "dot" + i + "_" + j ;
initDot._x = i ;
initDot._y = j ;
initDot.timer = 1000 + Math.ceil(Math.random()*800):
mask.attachMovie("dot", dotName, k, initDot);

}
drawGrid(200. 200, imagel_mc);
Итак, все «точечные» клипы находятся внутри другого анимационного клипа
с именем mask. Последний назначается маской для клипа, имя которого переда-
ется в параметре функции drawGrid(). В данном примере используется клип с име-
нем image1_mc; мы создадим его позднее, в разделе «Использование эффекта».
Но сначала нужно позаботиться об уничтожении клипов-«точек».

Создание таймеров
Для каждого «точечного» клипа уже установлено свойство timer. Теперь давайте
напишем код, обеспечивающий исчезновение «точек».
Отредактируйте символ клипа dot и добавьте новый слой с именем actions (тра-
диционно первый слой временной диаграммы называется scripts или actions и ис-
пользуется исключительно для хранения сценариев).
34 Глава 1. Визуальные эффекты

Добавьте к первому кадру слоя actions следующий фрагмент:


removeMe = function О {
clearlnterval(countDown):
thi s.removeMovi eCli p();
}:
var countDown = s e t l n t e r v a l ( t h i s . "removeMe", timer);
В последней строке функция setlntervalQ создает для каждой «точки» таймер
countdown. При завершении отсчета таймер вызывает функцию removeMe(). Эта

п
функция отменяет интервал отсчета и удаляет текущий клип. Тем самым созда-
ется эффект перехода «исчезающих пикселов».
ПРИМЕЧАНИЕ
Если при вызове setlnterval() в первом параметре передается ссылка на функ-
цию (как при вызове setlnterval(removeMe,timer)), значение ключевого слова this
в функции removeMe() не определено. По этой причине мы используем альтер-
нативную форму setlnterval(this,"removeMe",timer), у которой в первых двух па-
раметрах передаются объект и имя метода (в этом случае ключевое слово this
представляет объект, переданный в первом аргументе). При вызове removeMe()
ключевое слово this находится в области видимости, поэтому мы можем ис-
пользовать вызов this.removeMovieClip() для уничтожения клипа.

Использование эффекта
Разместите два изображения/видеоклипа, связываемых переходом, на двух раз-
ных слоях; первое изображение (или видеоклип) должно находиться на верхнем
слое, как показано на рис. 1.5. На панели свойств присвойте ему имя экземпляра
image 1_mc. Второе изображение может называться как угодно, поскольку оно
нигде не упоминается в программном коде.

:
5 • 10 15 3 . 2s 33 ;S .

Рис. 1.5. Создание перехода между двумя слоями


Текстовые эффекты на уровне пикселов 35

Чтобы ознакомиться с примером эффекта в действии, загрузите файл pixelMask.fla


с сайта книги.

Усовершенствования
Изменяя интервалы между исчезновением «точек», можно имитировать разные
эффекты переходов. Например, изменяя интервал на основании позиции точки,
вы сможете реализовать многие стандартные переходы:
// Вытеснение слева направо
initDot.timer = 1000 + (Math.random()*(initDot._x)*10);
// Вытеснение по диагонали
initDot.timer = 1000 + (Math.random()*(initDot._x + initDot._y)*5);

Итоги
Многие Flash-разработчики недооценивают возможности масок. На первый
взгляд, маскам трудно найти реальное применение, но если вникнуть поглубже,
вы измените свое мнение. Вполне естественно, что маски широко применяются
в самых замечательных эффектах, описанных в книге (см. трюк 21)!

Текстовые эффекты на уровне


ТРЮК

№2 пикселов
Создание текстовых эффектов и переходов на уровне пикселов.
Основной недостаток имитации пиксельных эффектов в Flash состоит в том, что
потенциальное ухудшение быстродействия ограничивает количество используе-
мых фиктивных пикселов. Существует два способа сохранить их количество на
достаточно низком уровне: ограничиваться небольшими изображениями (как
при имитации переходов на уровне пикселов - см. трюк 1) или же применять
эффекты к изображениям с многочисленными фоновыми пикселами, которые
могут игнорироваться при обработке эффекта.
Теперь это кажется очевидным, но когда-то мне понадобилась целая вечность,
чтобы понять, что текст подходит под описание «изображения с многочислен-
ными фоновыми пикселами». После непродолжительных поисков в Веб напра-
шивается предположение, что этот факт действительно неочевиден - похоже,
больше никто не использует этот трюк.
В настоящем разделе мы сделаем так, чтобы текст формировался из пикселов,
разбросанных по экрану. Конечно, применение других вычислений с учетом по-
зиций пикселов маски позволяет реализовать и другие эффекты.
Трюк делится на две части:
• преобразование текстового блока в квадраты 1 x 1 («фиктивные пикселы» из
предыдущего примера);
• анимация фиктивных пикселов.
36 Глава 1. Визуальные эффекты

Делается это так:


1. Создайте текстовое поле и введите в нем текст.
2. Нажмите клавиши Ctrl+B (Windows) или <HJ+B (Mac) или дважды выполните
команду Modify • Break Apart, чтобы преобразовать текстовое поле в прими-
тивную фигуру.
3. Не снимая выделения с текста, нажмите клавишу F8 и преобразуйте его в сим-
вол анимационного клипа с именем text. Убедитесь в том, что флажок Export
for ActionScript установлен, и задайте идентификатор компоновки text. Удали-
те экземпляр клипа со сцены, поскольку мы добавим его на стадии выполне-
ния из библиотеки методом MovieClip.attachMovie().
4. Для нормальной работы клипа регистрационная точка должна находиться
в левом верхнем углу текста. Активизируйте режим редактирования «на месте»
двойным щелчком на клипе затем выделите весь текст командой Edit • Select
All и задайте нулевые значения свойств X и Y на панели свойств (рис. 1.6).

Й • - — • • •

Н:: IS. 6

Рис. 1.6. Задание позиции регистрационной точки для выделенного текста

Трюк работает лишь в том случае, если текст был преобразован в примитивную
фигуру командой Modify • Break Apart (вскоре вы поймете, почему это необходи-
мо). Вообще говоря, эта операция нежелательна, поскольку она увеличивает раз-
мер файла. При большом объеме текста прирост получается довольно значи-
тельным. Одно из возможных решений проблемы - включение каждой буквы
шрифта в виде отдельного клипа, содержащего примитивную фигуру, и форми-
рование предложений на стадии выполнения. На первый взгляд кажется, что
файл SWF перегружается множеством лишних байтов, но стоит вспомнить, что
практически то же самое происходит при сохранении в SWF контуров шрифтов,
а эта операция должна выполняться всегда, когда буквы шрифта должны ис-
пользоваться в качестве графических элементов.
Нам также понадобится второй анимационный клип с идентификатором компо-
новки dot. Клип dot представляет собой прямоугольник 1 х 1, у которого обе
координаты, X и Y, равны 0, как показано на рис. 1.7 (для задания свойств следует
использовать панель Properties, так как точка получается слишком маленькой).
Программный код дублирует эффект «проявления с размывкой», но на этот раз
текст действительно размыт (обычно размывка имитируется при помощи аль-
фа-канала), как показано на рис. 1.8, поскольку разбиение текста на пикселы
является одной из составляющих эффекта.
Текстовые эффекты на уровне пикселов 37

Hi! 1-0 :Y:;O.Q

Рис. 1.7. Маска 1 х 1

Рис. 1.8. Текстовый эффект уровня пикселов (шаги 1-4)

function moverО {
this._x -= (this._x - t h i s . x ) / 4;
this._y -= (this._y - t h i s . y ) / 4:

function lastMoverO {
this._x -= (this._x - t h i s . x ) / 4;
this._y -= (this._y - t h i s . y ) / 4;
i f ( ( t h i s . _ x - t h i s . x ) < 0.1) {
dotHolder.removeMovi eCli p();
t e x t C l i p . _ v i s i b l e = true;

// Размещаем текст на сцене и скрываем его


textClip = this.attachMovie("text". "textClip". 0);
textClip._x = 200;
textClip._y = 100;
textClip._visible = false;
// Инициализация переменных, включая height и width
var dots = 1;
var distance = 10000;
var stopDot = true;
var height = textClip._y + textClip.Jieight;
var width = textClip._x + textClip._width;
// Создание клипа для каждого пиксела в тексте
38 Глава 1. Визуальные эффекты

var dotHolder = this.createEmptyMovieClip("holder". 1);


for (var j = textClip._y; j < height; j++) {
for (var i = textClip._x; i < width; i++) {
i f ( t e x t C l i p . h i t T e s t ( i . j . true)) {
var c l i p = dotHolder.attachMovie("dot". "dot" + dots, dots);
i f (stopDot) {
c l i p . _ x = distance;
clip.onEnterFrame = lastMover;
stopDot = false:
} else {
c l i p . _ x = Math.randomO * distance - distance/2;
clip.onEnterFrame = mover;
}
// Сохранение позиции, в которую должен перейти клип ( c l i p . x . c l i p . у ) ,
// и удаление точки с экрана
clip.x = i ;
clip.у = j :
clip._y = j :
dots++;

Функциями mover() и lastMoverQ мы займемся чуть позже. Остальной код поме-


щает текст на сцену и скрывает его, после чего инициализирует несколько пере-
менных, в том числе и определяющих ширину и высоту текста.
Цикл for использует метод MovieClip.hitTest() для поиска всех непустых пикселов
в тексте и создает для каждого найденного пиксела соответствующий клип dot.
С каждым клипом связывается обработчик onEnterFrameO, обеспечивающий ани-
мацию эффекта (вместо этого также молено было воспользоваться вызовом
setlnterval() - см. трюк 1).
В цикле стоит обратить внимание на два неочевидных момента.
Во-первых, использование метода hitTest() и является той причиной, по которой
было произведено исходное разбиение текста. Метод hitTest() всегда возвращает
false для динамических текстовых полей (в этом случае все пикселы интерпре-
тируются как пустые).
Во-вторых, посмотрите, как мы проверяем, все ли пикселы находятся в своих
конечных позициях. Большинство пикселов случайным образом разбросаны по
экрану и находятся под управлением обработчика mover(). Однако первый пик-
сел смещается на наибольшее расстояние, а также получает более сложный об-
работчик lastMover(). Данное событие останавливает эффект при достижении
пикселом своей итоговой позиции, так как к этому моменту все остальные пик-
селы уже должны находиться на своих местах (они перемещаются на меньшее
расстояние).

ПРИМЕЧАНИЕ
Проверка выглядит несколько неестественно, но она требует гораздо меньших
ресурсов, чем «правильное» выполнение аналогичной проверки для каждого
пиксела.
Имитация зернистости старой пленки 39

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

ТРЮК Имитация зернистости старой пленки


№3 Создание эффекта зернистой старой пленки с использованием Photoshop
и Flash.
Векторный механизм графического вывода Flash обладает массой достоинств,
но иногда требуется получить менее четкое изображение и уменьшить резкость
границ. Одним из простейших способов получения более стильной .анимации
или приглушения излишне резких границ является эффект зернистости, харак-
терный для старых кинопленок. Для получения более драматических или специ-
ализированных эффектов его можно объединить с эффектом колоризации (трюк 8)
или сепийной цветовой гаммы (трюк 13).
Самый очевидный способ реализации эффекта зернистости основан на добав-
лении в изображение случайных векторных линий и точек. Однако в этом слу-
чае воспроизводится только внешний эффект, но не атмосфера старого фильма;
в конечном счете изображение все равно остается резким и четким. В этом
трюке для уменьшения четкости клипа будет использоваться растровое изо-
бражение.
Трюк делится на две фазы: создание растра зернистости в Photoshop и его пос-
ледующее импортирование и использование в Flash (разумеется, вместо Photoshop
также можно использовать Fireworks - общие принципы остаются теми же).

Создание растра зернистости


Грязь, царапины и выпавшие частицы покрытия делают фотографическое изоб-
ражение более реальным. При попадании на пленку или негатив пыль, грязь,
волокна и т. д. отображаются в виде темных пятен или линий. Царапины выгля-
дят как белые линии.
Чтобы приступить к настройке изображения в Photoshop, выполните следую-
щие действия:
1. Запустите Photoshop.
2. Нажмите клавишу D, чтобы восстановить цвета изображения и фона по умол-
чанию.
3. Нажмите клавишу X, чтобы поменять местами цвета изображения и фона. Вы
получаете растр с черным цветом фона и белым цветом изображения.
4. Создайте новый файл Photoshop с именем grain.psd командой File • New.
Выберите размеры изображения такими, чтобы длина превышала ширину.
40 Глава 1. Визуальные эффекты

Я создал для демонстрационных целей файл 800 х 4.00 пикселов, но вы може-


те обойтись гораздо меньшим файлом (обычно 400 х 200).
5. Установите флажок Background Color в группе Contents диалогового окна New
Document, как показано на рис. 1.9. В результате получается прямоугольный
черный «холст».

1 :.,.,'•,...У&:.;,;.: ,JJ:'

I pixels
I pixels
1 pixels/inch

| ;© Background Co lor; •; ; : : . : ; :
... ;
•:j О Transparent :- : . \ •'

Рис. 1.9. Установка флажка Background Color в Photoshop

6. Добавьте новый слой при помощи кнопки Create a New Layer в нижней части
вкладки Layers. Вывод будет осуществляться только на новом слое, поэтому
следите за тем, чтобы на вкладке Layers всегда оставался выделенным только
слой Layer 1 (рис. 1.10).

Normal yjjsjOpacity: MOOH,j


Ь a F«:iiwH]>Jj

[C-eate в new layer [

Рис. 1.10. Установка флажка Background Color в Photoshop

Пора переходить к прорисовке эффектов. В старых фильмах встречаются три


разновидности шумов:
• волосяные линии, обусловленные темными включениями в пленке;
Имитация зернистости старой пленки 41

• точки и пятна, возникающие из-за попадания частиц грязи или других ве-
ществ на пленку. Светлые пятна появляются из-за царапин или отпадения
частиц покрытия пленки;
• царапины, появляющиеся из-за физического повреждения пленки, стираю-
щего часть изображения.
Используя инструментарий Photoshop (вернее всего, инструменты Pencil и Brush),
добавьте три типа эффектов на слой Layer 1. На рис. 1.11 слева находятся ма-
ленькие точки, в середине - большие пятна, и справа - царапины. Сверху и снизу
расположены волосяные линии.

Рис. 1.11. Имитация дефектов пленки в Photoshop

Размойте пикселы изображения при помощи инструмента Photoshop Eraser со


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

Рис. 1.12. Имитация неглубоких царапин


42 Глава 1. Визуальные эффекты

До настоящего момента использовался только белый цвет, однако многие де-


фекты старых пленок кажутся черными. Их тоже необходимо имитировать:
1. Выделите часть белых пикселов при помощи инструмента Photoshop Selection.
2. Инвертируйте выделение командой Image • Adjustment • Invert. Выделенные
пикселы вроде бы исчезают, потому что мы создаем черные пикселы на чер-
ном фоне, но на самом деле они остаются на месте - просто мы их не видим.
3. Удалите фоновый слой (щелкните на нем на вкладке Layers и перетащите на
значок с мусорным баком в нижней части вкладки).
В итоге у вас должно получиться что-нибудь вроде изображения, показанного
на рис. 1.13 (клетчатым узором в Photoshop изображается нулевой альфа-канал,
то есть отсутствие пикселов).

f
Рис. 1.13. Имитация выпадения фрагментов поверхности

Сохраните изображение в виде файла PNG. Не используйте никакие оптимиза-


ции для Веб!
Многие дизайнеры оптимизируют графику, подготовленную к загрузке в пакет
веб-дизайна (Flash). В действительности делать этого не нужно; оптимизацию
лучше всегда откладывать до момента создания SWF во Flash, поскольку в та-
ком случае вы получаете большую свободу действий.
Например, если клиент решит, что ему нужна версия сайта для каналов с высо-
кой пропускной способностью, вам останется лишь изменить параметры экспор-
тирования растрового изображения в Flash. Если же растровое изображение бу-
дет оптимизировано перед импортированием в Flash, придется заново запускать
Photoshop и экспортировать графику с новыми параметрами. После этого все
экземпляры старого растра на временной диаграмме Flash нужно будет заменить
экземплярами нового растра. Таким образом, импортируя растры с полным ка-
чеством и поручая их оптимизацию Flash, вы сэкономите немало времени. Для
тех, кто предпочитает работать в программе Fireworks, ее интеграция с Flash (то
есть запуск и редактирование) также способствует повышению эффективности.
Имитация зернистости старой пленки 43

Использование растра в Flash


После того как растровое изображение будет экспортировано из Photoshop в фор-
мате PNG, необходимо обеспечить его правильное использование:
1. Импортируйте файл PNG в Flash командой File • Import • Import to Library.
2. Выделите растр в библиотеке.
3. Щелкните правой кнопкой мыши (Windows) или щелкните с нажатой клави-
шей 3€ (Мае) на панели библиотеки. Выберите в контекстном меню команду
Properties.
4. Измените свойства изображения в соответствии с рис. 1.14: выберите низкий
коэффициент сжатия JPEG и запретите сглаживание (без сглаживания Flash
быстрее выполняет операции с растровыми изображениями).

• :'.••••"••

: g r a h
OK
Сфосип-ients and SettjngsAgham
Cancel

1S;39;2O Update

Compression; ; Photo (JPEG) Teat

Рис. 1.14. Свойства растрового изображения в библиотеке Flash

ПРИМЕЧАНИЕ
Обратите внимание: созданное нами изображение содержит как сжатие JPEG,
так и альфа-канал! Создать автономный файл в формате JPEG с ассоциирован-
ным альфа-каналом не удастся, но Flash не возражает против таких файлов.
Данная особенность чрезвычайно полезна для наложения векторов Flash на ра-
стровые изображения.

Перетащите растровое изображение на сцену, нажмите клавишу F8 (команда


Modify • Convert to Symbol) и преобразуйте растр в символ анимационного клипа
с именем grain.
Далее остается лишь наложить подвижную версию нашего клипа на видео, рас-
тровое изображение или векторную анимацию. На рис. 1.15 она наложена на
статическое изображение; рисунок выглядит так, словно перед вами кадр из ста-
рого фильма.
Глава 1. Визуальные эффекты
v
, v.-;\w-i:*»TT-n >-п—г—-* ' _^J . •'.•-•' . • .• J : : *•"

i
u
^• , « • •<•%!£:. Mliu ., .
1iiiii-i

.... т.

Рис. 1.15. Имитация старой пленки (шаги 1-3)

Те части клипа grain, которые не появляются на изображении, спрятаны при


помощи маски. Окончательный эффект показан на рис 1.16 (или исполь уйте
файл grain.fla с веб-сайта книги) иыюльзуиге

Рис. 1.16. Использование маски для придания окончательного вида эффекту

Итоги
Область применения представленной методики не ограничивается «созданием
атмосферы» в видеоклипах. Эффект «старой кинопленки» также позволяет
• маскировать недостатки видеоматериала (например, артефакты, обусловлен-
ные слишком высоким коэффициентом сжатия);
Создание SWF на базе анимированного формата GIF 45

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


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

Создание SWF набазе анимированного


формата GIF
Быстрое преобразование анимированных GIF-файлов для использова-
ния в эффектах Flash.
Мне показалось, что читателю было бы интересно узнать, как улучшить визу-
альное восприятие GIF-файла, загрузив его в Flash. Я отправился на страницу
O'Reilly (http://www.oreilly.com), где меня встретила зверушка, изображенная на
рис. 1.17 (утверждают, что это долгопят). Имя файла oreilly_header1.gif вполне
типично для срезов, создаваемых для таблиц на базе HTML, - стало понятно,
что с этим GIF-файлом можно работать. Я еще раз посмотрел на эту зверушку,
благо она была довольно симпатичной, и подмигнул ей. Она подмигнула в ответ.
После начального замешательства и обязательного повторения эксперимента
я понял, что имею дело с анимированным GIF-файлом.

O ' R E I L L Y

Рис. 1.17. Долгопят — талисман издательства O'Reilly на сайте oreilly.com

Тогда я задумался... На примере Flash-версии файла с этой зверушкой было бы-


удобно продемонстрировать различия между Flash и традиционным дизайном
HTML. Данный трюк показывает, как применение Flash позволяет уменьшить
размер файла по сравнению с анимированным GIF. А после успешной реализа-
ции двухмерной Flash-версии мигающего долгопята можно использовать ее для
создания трехмерного мигающего долгопята (см. трюк 35).

Исходный анимированный GIF


Копия нашего анимированного знакомого легко создается командой Save в веб-
браузере. Например, в Internet Explorer для Windows следует щелкнуть на GIF-
файле правой кнопкой мыши и выбрать команду Сохранить рисунок как (Save
Picture As) в контекстном меню. Изображение сохраняется на локальном диске.
Другое преимущество анимаций Flash перед анимированными GIF-файлами зак-
лючается в том, что их труднее украсть, чем этот рисунок с сайта O'Reilly, - для
46 Глава 1. Визуальные эффекты

этого SWF маскируется (см. трюк 98) в кэше браузера, где пользователи обычно
ищут загруженные SWF.
Если открыть GIF-файл O'Reilly в графическом редакторе (например, Fireworks
или Photoshop/ImageReady), вы увидите, что анимация подмигивания воспро-
изводится каждые 12 секунд (первому кадру назначена 12-секундная задержка),
а ее общая продолжительность равна 12 секундам. Первое, на что следует об-
ратить внимание, - на то что абсолютное большинство пикселов изображения
не изменяются между кадрами; меняются только глаза. Следовательно, преобра-
зование ролика в Flash и анимация одних глаз позволит заметно сократить раз-
мер файла.
Также следует помнить, что анимация не интерактивна. В данном случае отсут-
ствие интерактивности вполне уместно (выходки зверька не должны отвлекать
читателя), но для интереса мы добавим интерактивность и убедимся в том, что
SWF все равно получается меньше исходного GIF-файла.

Создание ресурсов для анимации


Проще всего импортировать все секции анимированного GIF-файла в виде се-
рии изображений в формате PNG, потому что при этом сохраняется качество
оригинала (особенно при использовании PNG-24), и к ним можно легко доба-
вить альфа-канал. Хотя формат GIF поддерживает прозрачность, в действитель-
ности вся поддержка сводится к одной маске, определяющей, отображать или не
отображать пиксел. Формат PNG-24 поддерживает полноценный альфа-канал,
в котором уровень прозрачности задается в процентах. На рис. 1.18 показаны
изображения PNG (в Photoshop), готовые к экспортированию в Flash.
В процессе преобразования применяется ряд интересных трюков:
• Изображение обрезается таким образом, чтобы анимируемая часть (то есть
глаза) была отделена от всего остального.
• Хотя исходная анимация состоит из шести кадров, три из них повторяются
(последовательность закрытия глаз представляет собой последовательность
их открытия, переставленную в обратном направлении). В результате суще-
ственно уменьшается количество уникальных кадров, которые придется соз-
давать в Flash, что также приводит к сокращению размера файла.
• В формате PNG-24 можно экспортировать полноценные альфа-данные, что
позволит организовать размывку краев изображения. Например, если мы за-
хотим разместить зверушку на фоне джунглей, чтобы она чувствовала себя
как дома, контурные пикселы можно будет слить с фоном и избавиться от
неровностей и ореолов, часто встречающихся при использовании стандарт-
ных изображений GIF.
Чтобы добавить прозрачность к импортированному изображению, выполните
следующие действия:
1. Скопируйте слой Background на вкладке Layers.
2. Удалите исходный слой Background. В изображении остается один слой с име-
нем Background Layer Copy.
Создание SWF на базе анимированного формата GIF 47

3. Применение инструмента Eraser к этому слою создает альфа-канал (после


удаления слоя Background при стирании пикселов не остается фона, который
просматривался бы сквозь стертые участки, поэтому Photoshop заменяет их
альфа-данными).

Рис. 1.18. Анимированный GIF-файл, преобразованный в серию PNG-файлов

После импортирования изображений PNG в Flash (команда File • Import) зве-


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

Рис. 1.19. Глазные яблоки, зрачки, веки и тело


48 Глава 1. Визуальные эффекты

Обратите внимание: глазные яблоки в этой версии сделаны векторными. Пос-


ледовательность мигания реализована как анимационный клип из трех растров
с постепенным закрытием глаз, после чего те же три растра воспроизводятся
в обратной последовательности.
Зрачки представляют собой две точки с именами leftEyejnc и rightEyejnc. Под
управлением следующего сценария они будут внимательно следовать за указа-
телем мыши, как показано на рис. 1.20. Как обычно, приведенный код связыва-
ется с первым кадром слоя actions главной временной диаграммы.

Рис. 1.20. Отслеживание указателя мыши

followMouse = function О {
this.startX = this._x;
this.startY = this._y;
this.onEnterFrame = animateEye;

animateEye = function () {
var distX = (_xmouse - t h i s . j O / 50;
var distY = (_ymouse - this._y) / 50;
i f (Math.abs(distX) < 5) {
this._x = this.startX+distX;
}
i f (Math.abs(distY) < 5) {
this._y = t h i s , startY+distY;

leftEyejnc.onEnterFrame = followMouse;
rightEyejnc.onEnterFrame = followMouse;
Функция followMouseO назначается обработчиком события onEnterFrame для обоих
зрачков. При вызове она просто сохраняет начальную позицию зрачка и назначает
обработчиком onEnterFrame функцию animateEyeO для последующих кадров.
Конечно, вы можете наделить свою зверушку гораздо большим спектром эмо-
ций, чем предусмотрено в анимированном GIF-файле (рис. 1.21), но это будет
уже не трюк, а проявление истинной сущности Flash.

Итоги
Хотя анимация получилась довольно стандартной, сама скорость ее создания на
базе существующего анимированного GIF-файла показывает, как легко созда-
Анимация PSD-файлов Photoshop в Flash 49

ются более универсальные анимации Flash. Размещение растровых изображе-


ний с альфа-каналами друг над другом позволяет создавать многослойные ани-
мации непосредственно на базе анимированных GIF-файлов. Этот трюк также
демонстрирует удобный способ экспортирования многослойных файлов Photoshop
формата PSD в Flash; просто экспортируйте каждый слой в виде отдельного
изображения в формате PNG-24, включающем данные прозрачности. Далее им-
портированная графика PNG воссоздается в нужном порядке на слоях Flash.
Конечно, между исходной последовательностью и результатом имеется важное
различие - полученные слои можно анимировать!

Рис. 1.21. Грустный долгопят и его собутыльник

Анимация PSD-файлов Photoshop


ТРЮК

№5 в Flash
Импортирование PSD-файлов Photoshop в Flash для последующей ани-
мации.
В этом трюке будет показано, как воссоздать файл Photoshop на слоях Flash.
Процесс рассматривается во всех подробностях, потому что они весьма поучи-
тельны (и к тому же бесплатны!), хотя модуль Photoshop PSD2FLA (http://
www.medialab.com/psd2fla) от сторонней фирмы Media Lab существенно упроща-
ет этот процесс. Вероятно, читатели, работающие с Director, помнят Media Lab
как разработчика PhotoCaster, популярной и почитаемой надстройки для им-
портирования PSD-файлов в Director.
Если в системе установлен QuickTime версии 4.0 и выше, PSD-файл можно им-
портировать прямо в Flash. Скорее всего, Flash сообщит, что файл импортиро-
вать не удается, но предложит импортировать его через QuickTime. Щелкните
на кнопке Yes, и изображение будет успешно импортировано.

ПРИМЕЧАНИЕ
В процессе импортирования Flash описывает файлы .psd как «графику Photoshop
версий 2.5, 3», однако при импортировании через QuickTime Flash обрабатыва-
ет файлы гораздо более поздних версий Photoshop.

Но при импортировании файлов через QuickTime возникает проблема: импор-


тированные файлы «сплющиваются» и в них теряется разбиение на слои, как
показано на рис. 1.22. Если учесть, что единственной разумной причиной для
50 Глава 1. Визуальные эффекты

импортирования PSD (вместо веб-форматов вроде JPEG) является использова-


ние внутренней информации слоев, становится очевидно, что способ импорти-
рования через QuickTime отнюдь не идеален.

Рис. 1.22. Многослойное изображение Photoshop

Данный трюк научит вас импортировать PSD-файлы таким образом, чтобы их


можно было эффективно воссоздать в Flash для создания анимаций с сохране-
нием значительной части исходных данных слоев.
Работа начинается с Photoshop: обрежьте/масштабируйте PSD-файл так, чтобы
полученное изображение подходило для использования в Web (то есть его раз-
меры не превышали 500 х 500 пикселов).
Результат значительно улучшается при пошаговом масштабировании графи-
ки. Например, изображение 1000 х 1000 сначала уменьшается до 900 х 900,
затем до 800 х 800 и т. д. вплоть до 500 х 500; итоговое изображение получает-
ся более качественным и оставляет больше свободы выбора для последующего
сжатия.
Существует и другая причина для уменьшения изображения: технология Flash
плохо приспособлена для тех операций с растрами, которые мы собираемся вы-
полнять - она лучше подходит для векторной графики. Чтобы обойти это огра-
ничение, необходимо позаботиться о том, чтобы Flash не приходилось изменять
слишком много информации на экране за один кадр. Уменьшение размеров ра-
стра до разумных пределов поможет решить эту задачу.
Следующий шаг - уменьшение количества слоев до минимума за счет объеди-
нения (консолидации) как можно большего их числа. Чтобы получить нормаль-
ное быстродействие в Flash, необходимо оставить не более пяти-шести слоев.
Также рассмотрите возможность удаления всех текстовых и других слоев, кото-
рые можно воссоздать средствами Flash.
Анимация PSD-файлов Photoshop в Flash 51

В своем примере я решил убрать весь текст, кроме названия (наверху слева).
Удаляемый текст заменяется более четким векторным текстом при последую-
щей обработке изображения в Flash. Название было сохранено в исходном виде,
поскольку к нему были применены эффекты Photoshop, которые трудно воспро-
извести средствами векторной графики.
На рис. 1.23 изображена упрощенная версия графики после удаления текста.

Рис. 1.23. Графика Photoshop после исключения слоев, которые могут быть
построены средствами Flash

На следующем шаге каждый слой экспортируется в отдельный файл PNG. Вы-


полните для каждого слоя в документе Photoshop следующие действия:
1) скройте все слои, кроме экспортируемого;
2) выполните команду File • Save As и сохраните изображение в формате PNG;
3) после экспортирования всех слоев перезагрузите все файлы PNG, окружен-
ные значительными пустыми участками (как, например, изображение листа
на рис. 1.24), и обрежьте их, удалив лишние пикселы с нулевым альфа-кана-
лом, как показано на рис. 1.25.
Вернитесь к исходному файлу PSD и оставьте окно Photoshop открытым (или
сделайте экранную копию изображения, если в системе не хватает памяти для
одновременного открытия Flash и Photoshop). Позднее мы еще вернемся к нему.
В Flash задайте размеры сцены по размерам PSD. Импортируйте все PNG-фай-
лы в библиотеку командой File • Import • Import to Library (Flash MX 2004) или
File • Import to Library (Flash MX).
Чтобы организовать эффективную анимацию растровых изображений, лучше
всего преобразовать (а точнее, «инкапсулировать») каждый растр в анимацион-
ный клип - после этого с растрами можно будет использовать методы и анима-
ционные переходы, поддерживаемые для анимационных клипов.
52 Глава 1. Визуальные эффекты

• ' '•••- V •

.... <——

•:•
':.; :li

г- >!>•<• U4I

Рис. 1.24. Слой, являющийся кандидатом на усечение

вит
Яе-ч

ДИИИИвЯииВВ

Рис. 1.25. Усеченное изображение заметно уменьшилось в размерах

1. Последовательно перетащите каждое растровое изображение из библиотеки


на сцену.
Анимация PSD-файлов Photoshop в Flash 53

2. Выделите растр.
3. Нажмите клавишу F8 и создайте на базе растра символ анимационного кли-
па. Для предотвращения путаницы рекомендуется присвоить клипам те же
имена, что и у растров, но снабдить их суффиксом _тс.
Когда все будет готово, вы получите набор растров с прозрачными фонами и смо-
жете разместить их на сцене Flash по аналогии с тем, как они размещались в ори-
гинале PSD. На рис. 1.26 представлена библиотека Flash с набором импортиро-
ванных растров.

' btm
i aps Foider
И background Bitmap
Щ сопсербопТШе Bitmap
Щ Breenleaf Bitmap
Щ overAfcha Bitmap
1 1 spine Bitmap

mcbackGround Movie dip


mcconceptai rT
i Jte
l Movie dip
mcgreenLeaf Movie Qip
me .over Ap
l ha Movie dip
me. spn
ie Movie Clip

'•• • > , :

Рис. 1.26. Импортирование растровых изображений в библиотеку Flash

Вручную разместите клипы на временной диаграмме (или на другом клипе -


в зависимости от того, как будет организован вывод) в тех же порядке и пози-
ции, в которых они следовали в исходном PSD-файле. Если потребуется, ими-
тируйте эффекты слоев Photoshop (такие как Darken, Multiply и т. д.) при помо-
щи цветовых эффектов Flash. Естественно, при желании можно внести изменения,
чтобы веб-версия Flash (рис. 1.27) отличалась от печатной версии Photoshop.
Процесс композиции завершается оптимизацией растровых изображений; для
этого щелкните на каждом растре в библиотеке правой кнопкой мыши (Windows)
или с нажатой клавишей §€ (Мае) и задайте для него параметры экспортирова-
ния. Обычно наилучший компромисс между размерами и качеством достигается
при следующих параметрах:
• фото (JPEG);
• без сглаживания;
• качество в интервале от 30 до 50%.
54 Глава 1. Визуальные эффекты

*v is'-;••:':а .-ч
: »: \<ц , •• х
>

Рис. 1.27. Воссоздание композиции Photoshop в Flash

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

ПРИМЕЧАНИЕ
Flash позволяет экспортировать растровое изображение с альфа-каналом од-
новременно с применением сжатия JPEG!

Итак, у нас имеется отправная точка для построения анимации. Теперь с каж-
дым элементом композиции можно выполнить следующие действия:
• анимацию с использованием кадрирования (задайте на панели свойств пара-
метру Tween значение Motion);
• присвоение имени экземпляра и динамическую анимацию средствами Action
Script.
Далее в композицию добавляются отсутствующий текст и векторные элементы,
удаленные из оригинала (или в Flash-версии создаются новые векторные элементы).
Как упоминалось ранее, анимация растровых изображений может привести к за-
метному торможению работы Flash. Впрочем, практический опыт показывает,
Генератор деревьев 55

что для получения нормального результата нужно либо ограничиться анимаци-


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

Итоги
Если создаваемая анимация не дает особой нагрузки на процессор и не занимает
много места на экране, попробуйте использовать механизм преобразования
PSD-PNG-Flash, описанный в данном разделе (если исходные условия не вы-
полняются, вероятно, стоит подумать о переходе на Director). У описанного пути
также есть свои преимущества, если вы собираетесь имитировать сайт по визуа-
лизациям Photoshop или печатным материалам. В этом случае также стоит по-
думать об использовании Photo Webber (http://www.photowebber.com) от создате-
лей PSD2FLA.
Практический опыт применения данной методики также показывает, что размер
итогового файла SWF может быть на удивление небольшим по сравнению с раз-
мером исходного файла PSD. Обычно размер анимированной SWF-версии бо-
лее или менее соответствует размеру статического JPEG-файла с качеством от
среднего до высокого.

ТРЮК Генератор деревьев


№6 Создание случайного генератора деревьев.

Данный трюк посвящен рисованию деревьев естественного вида с применением


стандартных средств (рекурсия/многократное применение алгоритма с масшта-
бированием). В следующем трюке будет показано, как создать движение с ис-
пользованием внутренней иерархии анимационных клипов.
Теперь перевожу на простой человеческий язык: мы собираемся нарисовать де-
рево и заставить его качаться на ветру (см. трюк 7). Для этого мы смоделируем
природные явления на программном уровне.
Когда я впервые посетил Flash Forward (http://www.flashforward2004.com), Джош
Дэвис (Josh Davis) говорил о мотивации своей работы. Если свести его 45-минут-
ную речь к одной фразе, он сказал: «Взгляните на природу, на то, что находится у вас
прямо перед глазами, - а затем подумайте, что с этим можно сделать во Flash».
Всемирная паутина полна подобных экспериментов. Ни одна книга трюков не
будет полной без одного-двух примеров такого рода.

Рекурсивное построение дерева


Чтобы получить следующую информацию о деревьях, я обратился к своей под-
руге Карен. У нас существует четкое разделение труда: она занимается садом,
а я — компьютерами.
И вот что мне удалось узнать, не выходя за порог дома. Деревья растут по очень
простому принципу, который обычно неукоснительно соблюдается. Ветка растет
56 Глава 1. Визуальные эффекты

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


толщина родительской ветки связана с толщиной веток, растущих из нее, отно-
шением, сохраняющим значение площади поперечного среза (общая толщина
ствола примерно равно толщине всех ветвей, растущих из него, или пропорцио-
нальна ей). А это означает, что отросток растет и делится точно по тем же прави-
лам, что и основная ветвь: их относительные размеры остаются одинаковыми.
Мы знаем о сохранении подобия между деревом и веткой, потому что, если
посадить в землю ветку (а точнее, если ее посадит Карен - мои ветки почему-то
всегда погибают), из нее вырастет дерево.
Учитывая все сказанное, я разработал случайный генератор деревьев. Два при-
мера сгенерированных деревьев изображены на рис. 1.28.

Рис. 1.28. По-моему, дерево получилось вполне правдоподобным


Генератор деревьев 57

Оба дерева (а также множество других) были сгенерированы одной функцией.


Далее приведен код файла treeGen.fla, который можно загрузить с веб-сайта
книги.
function counter О {
i f (branchCounter == undefined) {
branchCounter = 0 ;
}
return (branchCounter++);

function growO {
// Вырастить ветвь...
this.lineStyle(trunkThickness, 0x0. 100);
this.moveTo(0, 0);
this ЛineTo(0. trunkLength);
// Если это не ствол, изменить угол и размер ветви
i f (this._name != "trunk") {
this._rotation = (Math.random()*angle) - angle/2;
this._xscale *='branchSize:
this._yscale *= branchSize;
}
. // Сгенерировать ростки...
var seed = Math.ceil(Math.random()*branch);
for (var i = 0; i < seed; i++) {
if (counterO < 3000) {
var segment = this.createEmptyMovieClip("segment" + i. i)
segment.onEnterFrame = grow;
segment.+y = trunkLength; }
}
delete (this.onEnterFrame);

// Определить позицию ствола и назначить обработчиком


// события onEnterFrame функцию growO
this.createEmptyMovieClip("trunk". 0);
trunk._x = 200;
trunk._y = 400:
trunk.onEnterFrame = grow;

// Параметры дерева
var angle = 100;
var branch = 5;
var trunkThickness = 8;
var trunkLength = -100;
var branchSize =0.7;
Базовая форма дерева определяется параметрами, значения которых задаются
в завершающих строках листинга:
• angle - максимальный угол ветви по отношению к родителю;
• branch - максимальное количество ростков (дочерних ветвей) для любой
ветви;
58 Глава 1. Визуальные эффекты

• trunkThickness - толщина ствола дерева;


• trunkLength - длина ствола дерева;
• branchSize - отношение размеров дочерней и родительской ветвей (ветви
уменьшаются по мере удаления от ствола).
Сначала мы создаем ствол и задаем его позицию, после чего назначаем функцию
grow() обработчиком события onEnterFrame. Как подсказывает само название,
функция grow() «выращивает» пустое дерево в нашем клипе, для чего она
выполняет две операции. Сначала функция создает исходную ветвь, рисуя
вертикальную линию высотой trunkLength и толщиной trunkThickness. Если в на-
стоящее время рисуется ствол, он оставляется в первоначальном виде (фаза 1).
Если же рисуется ветвь, она поворачивается на угол +/- angle (фаза 2) и мас-
штабируется с коэффициентом branchSize (фаза 3); все эти фазы показаны
на рис. 1.29.

trunkThickness angle

Масштабирование
с коэффициентом branchSize

trunkLength

1 2 3
Рис. 1.29. Фазы построения ветви

Затем функция создает от 1 до branch новых «ростков». Весь фокус в том, что
ростки получают тот же обработчик onEnterFrame, что и текущий, а именно grow(),
поэтому в следующем кадре они отращивают собственные ростки и т. д. Здесь
используется фрагмент кода, который создает новый анимационный клип для
каждого ростка и назначает ему обработчик события onEnterFrame. Дерево могло
бы создавать новые ростки до бесконечности, но процесс необходимо как-то
ограничить, иначе Flash будет работать все медленнее и в итоге просто «завис-
нет». Чтобы предотвратить эту ситуацию, функция counterQ ограничивает об-
щее количество ветвей пороговым значением 3000:
var seed = Math.cei1(Math.randomC)*branch);
for (var i = 0; i < seed: i++) {
i f (counterO < 3000) {
var segment = this.createEmptyMovieClip("segment" + i . i ) ;
segment.onEnterFrame = grow:
segment.+y = trunkLength: }
}
В завершение grow() удаляет себя, поскольку она должна выполняться только
один раз для каждой ветви.
Имитация движения дерева 59

Итак, мы используем функцию, которая вызывает сама себя (а точнее, создает


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

ТРЮК Имитация движения дерева


№7 Применение кинематики на базе анимационных клипов.

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


стало время немного оживить статическую картинку. При движении дерева под
ветром используется та же иерархия, которая была использована при его по-
строении. Лично мне понадобилось некоторое время, чтобы осознать этот факт,
но зато потом все становится совершенно очевидно:
• при перемещении ствола перемещается все дерево;
• при перемещении ветви перемещаются все ее дочерние ветви.
Но чтобы сообразить, на какую величину должна перемещаться каждая часть
дерева, придется немного подумать. Сначала я решил, что ствол движется гораз-
до меньше ветвей кроны, но это не так. Чтобы убедиться в этом, воткните в зем-
лю ветку (обрезанную в точке ветвления) во время ветра. Вы увидите, что по
величине смещения она практически не отличается от ствола дерева. Ветка об-
ладает большей гибкостью, но площадь ее поверхности (если у нее нет листьев)
меньше, чем у ствола, поэтому давление ветра тоже пропорционально уменьша-
ется.
Ветвь кроны дерева перемещается сильнее, чем ствол, просто потому, что все
ветви в нижележащей иерархии тоже движутся и величина их перемещений
суммируется при перемещении всего дерева. Вот так! Каждый день узнаешь
что-то новое.
Сделанный вывод позволяет легко реализовать эффект ветра - просто нужно
обработать каждую ветвь по тем же правилам, что и ствол с другими ветвями.
Вместо удаления каждого обработчика onEnterFrame, как это было сделано в ис-
ходном коде построения дерева (см. трюк 6), мы изменим соответствующую
строку grow():
delete (this.onEnterFrame);
и заменим ее назначением функции sway() после «выращивания» ветви:
this.onEnterFrame = sway;
60 Глава 1. Визуальные эффекты

Чтобы имитировать эффект ветра, достаточно создать функцию sway(), которая


в каждом из кадров будет прибавлять к текущей ветви дополнительное сме-
щение:
function sway О {
this._rotation += wind;
}
Величина смещения должна изменяться; один из способов добиться желаемого
эффекта выглядит так:
function sway О {
wind += windEffect:
i f (wind > windStrength) {
wind = -wind;
}
this._rotation += wind:
}
Разумеется, мы должны задать начальные параметры ветра. Для нашего приме-
ра я подобрал следующий набор параметров (новые значения выделены жир-
ным шрифтом):
// Параметры дерева
var angle = 100:
var branch = 5: „
var trunkThickness = 8;
var trunkLength = -100;
var branchSize = 0.7;
// Параметры ветра
var windEffect = 0.05;
var windStrength = 1;
var wind = 0;
Также можно создать бегунки для ручной регулировки параметров в интерак-
тивном режиме (см. трюк 61).
На рис. 1.30 показано дерево, склонившееся на ветру. Загрузите файл treeO2.fla
с сайта книги, чтобы увидеть анимированную графическую версию во всей
красе.

Итоги
Хотя в представленном решении задействована пара неочевидных моментов, под
«трюком» здесь следует понимать скорее общий подход. Копирование живой
природы или других объектов, оказавшихся под рукой, — испытанный путь по-
иска новых идей и решений для Flash-дизайна.
Flash является средой графического программирования; именно это обстоятель-
ство делает возможным такие эксперименты, как в нашем решении. Вы можете
написать программу и немедленно получить графическую обратную связь. Если
Имитация движения дерева 61

потребуется создать несколько деревьев, поэкспериментируйте и посмотрите,


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

ив в ••
- : •

1
I

Рис. 1.30. Дерево на ветру

И все же моя личная муза - не природа, а видеоигры. Подозреваю, что все


проблемы, с которыми сталкиваются дизайнеры, уже давно встречались разра-
ботчикам видеоигр и были успешно решены ими... но это, как говорится, совсем
другая история.
ГЛАВА 2

Цветовые эффекты
Трюки № 8-13
Как правило, Flash-дизайнеры при создании анимации уделяют основное вни-
мание движению и масштабированию, однако цвет также может быть объектом
анимации для создания различных эффектов и переходов.
Для дизайнера анимация цвета интересна прежде всего тем, что она позволяет
с минимальными усилиями (и практически без увеличения файла) изменить вне-
шний вид и атмосферу. Изменением цветовой схемы анимаций Flash реализует-
ся широкий спектр эффектов - например, смена дня и ночи. Приданием изобра-
жению сепийных оттенков создается эффект «ретро», а цветовая гамма «электрик»
может использоваться для имитации более современного стиля «техно».
Изменения цвета могут применяться ко всему, что инкапсулируется в анимацион-
ных клипах, включая растровые изображения, видеоклипы и векторную графику.
В сущности, все, что отображается на сцене Flash, может стать объектом цвето-
вой анимации, управляемой посредством кадрирования (то есть на временной
диаграмме во время разработки) или ActionScript (на стадии выполнения).
Это обстоятельство упрощает применение цветовых эффектов на стадии выпол-
нения и позволяет сделать контент более привлекательным при минимальном
увеличении объема передаваемых данных. Вы узнаете, как при помощи цвето-
вых эффектов сделать растровое изображение более оригинальным, привести
его к цветовой гамме сайта и даже реализовать некоторые возможности видео
для статических растровых изображений.
Также мы рассмотрим, как применение цветовых переходов к видео субъектив-
но удлиняет короткий повторяющийся клип и делает его более интересным.
Учитывая, что пересылка видеоданных обычно сильнее всего загружает каналы
связи, вы также можете оптимизировать процесс загрузки видео за счет добавле-
ния сложных переходов на стадии выполнения (вместо их применения в исход-
ном видеоматериале).
Файлы SWF принадлежат к числу немногочисленных графических веб-ресур-
сов, у которых цвет обходится «бесплатно» - прибавление множества цветов
к Flash-сайту не создает дополнительной нагрузки на канал связи. Впрочем, су-
ществует и оборотная сторона: при такой свободе выбора вам придется действо-
вать более внимательно. По этой причине мы рассмотрим несколько новых спо-
собов управления цветом и быстрого создания палитр.
Применение цветовых эффектов к видео 63

Наконец, любой обзор работы с цветом в Flash будет неполным без упоминания
ActionScript. Сценарии существенно расширяют возможности цветовой анима-
ции. Мы рассмотрим способы создания нестандартных цветовых эффектов на
объектно-ориентированном коде ActionScript 2.O.

Применение цветовых эффектов


ТРЮК

№8 к видео
Имитация видеоперехода с использованием цветовых эффектов Flash.
В этом трюке класс Color используется для изменения видеоклипа и создания
уникального цветового перехода. Методика не является очевидной, а видеопере-
ходы обычно реализуются другими средствами, но суть трюков как раз и заклю-
чается в том, чтобы исследовать все неочевидное.

Как помочь плохому танцору


Всегда можно с уверенностью сказать, когда снимающийся в видеоклипе танцор
не умеет нормально двигаться. В таких случаях постановщик клипа часто пере-
мещает камеру или добавляет множество видеопереходов и эффектов, синхро-
низированных с музыкой. В результате движение на экране обретает нужный
ритм, даже если вся группа стоит на месте и кдвает головами в стиле 70-х годов.
Аналогичная проблема возникает с клипами Flash: пересылка видеоданных ин-
тенсивно загружает канал связи, а для достижения максимального коэффициен-
та сжатия приходится создавать последовательности с относительно малыми раз-
личиями между кадрами. Большинство кодеков, в том числе и кодек Sorenson,
используемый во Flash, выполняет как пространственное, так и временное сжа-
тие. Пространственное сжатие основано на поиске повторяющихся областей внут-
ри кадра (например, однородные черные фоны сжимаются очень хорошо). Вре-
менное сжатие основано на анализе смежных кадров и сохранении дельты
(информации об изменениях) между кадрами. По этой причине в видеоклипах
лучше оставить как можно меньше масштабного движения, чтобы разностные
кадры, связанные дельтами, занимали как можно меньший объем. (Можно про-
вести другую, более привычную аналогию: разностные кадры напоминают клю-
чевые кадры в анимации на временной диаграмме Flash. Как видите, принцип
кадрирования действует не только в анимации, но и в видео.) Ключевые кадры
видео используются для сохранения качества изображения и решения проблем
в тех ситуациях, когда из-за слишком больших различий между кадрами коди-
рование дельт становится неэффективным.
Получается, что мы не можем включить в видео слишком много движения без
значительного увеличения объема загружаемых видеоданных.
Решение проблемы, как и в истории с музыкальным клипом, заключается в до-
бавлении «внешнего» движения или эффектов. Мы применяем эффекты на про-
граммном уровне на стадии выполнения (на стороне клиента), чтобы они не
влияли на сжатие видео (то есть не увеличивали объем загружаемых данных)
из-за появления больших различий между кадрами.
64 Глава 2. Цветовые эффекты

ПРИМЕЧАНИЕ
Чтобы уменьшить объем анимации, не утомляя зрителя, следует на программ-
ном уровне внести изменения, отсутствующие в исходном видеоматериале.

Например, применение видеоэффектов на стадии выполнения помогает скрыть


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

Кодирование цветов
Возможно, вам доводилось применять цветовые эффекты к видеоклипам при
помощи диалогового окна Advanced Effect (рис. 2.1). А если не доводилось, рас-
смотрим несложный пример цветовой анимации:
1. нарисуйте черный круг на сцене в первом кадре и преобразуйте его в символ
анимационного клипа (F8).
2. вставьте в кадре 10 ключевой кадр (выделите кадр 10 на главной временной
диаграмме и выполните команду Insert • Timeline • Keyframe).
3. щелкните на ключевом кадре 1 и примените к экземпляру анимацию движе-
ния (задайте на панели свойств параметру Tween значение Motion).
4. щелкните на ключевом кадре 10. Активизируйте инструмент Selection и щел-
кните на сцене, чтобы снять выделение с кадра. Наконец, щелкните на экзем-
пляре клипа на сцене, чтобы выделить его.
5. выберите в списке Color на панели свойств строку Advanced.
6. щелкните на кнопке Settings на панели свойств; на экране появляется диало-
говое окно Advanced Effect. Задайте параметру rb значение 200, как показано
на рис. 2.1. Закройте диалоговое окно кнопкой ОК.
Если медленно перемещать индикатор текущей позиции по первым 10 кадрам
временной диаграммы, вы увидите, как цвет клипа медленно переходит от чер-
ного к красному то есть, фактически, происходит цветовой переход (если при
кадрировании была допущена ошибка, клип останется черным до кадра 9, а за-
тем внезапно станет красным на кадре 10).
Все это, конечно, хорошо. Но как применить цветовой переход к видео на стадии
выполнения? Класс Color позволяет применять аналогичные преобразования к лю-
бым анимационным клипам, в том числе и к содержащим видеоклипы. Метод
Color.setTransform() получает один аргумент - объект преобразования со свой-
ствами га, да, ba, aa, rb, gb, bb и ab.
Объект преобразования (transObject) представляет собой экземпляр класса Object
со свойствами, используемыми для выполнения цветовых преобразований. Во-
семь свойств объекта просто соответствуют значениям восьми полей диалогово-
го окна Advanced Effect на рис. 2.1. Чтобы понять смысл свойств, поэксперимен-
тируйте с изменением параметров в окне Advanced Effects.
Применение цветовых эффектов к видео 65

Мо-леОр у C_i«y: И ancec vj


::::-.::.::':.,.

•Л: 3~ 5 ),: 69.0 О


М;;| 37.5 [yv 123.0 Advanced Effect

Га !; • Rei - ; 1004, vj xR} + •rb

ga—^ufeer,-{ :oo«. v лс>+ о ^ S i i — g b

Ьа I • Bee- ( :>''; У «B)t 0

Рис. 2 . 1 . Настройка цветовой трансформации в диалоговом окне Advanced Effect

Ручное применение цветовых эффектов к растровому фотографическому изоб-


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

Цветовые видеопереходы
В следующем трюке реализуется один характерный тип преобразований - мгно-
венные эффекты (например, когда нормальный цветной клип резко превращает-
ся в фотографический негатив, остается им в течение нескольких кадров, а затем
возвращается к исходному состоянию). Эффект выглядит весьма впечатляюще,
особенно если синхронизировать его со звуком (см. трюк 59). Методика может
быть расширена для создания другой категории эффектов: наплывов и других
постепенных преобразований (см. трюк 9).
Начнем с мгновенных эффектов. На рис. 2.2 показано исходное изображение,
а на рис. 2.3 и 2.4 - два возможных эффекта.

Рис. 2.2. Исходное изображение (нейтральное преобразование)

Исходное изображение на рис. 2.2 использует нейтральное преобразование с па-


раметрами
{га:100. гЬ:О. да:100. gb:O. ba:100. bb:O. aa:100. ab:O}
Глава 2. Цветовые эффекты

Рис. 2.3. Инвертированное изображение

Рис. 2.4. Контрастное изображение

На рис. 2.3 представлено инвертированное изображение с преобразованием


(га:-100. rb:255. да:-100. gb:255. Ьа:-100. bb:255. аа:100, ab:0}
Однако негатив не исчерпывает всех возможных вариантов. Сценарные преоб-
разования позволяют преодолеть ограничения, накладываемые диалоговым ок-
ном Advanced Effect. На рис. 2.4 изображено контрастное преобразование
{га:500. rb:-500. ga:500. gb:-500. ba:500. bb:-500. аа : 100. ab:0}
Также можно создавать и другие эффекты - например, эффект осветления, при
котором изображение кажется «передержанным». Осветление производится пре-
образованием вида
{га:100. rb:150. да:100. gb:150. Ьа:100. bb:150. аа:100. ab:0}
Следующее преобразование усиливает красные оттенки:
{га:500. rb:-500. да:100. gb:0. ba:100. bb:0. aa:100. ab:0}
Наконец, снижение яркости производится преобразованием
{га:100. rb:-150. ga:100. gb:-150. Ьа: 100. bb:-150. аа:100. ab:0}
Чтобы лучше понять суть упомянутых эффектов, запустите файл colortransforms.fla
из архива примеров.
Следующий фрагмент применяет мгновенную инверсию к содержимому ани-
мационного клипа:
function negativeF1ick(targetClip. duration) {
Применение цветовых эффектов к видео 67

thi s.neutralizer = function О {


negColor.setTransform(neutral);
// Обновление экрана
updateAfterEventO:
// Сброс интервала
clearlnterval(neglnterval);
}:
// Определение преобразования, инвертирующего текущие цвета
var negTrans = {га:-100. rb:255. да:-100. gb:255.
Ьа:-100. bb:255. aa:100. ab:0}:
//Определение нейтрального преобразования для отмены эффекта
var neutral {ra:100. rb:0. да:100, gb:0. Ьа:100. bb:O. aa:100. ab:0}:
// Выбор клипа и применение преобразования
var negColor = new Color(targetCTip);
negColor.setTransform(negTrans);
// Назначение функции обратного вызова для отмены эффекта
// по истечении заданного интервала
var neglnterval = setlnterval(this.neutralizes duration);
}
Следующая строка на одну секунду применяет эффект инверсии к клипу bitmapClip;
предполагается, что мы ранее создали этот клип, содержащий растровое изобра-
жение (проследите за тем, чтобы клипу было присвоено имя экземпляра bitmapClip
на панели свойств):
negativeFl ickCbitmapCl ip. 1000):
Чтобы применить эффект к видео, следует вызвать negativeFlick() с именем со-
ответствующего клипа. В следующем примере эффект применяется к клипу
myVideojmc на две секунды (2000 мс). Как и в предыдущем случае, имя экземп-
ляра для клипа (который, как предполагается, содержит видеоинформацию)
назначается на панели свойств:
negativeFl1ck(myVideo_mc. 2000):
Как правило, сценарий с определением функции negativeFlick() и ее вызовом
присоединяется к отдельному слою actions.
Для вызова negativeFlickQ с временной диаграммы видеоклипа myVideojnc мож-
но воспользоваться вызовом
negativeFlickCthis. 2000):
Функция negativeFlick() создает экземпляр Color и использует его для примене-
ния преобразования к целевому клипу. В последней строке negativeFlick() также
задается интервал вызова neutralize^). Функция neutralize^) отменяет выполнен-
ное преобразование посредством применения нейтрального преобразования. Далее
программа сбрасывает интервал таймера - если этого не сделать, вызовы будут
периодически повторяться.
Обратите внимание: функция setlntervalQ не связана напрямую с частотой сме-
ны кадров, поэтому функция обратного вызова (в данном случае neutralize^))
обычно выполняется перед другими событиями уровня кадров (такими, как
onEnterFrame). При создании графических эффектов с применением setlnterval()
вся выгода от использования внекадровых событий теряется, если нам придется
68 Глава 2. Цветовые эффекты

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


этой причине вызов updateAfterEvent() решает проблему, обновляя экран в конце
функции обратного вызова.
В этом трюке были представлены ключевые моменты применения цветовых пре-
образований к видеоклипам:
• использование объекта цветового преобразования для изменения цветовой
гаммы видеоклипа;
• использование интервалов и функций обратного вызова для внесения вре-
менных изменений;
• использование нейтрального цветового преобразования для восстановления
исходных цветов.
Представленная методика применима не только к видео, но и к любым анимаци-
онным клипам и даже к главной временной диаграмме. Более того, сброс цвето-
вой схемы с применением нейтрального преобразования тоже не обязателен.
Например, вы можете периодически примерять случайные цветовые преобразо-
вания, для этого функция обратного вызова должна сгенерировать случайные
значения свойств объекта преобразования (вместо применения нейтрального
преобразования).

Растворение видео на черном


ТРЮК

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

Протяженные эффекты
Для реализации протяженных переходов нам понадобится структура данных,
позволяющая вносить поэтапные изменения в параметры цветового преобразо-
вания за несколько кадров. На практике часто встречаются эффекты растворе-
ния видео на черном и белом фоне. Итоговые объекты преобразований для та-
ких эффектов выглядят так:
transToBlack={ra:100. rb:-255. да:100. gb:-255.
Ьа:100. bb:-255. aa:100. ab:0}:
transToWhite={ra:100. rb:255. да:100. gb:255.
ba:100. bb:255. aa:100. ab:0}:
Обратите внимание: смещения у этих преобразований совпадают, отличается
только знак (+255 или -255). В результате мы либо прибавляем к каждому пик-
селу значение RGB с компонентами (255, 255, 255) (растворение на белом фоне),
Растворение видео на черном и белом фоне 69

либо вычитаем его (растворение на черном фоне). Поскольку каждый из трех


цветовых каналов принимает значения из интервала от 0 до 255 (от 0 х 00 до 0 х FF
в шестнадцатеричной записи), пиксел принимает значение 255 (белый) или 0 (чер-
ный) независимо от его исходного цвета.
Следующий фрагмент кода позволяет растянуть изменение цвета на заданное
количество кадров, чтобы растворение происходило постепенно:
function transCtargetClip. frames, targetTrans) {
var transCol = new Color(targetClip);
// Получение текущего преобразования, примененного к клипу
var getTrans = transCol .getTransformO;
var diffTrans = new ObjectO;
// Вычисление разности для каждого из 8 свойств
// и ее сохранение в цветовом объекте diffTrans
for (var i in targetTrans) {
d i f f T r a n s [ i ] = (targetTrans[i]-getTrans[i])/frames: •
}
targetClip.onEnterFrame=function() {
var getTrans = transCol .getTransformO;
for (var i in diffTrans) {
getTrans[i] += d i f f T r a n s [ i ] ;
}
transCol.setTransform(getTrans);
frames--;
i f (frames == 0) {
// Явно задать итоговое преобразование на случай, если
// целевые числа не кратны числу кадров, затем
// выполнить зачистку.
transCol.setTransform(targetTrans);
delete this.onEnterFrame;
delete transCol;

Для анимации цветового перехода необходимо знать три параметра: целевой


клип (в который встроен видеоматериал), продолжительность перехода в кадрах
и тип перехода (растворение на черном или белом фоне, а точнее - соответству-
ющий объект цветового преобразования).
Вся необходимая информация передается в аргументах функции trans(): targetClip,
frames и targetTrans. Например, следующий вызов определяет эффект растворе-
ния на белом фоне для видео в клипе myVideojnc на протяжении 24 кадров:
transToWhite = {га:100. rb:255. да:100. gb:255, Ьа:100. bb:255. aa:100. ab:0};
transdnyVideojnc. 24. transToWhite):
Функция trans() решает три задачи.
Сначала она получает текущий объект цветового преобразования, примененный
к целевому клипу, при помощи функции Color.getTransformO и сохраняет его
в переменной getTrans. Затем она создает объект diffTrans, свойства которого опре-
деляют величину приращения getTrans на каждом кадре для получения итогового
70 Глава 2. Цветовые эффекты

преобразования targetTrans за заданное количество кадров. Если в среде разра-


ботки не применялись другие преобразования, переменная getTrans всегда равна
{га:100. rb:0. да:100. gb:0. Ьа:100. ЬЬ:0. аа:100. ab:0}
Почему? При отсутствии преобразований getTrans определяет объект нейтраль-
ного преобразования - тот самый, параметры которого отображаются на панели
Advanced Effects (рис. 2.1) при отсутствии определенных преобразований.
Переменная targetTrans содержит целевое преобразование, заданное при вызове
функции transQ. Для эффекта растворения на белом фоне она выглядит так:
{га:100. rb:255. да:100. gb:255. Ьа:100. bb:255. aa:100. ab:0}
Вычитание targetTrans из getTrans и деление результата на количество кадров
дает приращение, применяемое к клипу на каждой итерации. Мы сохраняем его
в объекте diffTrans:
diffTrans[i] = (targetTrans[i]-getTrans[i])/frames;
В нашем примере с 24-кадровым переходом будет получен следующий объект
diffTrans:
{га:0. гЬ:10.625. да:0. дЬ:10.625. Ьа:0. bb:10.625, aa:0. ab:0}
Напоследок функция trans() должна настроить обработчик onEnterFrame, чтобы
обеспечить анимацию цветового перехода от getTrans до targetTrans с течением
времени. Для этого мы определяем функцию и присваиваем ее свойству on Enter
Frame, как показано в предыдущем фрагменте.
Честно говоря, определять продолжительность перехода в кадрах не очень ло-
гично. При воспроизведении видеоматериалов обычно используются временные
единицы измерения, поэтому многошаговое цветовое преобразование лучше при-
менять по отношению к интервалам заданной продолжительности (определен-
ным функцией setlnterval).
Таким образом, методика покадрового изменения больше подходит для приме-
нения цветовых переходов к анимационным клипам, не содержащим видеоин-
формации. Однако методика повременного изменения уже была продемонстри-
рована ранее (см. трюк 8), поэтому давайте внимательнее присмотримся к по-
кадровой методике.
Обработчик onEnterFrame, определенный внутри trans(), на каждом кадре при-
бавляет приращение diffTrans к текущему объекту преобразования вплоть до за-
вершения эффекта:
for (var i in diffTrans) {
getTrans[i] += diffTrans[i];
} -
transCol.setTransform(getTrans);
Нельзя исключать того, что в конце перехода преобразование не достигнет ко-
нечного состояния из-за ошибок округления, поэтому для надежности нужно
задать его явно. После этого остается лишь выполнить необходимую зачистку
(деинициализацию).
Растворение видео на черном и белом фоне 71

frames--;
if (frames == 0) {
// Явно задать итоговое преобразование на случай, если
// целевые числа не кратны числу кадров, затем
// выполнить зачистку.
transCol.setTransform(targetTrans);
delete this.onEnterFrame;
delete transCol;
}
Попробуйте выполнить сценарий с другими видами преобразований, встречаю-
щихся в этом и предыдущих трюках.

Итоги
Два последних трюка интересны прежде всего тем, что они могут применяться
к любому анимационному клипу, а не только к клипам, содержащим видеомате-
риалы. Например, применение их к _root позволяет применять преобразования
ко всему SWF-файлу во время выполнения (хотя в некоторых ситуациях такой
вариант непрактичен из-за чрезмерной загрузки процессора). Помимо создания
впечатляющих эффектов, цветовые переходы также находят практическое при-
менение: инвертирование цвета всего содержимого сцены на 100 мс может стать
сигналом о неправильной реакции пользователя (при включении так называе-
мых специальных возможностей система Windows при выдаче сообщения об
ошибке ненадолго изменяет цвет экрана, потому что пользователи с дефектами
слуха могут не расслышать звуковой сигнал).
Добавление «видеоподобных» цветовых переходов к статической графике (ска-
жем, к растровым изображениям) обладает другим большим преимуществом: вы
можете «обмануть» пользователя и заставить его думать, что он смотрит ви-
део, - особенно если действовать хитро и разбавить последовательность реаль-
ными видеофрагментами. Эта методика способна творить настоящие чудеса, осо-
бенно для маскировки предварительной загрузки видео!
Вероятно, самые наблюдательные читатели заметили, что во всех представлен-
ных примерах данные альфа-канала оставались неизменными. Чтобы отрегули-
ровать альфа-канал, просто задайте объект преобразования, у которого свойства
га, да, Ьа или аа не равны 100. Изменение альфа-канала позволяет реализовать
такие профессиональные эффекты, как перекрестное растворение, то есть плав-
ный переход от одного видеоклипа к другому (а еще лучше - переход видеокли-
па в векторную графику Flash). Альфа-переходы интенсивно расходуют ресурсы
процессора, но, к счастью, Flash Player 7 обладает гораздо более производитель-
ным механизмом воспроизведения видео, поэтому и эта проблема перестала быть
такой серьезной.
Аналогичные принципы справедливы для звуковых преобразований. Объект зву-
кового преобразования, представленный классом Sound, позволяет создавать сце-
нарные эффекты изменения громкости и баланса (трюк 60).
72 Глава 2. Цветовые эффекты

Пользовательский класс цветового


ТРЮК

№10 преобразования
Создание пользовательского класса для выполнения цветовых преобра-
зований.
Как было показано в двух последних трюках, существует целый ряд стандарт-
ных цветовых преобразований (см. трюк 8), которые часто применяются к целе-
вым клипам. Более того, вы уже знаете, что это требует определенных вспомога-
тельных действий, включая настройку таймеров и функций обратного вызова
(см. трюк 9). Специфика задачи наводит на мысль о том, что она хорошо подхо-
дит для оформления в виде пользовательского класса. Класс позаботится обо
всех служебных операциях и позволит выполнить цветовое преобразование про-
стым вызовом нескольких методов. В этом трюке пользовательский класс цветово-
го преобразования будет реализован на ActionScript 2.0 средствами объектно-
ориентированного программирования (ООП) вместо процедурного кода времен-
ной диаграммы, использовавшегося в предыдущих трюках.

Объектно-ориентированное преобразование
ActionScript 2.0 работает только в Flash MX 2004 или Flash MX Professional
2004. Кроме того, необходимо выбрать ActionScript 2.0 на вкладке Flash диалого-
вого окна File • Publish Settings. Более того, разработанный нами класс Transform
должен храниться во внешнем текстовом файле Transform.as (и регистр симво-
лов имени, и расширение .as являются обязательными). В Flash MX Professional
2004 для создания и редактирования таких файлов можно использовать коман-
ду File • New • ActionScript File. B Flash MX 2004 вам потребуется внешний тек-
стовый редактор (см. трюк 74). Файл .as должен находиться в одной папке с фай-
лом .fla, использующим класс Transform.
Хотя я не смогу привести полный курс ООП и ActionScript 2.0, для использова-
ния класса цветового преобразования не обязательно разбираться в тонкостях
ООП. Некоторые ключевые аспекты кода рассматриваются после листинга.
Далее приводится объектно-ориентированная версия, реализованная в виде поль-
зовательского класса Transform; этот класс должен храниться во внешнем файле
Transform.as.
// Этот код ActionScript 2.0 должен храниться во внешнем файле Transform.as
class Transform {
// NEG_TRANS - инвертирование цветовых значений.
// NEUTRAL_TRANS - сброс цветовых значений.
II BLACK_TRANS - замена цветовых значений черными пикселами.
// WHITE_TRANS - замена цветовых значений белыми пикселами.
// RATE - скорость применения эффекта в миллисекундах.
private s t a t i c var NEG_TRANS:Object = {га:-100. rb:255.
ga:-100. gb:255. ba:-100. bb:255. aa:100. ab:O};
private s t a t i c var NEUTRAL_TRANS:Object = {ra:100. rb:O.
ga:100. gb:O. ba:100. bb:O. aa:100. ab:O};
Пользовательский класс цветового преобразования 73

private static var BLACK_TRANS:Object = {га:100. rb:-255.


ga:100. gb:-255. ba:100. bb:-255. aa:100. ab:0};
private static var WHITEJRANS: Object = {га: 100. rb:255.
ga:100. gb:255. ba:100. bb:255. aa:100. ab:0}:
private static var RATE:Number = 50;
private var interval:Number;
private var startTime:Number;
private var colorObj:Color;
// Конструктор получает целевой клип, к которому
// применяется преобразование.
public function Transform(targetClip:MovieClip) {
colorObj = new Color(targetClip);
}
// Инвертирование цветовых значений
public function invert(duration:Number):Void {
applyTransform(NEG_TRANS, duration);
}
// Восстановление стандартных цветовых значений,
// заданных в среде разработки,
public function reset(duration:Number):Void {
applyTransform(NEUTRAL_TRANS. duration);
}
// Реализация эффекта растворения на черном фоне
// в течение заданного интервала в миллисекундах
public function fadeToBlack(duration:Number):Void {
applyTransform(BLACK_TRANS. duration):
}
// Реализация эффекта растворения на белом фоне
// в течение заданного интервала в миллисекундах
public function fadeToWhiteCduration:Number):Void {
applyTransform(WHITE_TRANS. duration);

// Функция инициирует эффект растворения и задает его продолжительность,


private function applyTransform(transObject:Object,
duration:Number):Void {
var getTrans:Object = colorObj.getTransform( );
var diffTrans:Object = new Object( );
startTime = getTimer( );
for (var i in transObject) {
diffTrans[i] = (transObject[i] - getTrans[i]) / (duration / RATE);
}
// Используется форма setlntervaK). которая вызывает метод объекта.
// поэтому свойства экземпляра доступны (обращение через объект this)
// Первый параметр - объект (this), для которого вызывается метод.
// заданный вторым параметром (в данном случае "transition")
// и передаваемый в строковом виде.
// Третий параметр - интервал в миллисекундах.
// Четвертый, пятый и шестой параметры передаются transitionO.
74 Глава 2. Цветовые эффекты

interval = set Interval(this, "transition". RATE. transObject.


diffTrans. duration);

// Метод применяет каждый шаг цветового преобразования.


private function transition(transObject:Object. diffTrans:Object.
duration:Number):Void {
var getTrans:Object = colorObj.getTransforrrK );
for (var i in diffTrans) {
getTrans[i] += di ffTransCi 3:
}
col orObj.setTransform(getTrans);
i f (getTimer( ) - startTime > duration) {
// Завершение последнего шага перехода
colorObj.setTransform(transObject):
// Сброс интервала (остановка эффекта)
clearlnterval(interval):
}
// Принудительное обновление экрана между кадрами
updateAfterEvent( );
public function die( ):Void
// Завершающие действия

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


Но сначала стоит ответить на один вопрос: почему методы пользовательского
класса Transform не были добавлены в класс MovieClip или Color? В ActionScript
1.0 такое решение было бы вполне обычным и даже предпочтительным. Однако
в ActionScript 2.0 вместо расширения существующих классов рекомендуется соз-
давать пользовательские классы.
Если вы еще не знакомы с синтаксисом ActionScript 2.0, обратите внимание на
ключевое слово class, использованное для определения класса. В классе объяв-
ляется несколько переменных за пределами всех модулей. Статические свой-
ства, также называемые свойствами уровня класса, определяются с ключевым
словом static и существуют в единственном числе (в нашем примере таким обра-
зом инициализированы различные типы преобразований и интервал между об-
новлениями RATE, равный 50 мс).
Остальные свойства, объявленные без ключевого слова static, являются свой-
ствами экземпляров (то есть каждый экземпляр класса содержит собственную
копию свойства). Ключевое слово private означает, что данное статическое свой-
ство или свойство экземпляра недоступно за пределами класса. Переменные,
объявленные внутри методов (такие, как переменная getTrans, объявленная внутри
метода applyTransform), являются локальными. Типы данных всех переменных,
свойств, параметров и возвращаемых значений методов задаются в синтаксисе
«двоеточие + тип» (например, :Number).
Хорошим тоном в программировании считается использование стандартизиро-
ванных схем выбора имен переменных во всей программе, но благодаря точному
Пользовательский класс цветового преобразования 75

структурированию и типизации данных в ООП эти правила не столь важны.


Имена констант (например, статических полей) записываются В ВЕРХНЕМ РЕ-
ГИСТРЕ, а для записи имен «полноценных» переменных используется схема
«camelCase» (особая смесь символов верхнего и нижнего регистров).
Теперь обратите внимание на функцию-конструктор TransformQ (в ActionScript
2.0 эта функция не обязательна), используемую для инициализации экземпля-
ров класса. В нашем примере конструктору передается целевой клип, который
позднее будет использоваться другими методами класса. Затем класс определя-
ет несколько открытых методов, которые могут вызываться извне для экземпля-
ров класса (скажем, invert() или fadeToWhiteO), а также приватных методов, пред-
назначенных только для внутреннего использования.
Обратите внимание на форму вызова setlntervalQ. В данном примере в первом
параметре должен передаваться объект. Мы передаем ключевое слово this, пред-
ставляющее текущий объект (то есть экземпляр класса Transform, для которого
был вызван метод applyTransform()). Во втором параметре передается имя метода,
вызываемого для this, а именно "transition" (имя должно задаваться именно так,
в строковом виде). Итак, в положенный момент времени метод Transform.transitionQ
будет вызван для текущего экземпляра this. Вызов метода для текущего экземп-
ляра гарантирует, что свойства экземпляра (такие, как interval и colorObj) будут
доступны внутри transitionQ. Четвертый и пятый параметры setlnterval(), diffTrans
и duration, передаются методу transitionQ при его вызове. Метод transition() вы-
полняет заданный переход за заданный промежуток времени и сбрасывает ин-
тервал таймера после завершения.
Чтобы использовать класс в своей программе, сначала создайте экземпляр клас-
са Transform, как показано далее (где myVideojnc - существующий анимацион-
ный клип, имя экземпляра которого было задано на панели свойств):
var transformer:Transform = new Transform(myVideo_mc):
Затем вызовите для полученного объекта transformer нужные методы класса:
transformer.invert(3000); // Инверсия цветов на 3 секунды
transformer.fadeToWhite(2000); // Растворение на белом фоне за 2 секунды
Зачистка после завершения работы с объектом выполняется следующим фраг-
ментом:
transformer.die():
delete transformer;
Попробуйте усовершенствовать этот класс и реализовать в нем дополнительные
возможности:
• предоставьте пользователю возможность изменять значение RATE;
• добавьте элементы для повторения перехода. Это позволит применять мига-
ние и другие повторяющиеся эффекты;
• определите более сложные методы для реализации растворения одного кли-
па в другом.
Применение ActionScript 2.0 позволяет создавать новую функциональность и ра-
ботать с ней методами новых классов. Так создаются библиотеки часто исполь-
зуемых возможностей, не реализованных на уровне базового языка ActionScript.
76 Глава 2. Цветовые эффекты

Некоторым разработчикам объектно-ориентированный стиль ActionScript 2.0


может показаться недостаточно компактным, поскольку определение структуры
кода содержит едва ли не больше строк, чем непосредственное решение задачи
(это особенно заметно для небольших классов). Однако в долгосрочной перс-
пективе дополнительное структурирование имеет свои преимущества: гибкость
кода упрощает его использование в разных приложениях и передачу другим
пользователям (последнее особенно удобно в рабочих группах, состоящих из
одного программиста в ActionScript и нескольких дизайнеров, не владеющих
навыками программирования).
И еще одно обстоятельство: хотя объектно-ориентированный код вроде бы зани-
мает больше места, чем в других стилях программирования, откомпилирован-
ный байт-код может оказаться более эффективным (см. трюк 100). Flash Player 7
оптимизирован для объектно-ориентированного кода. Сравнительный хрономет-
раж хорошо написанного объектно-ориентированного и процедурного кода Action
Script показывает, что ООП повышает быстродействие за счет усиленного ис-
пользования локальных переменных и передачи данных в аргументах: и то, и дру-
гое повышает эффективность сгенерированного байт-кода.

Создание и упорядочение
ТРЮК

№ 1 1 пользовательских каталогов цветов


Сохранение и организация каталогов цветов без использования панели
Color Swatches.
Цветовая схема является одним из важнейших факторов, определяющих общее
впечатление и эмоциональное воздействие Flash-сайта. Текущую палитру с па-
нели Color Swatches можно сохранить в виде набора цветов Flash (CLR-файл).
Тем не менее, работать с цветами на панели Color Swatchers (например, сгруппи-
ровать их удобным для вас способом) не так легко, как хотелось бы.
Конечно, ничто не мешает вам создать собственный каталог цветов. Просто соз-
дайте слой с именем swatches, преобразуйте его в опорный слой (команда
Modify • Timeline • Layer Properties • Type • Guide) и разместите несколько прямо-
угольников для хранения цветов. Художник выделяет отдельный участок па-
литры и пробует на нем краски, прежде чем наносить их на холст; вы тоже
можете создать сколько угодно цветовых образцов и упорядочить их по своему
усмотрению. Для изменения или получения цвета конкретного образца исполь-
зуются обычные инструменты: «ведро с краской» и «пипетка».
На рис. 2.5 набор цветов сохраняется в виде цветового каталога, находящегося
вне сцены в документе FLA. Поскольку образцы расположены на опорном слое,
они не экспортируются в итоговый SWF-файл.
Конечно, остается еще одна проблема: как перенести нужные цвета в Flash?

Импортирование цветов
На панели Color Swatches находится пережиток прошлого, динозавр из давно
ушедшей эпохи - веб-безопасная палитра. В наше время веб-безопасная палит-
Создание и упорядочение пользовательских каталогов цветов 77

ра практически не используется. Если компьютер не способен отображать более


256 цветов, скорее всего, он не сможет поддерживать Flash Player (исключение
могут составлять некоторые карманные компьютеры).
Более того, веб-безопасная палитра спроектирована для работы на оборудова-
нии с поддержкой палитр с 8-, 16- или 32-разрядной кодировкой цвета. Веб-
безопасные цвета могут неточно отображаться на компьютерах, настроенных
на отображение 24-разрядного цвета.
Используя градиентные заливки во Flash, вы уже выходите за рамки веб-безо-
пасных цветов, даже если цвета, определяющие градиент, были выбраны из веб-
безопасной палитры.
Для создания цветовых палитр можно использовать Photoshop (или Fireworks).
На вкладке Swatches в Photoshop (рис. 2.6) могут отображаться многие палитры,
не только веб-безопасные; кроме того, существует много заготовок палитр, ори-
ентированных на печать.

Рис. 2.5. Сохранение цветовых образцов за пределами сцены на опорном слое

0 Color v Svatches \_Styles \


:
ш
Ш
: •- si
I щ ш ;: |
Ш
,„]„.] 1 1 .1
1
щящ
ш Щ
щ
: П
.: •>-. WfiB"-'- j
эЬ Ч|
Рис. 2.6. Вкладка Swatches в программе Photoshop

К сожалению, Flash не поддерживает импортирование «родных» файлов Photoshop


в формате АСО (Adobe COlor). He беспокойтесь: и Flash, и Photoshop поддержи-
вают другой, скрытый формат палитр, а именно файлы ACT (Adobe Color Table).
78 Глава 2. Цветовые эффекты

АСТ-файлы могут создаваться только на базе изображений с индексированны-


ми цветами, обычно GIF или PNG-8.
Чтобы создать такую палитру в Photoshop, выполните следующие действия:
1) создайте изображение;
2) выполните команду File • Save for Web;
3) выберите формат GIF или PNG-8 в разделе Settings диалогового окна Save for Web;
4) выберите в раскрывающемся списке Colors количество цветов, которые долж-
ны присутствовать в палитре;
5) чтобы сохранить палитру, щелкните на кнопке с треугольником в правом
верхнем углу окна (рис. 2.7) и выберите в открывшемся меню Options коман-
ду Save Color Table.

Lossy. 0 >
Perceptual U
Diffusion [vj Dithtr I ООН

No Transpar»,. V j Amount-

Рис. 2.7. Сохранение цветовой палитры в Photoshop

Чтобы загрузить цветовую таблицу в Flash, выберите команду Add Colors в меню
Options панели Color Swatches. Импортированные цвета присоединяются в конец
текущего каталога цветов.
Существует и другой, гораздо более простой способ импортирования цветов из
Photoshop: нарисуйте серию образцов в Photoshop, используя однородную кисть
или аэрограф (рис. 2.8), затем импортируйте растровое изображение в формате
без потери данных (PNG-32 или TIFF) в Flash.

> • # »
Рис. 2.8. Изображение, используемое для перенесения
цветовой палитры из Photoshop в Flash
Использование естественных цветовых схем 79

Инструмент «пипетка» распознает отдельные пикселы растра; выборка цветов


из импортированного изображения производится практически так же, как и вы-
борка из векторных цветовых блоков. Это чрезвычайно эффективный способ
перенесения цветовых данных из Flash в Photoshop.

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

Использование естественных
ТРЮК

№12 цветовых схем


Создание цветовых комбинаций и схем на базе реальных изображений.
Панель Color Mixer нельзя назвать идеальным способом создания новых цвето-
вых палитр (см. трюк 11). Человеческий глаз относительно плохо различает цве-
та. Например, темно-красный цвет в окружении белых цветов покажется более
темным (и даже черным), чем в окружении других темных цветов, и это вполне
естественно, поскольку в процессе эволюции глаз научился выделять не абсо-
лютные цвета, а относительные различия между цветами, отображаемыми в на-
стоящий момент.
С учетом сказанного иногда бывает проще выбирать цветовые палитры на осно-
ве изображений, взятых из реальной жизни. Например, на рис. 2.9 цвета выбира-
ются из изображений лезвия ножа и цветочных лепестков.
Оба изображения были получены на недорогом планшетном сканере. Такой спо-
соб гораздо быстрее поиска каталогов веб-безопасных цветов в Веб и намного
дешевле приобретения книги цветовых образцов для многокрасочной печати.
Но при попытке выбрать цвет из любого из этих изображений немедленно воз-
никают проблемы. Дело в том, что цвета соседних пикселов сильно различают-
ся; вы пытаетесь выбрать цвет из желтого лепестка, а получаете, к примеру,
светло-зеленый образец. Чтобы упростить выбор цветов, следует преобразовать
изображение и сделать его более подходящим для применения «пипетки». Про-
ще всего это делается при помощи некоторых фильтров Photoshop.
Для уменьшения шума в оцифрованном изображении применяется фильтр Filter •
Noise • Despeckle. Цвета становятся более однородными, но проблемы с точным
выбором цвета из естественного изображения все равно остаются. К счастью,
существует фильтр, обеспечивающий нужный результат. Выполните команду
80 Глава 2. Цветовые эффекты

Filter • Pixelate • Pointillize. Изображение разбивается на отдельные пятна, напо-


минающие мазки краски на палитре художника (рис. 2.10).

Рис. 2.9. Отсканированные изображения ножа (оттенки серого цвета)


и цветов (живые естественные краски)

Р'-ТТДШВДК*? : '/'Ы Г1' • .,.:.••.. .:...•..,•.•.

Рис. 2.10. Часть изображения до применения фильтра пуантилизации (слева)


и после него (справа)

Сохраните полученный результат в формате без потери данных, поддерживае-


мом Flash (например, PNG-32 или TIFF), и импортируйте его в Flash.
Расположите изображение вне сцены на guide layer, чтобы оно не экспортирова-
лось в итоговый SWF-файл. Теперь у вас имеется естественная палитра, причем
сходные цвета расположены в ней вблизи тех цветов, с которыми они соседству-
ют на реальном объекте. Чтобы выбрать цвет из каталога, воспользуйтесь «пи-
петкой», как показано на рис. 2.11.
Имитация эффекта сепии 81

Рис. 2 . 1 1 . Выбор цвета из растрового каталога цветов с применением


панели Color Mixer и инструмента Eyedropper

Итоги
Проектирование цветовых схем в Flash (и во многих других приложениях) неред-
ко производится методом проб и ошибок, поскольку цвета, выбираемые по отдель-
ности, воспринимаются совсем не так, как в окружении других цветов. Сканирова-
ние изображения реально существующего объекта, уже содержащего желаемую
цветовую схему, и его преобразование в цветовой каталог повышает точность вы-
бора цветов, так как последний осуществляется в контексте. Утилита Gliftic ав-
томатически строит цветовые схемы на базе изображений (http://www.ransen.com/
Gliftic/Gallery/Natural-Color-Schemes.htm).
На основе работ Джошуа Дэвиса и других

ТРЮК Имитация эффекта сепии


№13 Имитация эффектов тона/насыщенности в Flash для создания изображе-
ний в сепийной цветовой гамме.
Многие графические редакторы, в том числе Photoshop и Fireworks, позволяют
изменять тон и насыщенность цветов изображения для создания нестандартных
цветовых гамм, в том числе и цветовой гаммы сепии. Flash тоже предоставляет
такую возможность, хотя с первого взгляда это может быть неочевидно. В этом
82 Глава 2. Цветовые эффекты

трюке вы узнаете, как вручную создать эффект сепии в Photoshop и затем преоб-
разовать результат в Flash.

Создание эффекта сепии в Photoshop


Сепийная цветовая гамма имитирует вид сепийных фотографий (также назы-
ваемых альбуминными), печатавшихся во второй половине XIX века по техно-
логии, предложенной Луи-Дезире Бланкар-Эвраром в 1850 году. Темно-коричне-
вая тональность старых фотографий вызвана не старением, а исходным процессом
проявки. Дополнительную информацию об альбуминной печати можно найти
на сайте Королевского фотографического общества (http://www.rps.org/book/terms/
albumen.html).
Если в вашем графическом редакторе предусмотрена встроенная поддержка эф-
фекта сепии, задача решается элементарно. Например, в Fireworks следует открыть
изображение и выполнить команду Commands • Creative • Convert to Sepia Tone.
В этом разделе будет рассмотрен более общий технологический процесс в Photo-
shop, не ограничиваемый сепийными тонами. Откройте изображение в Photoshop
и выполните команду Image • Adjustments • Hue/Saturation. На экране появляется
окно Hue/Saturation, показанное на рис. 2.12. Установите флажки Colorize и Preview.

• . щшш ; ••'

I O l

> 1 ?| * | EPreview I

Рис. 2.12. Окно Hue/Saturation в Photoshop

Процесс создания сепийной тональности состоит из двух шагов:


1) снижения насыщенности вплоть до получения черно-белого изображения;
2) раскрашивания изображения определенным оттенком (темно-коричневым для
создания эффекта сепии).
Для снижения насыщенности цветов можно перевести ползунок Saturation в край-
нее левое положение, но это перебор - нужно оставить немного цветовой ин-
формации для применения цвета. Оставьте его в положении 25.
Чтобы окрасить изображение, переведите ползунок Hue в позицию темно-крас-
но-коричневых оттенков (от 0 до 30).
Оригиналы сепийных фотографий имеют слегка розоватый оттенок, поэтому
значения тона в интервале от 330 до 350 тоже можно считать допустимыми.
Имитация эффекта сепии 83

Воспроизведение эффекта в Flash


Цветовые эффекты Flash обеспечивают изменение цветов, но не поддерживают
снижения насыщенности, поскольку класс Color использует модель RGB, а сле-
довательно, не может легко отделить цвет от яркости. Единственным способом
удаления всех цветов является радикальное увеличение или уменьшение ярко-
сти, однако оно приводит к неприятному побочному эффекту - изображение
растворяется на белом или черном фоне!
Итак, обработка должна начаться с изображения, у которого насыщенность уже
была снижена. В Photoshop эта задача решается командой Image • Adjustments •
Desaturate.
Импортируйте обработанное изображение в Flash, разместите его на сцене. Вы-
делите изображение и преобразуйте его в символ анимационного клипа (F8).
Это позволит применять к изображению цветовые эффекты и использовать его
с экземплярами Color.
Далее следует найти нужный цвет. На панели Color Mixer (Window • Design
Panels • Color Mixer) выберите в меню Options режим HSB; введите значение Hue,
использовавшееся в Photoshop (30 в нашем примере), и увеличьте значения
Saturation и Brightness на 50 и 75 % соответственно (рис. 2.13). Оставьте панель
Color Mixer открытой.

Н; 3D5 RGB

50%
M i l y*!ii В 75% Add Swatch

гv Alphati 100% Help

Close Panel
J

Рис. 2.13. Панель Color Mixer

Выделив анимационный клип с изображением, задайте на панели свойств пара-


метру Color значение Tint. Задайте параметру Tint Amount (справа от цветового
образца) значение 25%. Выделите образец и щелкните на цвете, созданном на
панели Color Mixer. Изображение превращается из черно-белого в сепийное.
Хотя Flash-версия эффекта сепии сохранит некоторую долю базовых цветов, по
точности передачи светлых областей она уступает версии Photoshop. Это связа-
но с тем, что Photoshop выполняет гораздо более сложную обработку цветов для
сохранения яркости. В этом проявляется недостаток эффектов реального времени
по сравнению с предварительным обсчетом: Flash приходится работать быстро,
84 Глава 2. Цветовые эффекты

поэтому не стоит рассчитывать на то, что изменение цветов будет выполнено так
же точно, как в Photoshop.
Наконец, чтобы воссоздать этот эффект в ActionScript, задайте параметру Color
значение Advanced, щелкните на кнопке Settings, запомните цветовые значения
и используйте их для определения цветовых преобразований на стадии выпол-
нения (см. трюк 10).

Эффект сепии в статической графике


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

Рис. 2.14. Создание границы кадра в виде круглого отверстия с размытыми краями

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


базовыми цветами. Например, применение синей колоризации с добавлением
линий и фигур в стиле «техно» придает изображению более современный стиль
(рис. 2.16). Более того, кроме согласования изображения с общим дизайном сай-
та, наложение векторных элементов на изображение способно добавить динами-
ки и замаскировать пиксельные артефакты.
Имитация эффекта сепии 85

Стоит заменить растр зернистости накладкой, состоящей из линий и бессмыс-


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

Рис. 2.15. Отображение портрета в сепийных тонах через круглое отверстие

Рис. 2.16. Изображения в стиле «техно» создаются в синей цветовой


гамме и содержат наложенный текст
86 Глава 2. Цветовые эффекты

Динамический эффект сепии и класс Color


Анимация эффекта сепии производится по тем же принципам, что и добавление
цветовых эффектов в видео (см. трюк 10). В комбинации с эффектом старой
пленки (см. трюк 3) создается впечатление, что перед вами не статическое изоб-
ражение, а стилизованный видеоклип. Эффект сепии и другие цветовые эффек-
ты позволяют обрабатывать графику на стадии выполнения.
Область применения цветовых эффектов не ограничивается одним растровым
изображением. Применяя их ко всему SWF-файлу за счет применения к _root,
вы сможете быстро изменить цветовую схему сайта. А если объединить эту воз-
можность с заменой сепии на накладку в стиле «техно», вы измените стиль оформ-
ления сайта. Цветовые эффекты также могут использоваться для обозначения
разных состояний - например, цветом можно выделить недоступные элементы
интерфейса или миниатюры в каталоге графики, загруженные и готовые к про-
смотру.
ГЛАВА 3

Рисование и маски
Трюки № 14-25
Говоря о «рисовании» в Flash, мы нередко говорим о двух разных вещах. Первая,
более традиционная форма рисования - рисование «от руки» - используется
художниками, создающими анимацию на Flash. Во второй форме графика создает-
ся при помощи сценариев; я называю ее «кинетическим рисованием». Кинетичес-
кое рисование не сводится к перемещению по экрану графических объектов -
вы также можете создавать графику в реальном времени и отображать промежу-
точные результаты для пущего эффекта. Рисование в реальном времени осуще-
ствляется средствами так называемого Drawing API - набора методов класса
MovieClip, в том числе lineStyle(), moveTo(), lineToQ, beginFillQ и т. д., предназначен-
ных для создания линий и заливок.
Аниматор классической школы найдет в этой главе полезные приемы для реше-
ния стандартных проблем - таких, как сокращение пикселизации вокруг краев
растрового изображения (см. трюк 23), обеспечивающее эффективное объедине-
ние растровой графики с векторным содержимым и ликвидацию неровностей
на линиях.
Разработчик сценариев узнает, как решать некоторые стандартные проблемы
Flash, в том числе проблему неточности свойства _alpha (см. трюк 19) и «сдвига
пикселов» в растровых изображениях (см. трюк 24). Также здесь описаны
приемы создания стандартных «строительных блоков» при динамическом по-
строении графического контента (скажем, рисование круга из прямой линии -
см. трюк 14).
Навыки рисования в Flash абсолютно необходимы как художникам, так и раз-
работчикам сценариев, поэтому представленные трюки должны быть доступны-
ми для всех категорий пользователей Flash. Опытные Flash-разработчики
не удивятся тому, что некоторые из трюков основаны на использовании масок.
Если вы еще не знакомы с масками, обратитесь к краткому введению в начале
главы 1.
Глава 3. Рисование и маски

Быстрое построение кругов


ТРЮК

№14 с заливкой
Рисование кругов с заливкой на стадии выполнения требует интенсив-
ной работы процессора. Рисование кругов из прямой линии повышает
быстродействие и обеспечивает большую гибкость по сравнению с ин-
струментами, применяемыми на стадии разработки.
Нарисовать прямоугольник с заливкой средствами Drawing API относительно
легко - вы определяете четыре угловые точки, и находящаяся между ними об-
ласть заполняется автоматически. С кругами дело обстоит сложнее. Вам придет-
ся либо аппроксимировать кривизну круга многочисленными отрезками, либо
создать серию дуг методом MovieClip.curveToQ. В обоих случаях тригонометри-
ческие вычисления замедляют работу программы и безнадежно усложняют код
для тех, кто слабо разбирается в синусах и косинусах. И все же не стоит огор-
чаться, в Flash существует очень простой способ рисования кругов с заливкой -
для этого достаточно нарисовать всего одну прямую линию.
Каждый раз, когда вы рисуете прямую, ее концы закругляются (рис. 3.1).

1111
Щ

НИ 163.0

Рис. 3 . 1 . Короткая линия с закругленными концами

Вероятно, вы подумали: «Понятно, к чему он клонит. Если нарисовать достаточ-


но короткую линию, закругленные концы соприкоснутся, и получится круг, вер-
но?» В каком-то смысле. Инструменты Pencil и Line не позволяют нарисовать
достаточно короткую линию и ограничивают толщину линий значением 10, по-
этому нарисовать достаточно большой круг таким способом не удастся. К тому
же рисовать круги нужно именно на стадии выполнения, поэтому трюк исполь-
зует ActionScript для рисования очень коротких, очень толстых линий. Попро-
буйте выполнить следующий фрагмент:
var clip:MovieClip = this.createEmptyMovieClip("circlejnc".
thi s.getNextHi ghestDepth());
circle_mc._x = circ1e_mc._y = 150;
circle_mc.lineStyle(200. 0x0, 100):
circle_mc.moveTo(0, 0);
circle_mc.lineTo(0.2. 0);
Он рисует круг, изображенный на рис. 3.2.
Круг представляет собой отрезок длиной всего 0,2 единицы и толщиной 200 еди-
ниц. Flash рисует два закругленных конца этой очень короткой линии так
Быстрое построение кругов с заливкой

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

Рис. 3.2. Очень короткая линия, закругленные концы которой образуют круг

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


динамически нарисовать круг.

Программа
Следующая программа (файл dynaButton.fIa на сайте книги) строит меню, в ко-
тором круглые кнопки используются в качестве маркеров команд. Жирным шриф-
том выделен фрагмент, создающий «псевдокруги» в клипе:
function createButton(dynaButton. dynaLabel. depth, x. у) {
var c l i p = this.createEmptyMovieClip(dynaButton. depth);
clip.lineStyle(15. 0x0, 100);
clip.moveTo(0, 0 ) ;
clip.lineTo(0.2, 0);
c l i p . _ x = x:
c l i p . _ y = y;

var txt_fmt:TextFormat = new TextFormatO;


txt_fmt.font = "_sans";
txt_fmt.size = 12;

this.createTextField(dynaButton + " _ t x t " . depth + 1.


x + 10. у - 10. 100. 20);
var textLabel = this[dynaButton + " _ t x t " ] ;
textLabel.text = dynaLabel;
textLabel.setTextFormat(txt_fmt);
}
createButton("home_btn". "home". 1. 100. 10);
createButton("products_btn", "products". 3, 100. 30);
createButton("about_btn". "about us". 5. 100. 50);
createButton("links_btn". "links we l i k e " . 7. 100. 70);

home btn.onRelease = functionO {


90 Глава 3. Рисование и маски

// Необходимые действия

products_btn.onRelease = function О
// Необходимые действия

about_btn.onRelease = f u n c t i o n O
// Необходимые действия

1 inks_btл.onRelease = functionO {
// Необходимые действия
}:
При выполнении этого кода на экране появляется динамически сгенерирован-
ное меню, изображенное на рис. 3.3.
ф home
Ф products
ф about us
Ф links we like

Рис. 3.3. Использование «псевдокругов» в качестве маркеров меню

Усовершенствование трюка
Чтобы код стал более универсальным, можно усовершенствовать идею и напи-
сать класс создания кнопок на ActionScript 2.0:
// Этот код ActionScript 2.0 должен храниться
// во внешнем файле CreateButton.as
class CreateButton {
// Переменная target определяет временную диаграмму, на которой
// CreateButton будет создавать кнопки.
private var target:MovieClip:
// Конструктор
public function CreateButton(targetTimeline:MovieClip) {
target— targetTimeline;
// Определение метода createBtnO
// Аргументы:
// buttonName - имя экземпляра создаваемой кнопки
// dynaLabel - надпись на создаваемой кнопке
// depth - глубина кнопки
// х, у - координаты создаваемой кнопки.
// Возвращаемое значение:
// Анимационный клип кнопки с. именем экземпляра buttonName.
public function createBtnCbuttonName:String. dynaLabel:String,
depth:Number, x:Number, y.• Number):MovieClip {
// Инициализация
var clip:MovieClip:
Быстрое построение кругов с заливкой , 91

var clipMask:MovieClip:
var txt_fmt:TextFormat;
var clipText:TextField;

// Создание клипа для кнопки


clip = target.createEmptyMovieClip(buttonName. depth);
drawPip(clip);
clip._x = x;
clip._y = y:

// Создание области принадлежности к кнопке


clipMask = clip.createEmptyMovieClip("mask". 0);
clipMask._vi sible = false;
drawPip(clipMask);
clip.hitArea = clipMask;

// Создание объекта TextFormat для применения форматирования


txt_fmt = new TextFormatO;
txt_fmt. font = "_sans";
txt_fmt.size = 12;

// Создание текстового поля (то есть подписи)


clip.createTextFieldCbuttonName + "_txt", 1. 10. -10. 100. 20);
clipText = clip[buttonName+ "_txt"};
clipText.text = dynaLabel:
cli pText.setTextFormat(txt_fmt);
return clip:
}
private function drawPip(clip);Void {
clip.lineStyle(15. 0x0. 100):
clip.moveTo(0. 0);
clip.lineTo(0.2. 0);

Чтобы использовать класс CreateButton, сохраните этот код в файле с именем


CreateButton.as. Затем создайте новый файл с расширением .fla в одном ката-
логе с CreateButton.as. Создайте в этом файле новый экземпляр класса Create
Button:
var buttonGen:CreateButton = new CreateButton(this);
При конструировании экземпляра CreateButton передается один аргумент - вре-
менная диаграмма (то есть главная временная диаграмма или анимационный
клип), на которой будут создаваться кнопки. После создания экземпляра Create-
Button кнопки на целевой диаграмме создаются вызовами метода CreateBut-
ton.createBtn():
var home:MovieClip = buttonGen.createBtn("home", "home".
this.getNextHighestDepthO. 100. 10);
var products:MovieClip = buttonGen.createBtn("products", "products".
this.getNextHighestDepthO. 100. 30);
var about:MovieClip = buttonGen.createBth("about", "about us",
this.getNextHighestDepthO. 100. 50):
92 Глава 3. Рисование и маски

var links:MovieClip = buttonGen.createBtn("links", "links we like".


this.getNextHighestDepthO. 100. 70);

home.onRelease = functionO {
traceC'You clicked the home button");

products. onRel ease = functionO {


traceC'You clicked the products button");

about. onRel ease = functionO {


traceC'You clicked the about button");

links.onRelease = functionO {
traceC'You clicked the links button"):

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


преимуществ:
• создаваемые кнопки лучше структурированы. На этот раз текст подписи хра-
нится внутри клипа кнопки. Чтобы щелчок мышью мог осуществляться только
на кнопке (а не на тексте подписи), метод createBtnQ также создает клип
маски mask, определяющий круг как область, на которой можно щелкать;
• программист сам выбирает местонахождение создаваемых кнопок. Для этого
при создании нового экземпляра CreateButton задается временная диаграмма,
на которой должны создаваться кнопки.
Многие пользователи жалуются на то, что в ситуациях, когда достаточно про-
стых кнопок и полос прокрутки (самых распространенных компонентов пользо-
вательского интерфейса), компоненты Flash MX 2004 «раздуты» ненужной фун-
кциональностью (см. трюк 73). Приведенный листинг демонстрирует простое
решение - определение пользовательского класса для создания компонента!
Такое решение по компактности превосходит не только компоненты Flash MX
2004 v2, но и более старые компоненты Flash MX vl.
Конечно, этот нетривиальный трюк с построением круга существенно упрощает
генерирование компонента на стадии выполнения и его прорисовку.

ПРИМЕЧАНИЕ
После компиляции наш класс кнопки занимает менее 1 Кбайт — он состоит
только из программного кода и поэтому хорошо сжимается. Благодаря этой
особенности он хорошо подходит для сайтов, которые должны занимать как
можно меньший объем (например, рассчитанных на мобильные устройства),
а также для конкурсов на самую компактную программу.

Круги также часто используются в графических Flash-приложениях и при рабо-


те с трехмерными каркасными моделями для представления точек, которые мо-
гут перетаскиваться мышью. Пример приведен в следующем листинге (файл
dynaPoint.fla на сайте книги):
function createPoint(dynaPoint. depth, x, у) {
c l i p = this.createEmptyMovieClip(dynaPoint. depth);
clip.lineStyle(20. 0x0. 100);
clip.moveTo(0, 0);
Синтетическая графика 93

c1ip.lineTo(0.2. 0);
clip._x = х;
d i p . _ y = у;
}
function drag О {
this.startDrag(true);
paper.onMouseMove = drawLine;
this.onPress = drop:
}
function dropO {
this.stopDrag(true);
delete (paper.onMouseMove);
this.onPress = drop;
}
function drawLineO {
this.clearO;
t h i s . l i n e S t y l e ( 2 . 0x0. 100);
this.moveTo(pointl._x, p o i n t l . _ y ) ;
this.lineTo(point2._x, point2._y);
updateAfterEventO;
}
// Пример использования:
createPointC'pointl". 1. 100. 100):
createPoint("point2". 2. 120. 100):
pointl.onPress = drag;
point2.onPress = drag;
this.createEmptyMovieClip("paper". 0);
Протестируйте пример: щелкните на точке и перетащите ее, как показано на
рис. 3.4. Повторный щелчок останавливает перетаскивание.

Рис. 3.4. Перетаскивание «псевдокруга»

Как видно из двух рассмотренных примеров, возможность быстрого построения


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

Синтетическая графика
Вместо загрузки больших растровых изображений или создания готовых
макетов заставьте Flash генерировать изображения «на ходу».
Как известно, компьютеры умеют генерировать песни на основании небольшого
набора музыкальных правил. Точно так же их можно заставить генерировать
простые изображения на основе нескольких правил построения макета и разме-
щения графических объектов.
94 _^ Глава 3. Рисование и маски

Как и во всем «компьютерном творчестве», художественные способности потре-


буются в первую очередь программисту, а не компьютеру. Программист сначала
создает завершенные, но взаимозаменяемые фрагменты, а затем поручает ком-
пьютеру собрать из них готовое произведение.
Далее представлена типичная разновидность этого трюка, автором которой яв-
ляется Энтони «Ant» Идеи (a.k.a. arseiam). Его работа основана на построении
сетки из клипов, каждый из которых содержит простые геометрические фигуры.

Листинг
Изображение строится из нескольких секций, каждая из которых находится на
ключевом кадре анимационного клипа node. Примеры секций представлены на
рис. 3.5. Исходный текст программы хранится в файле antart.fla на сайте книги.

Рис. 3.5. Фигуры для синтетического изображения

Следующий фрагмент генерирует сетку 12 х 8 из наших узловых клипов каж-


дый раз, когда пользователь щелкает на сцене, и останавливает каждую копию
на кадре со случайным номером:
this.onMouseDown = function О {
var depth = 0;
for (var i = 0; i < 12: i++) {
for (var j = 0: j < 8: j++) {
var me = "n" + i + j ;
this.attachMovieC'node", me. depth++);
this[me]._x = 50 * i ;
this[me]._y = 50 * j :
this[me].gotoAndStop(random(100) + 1):

Фрагмент строит случайную сетку из фигур; при этом создаются узоры вроде
изображенного на рис. 3.6.
Чтобы узор получился более сложным, можно вложить в него дополнительные
копии node. Каждая копия node содержит следующий код:
i f (Math.ceil (Math.randomO < 0.80)) {
this.attachMovieC'node", "n". 0):
this["n"]._x = 50*i:
this["n"]._y = 50*j;
this["n"]._xscale = n._yscale = _parent._xscale / 1.5;
thi s["n"].gotoAndStop(Math.cei1((Math.random()*10))):
Синтетическая графика 95

Рис. 3.6. Случайный узор, сгенерированный из базовых фигур

Если проверяемое условие истинно (а это происходит в 80% случаев), секция if


создает уменьшенную копию node поверх текущего экземпляра node. Создание
уменьшенной фигуры делает внешний вид текущего узла менее тривиальным.
Внутренняя копия тоже содержит этот фрагмент, поэтому с вероятностью 80%
в ней создается еще меньшая версия node. Это приводит к дальнейшему услож-
нению узора.
Таким образом, узор является случайным по двум факторам - программа изменя-
ет фигуру в каждом узле сетки и случайным образом выбирает количество вложен-
ных фигур на каждом узле. Один из возможных результатов показан на рис. 3.7.

liliilil
Рис. 3.7. Случайный узор, сгенерированный из базовых фигур
96 Глава 3. Рисование и маски

Итоги
В примерах продемонстрированы два стандартных приема создания синтетичес-
кой графики: рекурсия (рисование постепенно уменьшающихся копий одного
клипа внутри текущего узла) и случайное размещение. Создав набор фигур, ко-
торые хорошо сочетаются друг с другом независимо от размещения и вложения,
Энт Идеи создал узор, который всегда выглядит естественно, словно рисунок
был обдуман заранее. "
Конечно, Энт действительно все «обдумал заранее» - но лишь при проектиро-
вании форм, рассчитанных на хорошее объединение друг с другом!
Именно этот принцип заложен в основу всего «компьютерного творчества» -
программист проектирует серию фраз или визуальных образов, хорошо комби-
нируемых друг с другом (или определяет правила построения случайных пос-
ледовательностей), а затем предлагает программе показать, что же из этого вый-
дет!
Спасибо Энту Идену за творческую идею и разрешение на использование графики

ТРЮК Мозаичное заполнение плоскости


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

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

Рис. 3.8. Разбиение плоскости на одинаковые мозаичные плитки


\
Мозаичное заполнение плоскости 97

Начнем с мозаики из квадратных плиток, потому что с ними проще всего работать.
Чтобы создать более интересный узор, можно вырезать или просто затемнить
часть плиток. Для создания квадратной решетки можно воспользоваться сред-
ствами привязки Flash (View • Grid • Show Grid and View • Snapping • Snap to Grid).
Нарисуйте на сцене темный круг, полностью закрывающий одну ячейку, не-
сколько раз продублируйте его и заполните все квадраты в области 2 x 2 (рис. 3.9).

Рис. 3.9. Первая фаза построения идеальной мозаики

Созданные позитивные и негативные области на сетке 2 x 2 преобразуются в узор


при помощи различных инструментов выделения, создания заливок и контуров,
как показано на рис. 3.10.

Рис. 3 . 1 0 . Применение контуров и заливок для создания фигур

На рис. 3.11 создаются простые круговые и ромбовидные формы вроде тех, что
использовались при построении синтетической график№(см. трюк 15).

-Ф-
Рис. 3 . 1 1 . Некоторые узоры, полученные применением контуров и заливок
к позитивным и негативным областям
Глава 3. Рисование и маски

Создав несколько дополнительных ромбовидных фигур, можно преобразовать


плитку 2 х 2 в повторяющийся узор, показанный на рис, 3.12.

Рис. 3.12. Повторяющийся ромбовидный узор

Далее в полученном узоре выделяется одна плитка (рис. 3.13), которая позднее
используется для эффективного воссоздания узора (рис. 3.14).

Рис. 3.13. Плитка, используемая для формирования узора

Рис. 3.14. Создание мозаики посредством ручного размещения плиток


Узорные заливки 99

Итоги
Конечно, ручное размещение плиток - не самый удобный способ; к тому же
плитки относительно бесполезны, если мы не сможем использовать их для за-
полнения фигур и областей по своему выбору. В трюке 17 будет показано, как
организовать мозаичное заполнение фигур.
Но прежде чем следовать дальше, попробуйте создать несколько собственных
узоров - например, заменив круги треугольниками в квадратных ячейках. Так-
же попробуйте начать с прямоугольных ячеек или других фигур, изображенных
на рис. 3.8.

ТРЮК Узорные заливки


№17 Flash не обладает средствами для заполнения непрямоугольных облас-
тей пользовательскими мозаичными узорами на стадии выполнения. Тем
не менее, применение маски позволяет заполнить область произволь-
ной формы узорной заливкой.
Во Flash, как и в большинстве графических редакторов, существует специаль-
ный инструмент для заполнения произвольных областей однородными и гра-
диентными заливками. С точки зрения Flash, заливка существует отдельно от
границы фигуры (контура). Инструмент Paint Bucket использует цвет заливки,
заданный образцом Fill Color в секции Colors палитры Tools (Window • Tools). На-
пример, чтобы выбрать градиентную заливку, щелкните на образце Fill Color и вы-
берите в открывшемся меню нужный тип градиентной заливки.
Далее панель Color Mixer используется для настройки градиента. Выделите заливку
инструментом Selection, затем выполните команду Window • Design Panels • Color
Mixer. На панели Color Mixer из меню выбирается тип градиента - линейный
(Linear) или радиальный (Radial). Вы даже можете выбрать растровую заливку
(Bitmap), и тогда Flash предложит выбрать растовое изображение для мозаично-
го заполнения области.
Таким образом, выбрать заливку области на стадии разработки относительно
несложно. Более того, градиентные и растровые заливки можно модифициро-
вать (масштабирование, перекос, повороты и преобразования) при помощи ин-
струмента Fill Transform из палитры Tools. Тем не менее, средства определения
заливок в ActionScript более ограничены. Методы fill() и beginGradientFill() класса
MovieClip, входящие в Drawing API, позволяют создавать на стадии выполнения
однородные, линейные градиентные и радиальные градиентные заливки, но мо-
заичные заливки не поддерживаются.
Ранее было показано, как создать узор многократным повторением базовой «мо-
заичной плитки» (см. трюк 16). Давайте посмотрим, как использовать эту воз-
можность для заполнения разных фигур нашим узором.

Заполнение прямоугольной области


Допустим, в диалоговом окне Symbol Linkage анимационному клипу плитки был
присвоен идентификатор компоновки tilePattern. Следующий фрагмент генери-
рует мозаичный прямоугольный узор из одинаковых плиток:
100 Глава 3. Рисование и маски

function tilerdinkagelD:String. target:MovieClip. clipName:String,


depth:Number, x:Number, у:Number,
row:Number, column:Number):MovieClip {
var pattern:Movie'Clip = target.createEmptyMovieClip(clipName, depth):
var depthCount:Number = 0:
for (var j:Number = 0: j < column: j++) {
for (var i:Number = 0: j < row. i++) {
var tile:MovieClip = pattern.attachMoviedinkagelD.
" t i l e " + i + "_" + j . depthCount);
t i l e . _ x = x + (tile._width * i ) :
t i l e . _ y = у + (tile._height * j ) :
depthCount++:

return pattern;
}
var patternClip:MovieClip = t i l e r C ' t i l e P a t t e r n " . t h i s .
"patternClip". 1. 50. 50. 15. 5);
Программа создает клип patternClip и заполняет его узором, состоящим из 15 х 5
плиток; левая верхняя плитка находится в позиции (50, 50), как показано на
рис. 3.15.

-w-
"ф- -ф- -ф-

"ф*
"ф- -ф-
А

- -^»w -Aw, „ilPSu. ^»ЙЧ^ -JA- J L ^AI» -ЖЬ. -»^- ^V. ^Aw J(L. ^

Рис. 3.15. Большая мозаика, построенная из одинаковых плиток

Функция tiler() получает восемь аргументов:


• linkagelD - идентификатор компоновки символа, определяющего базовую
мозаичную плитку;
• target - временная диаграмма, на которой строится узор;
• clipName - анимационный клип, который будет содержать построенный узор;
• depth - глубина создания clipName;
• х, у - позиция первого (левого верхнего) угла;
• row, column - количество плиток по вертикали и горизонтали.
Функция tiler() позволяет легко создавать векторные узоры в SWF-файле, когда
размер сцены меньше окна браузера и вы хотите заполнить неиспользуемую
область бордюра (см. трюк 92). Узорная заливка (например, косые диагональ-
ные линии) также может обозначать какое-то свойство контента (например, «эта
область не может быть выделена» или «эта часть пользовательского интерфейса
в данный момент недоступна»).
Узорные заливки 101

Заполнение областей непрямоугольной формы


Задача заполнения узором прямоугольных областей решается тривиально, с облас-
тями другой формы дело обстоит сложнее. Например, в несложном графичес-
ком редакторе, написанном на Flash, было бы желательно разрешить пользова-
телю создавать фигуры с узорной заливкой. Однако на стадии выполнения Flash
позволяет создавать векторные фигуры с однородными и градиентными залив-
ками, но не с узорными. Данное ограничение можно обойти при помощи масок.
В следующей программе наша функция заполнения прямоугольных областей
используется для заполнения круга. Для этого динамически построенный круг
назначается маской для мозаичного узора.
Давайте разберемся, как работает эта программа. Сначала она создает пустой
клип с именем myCircle. Внутри myCircle создаются еще два анимационных кли-
па. Первый клип (mask) содержит круг, второй (pattern) - содержит область
с мозаичным узором, размеры которой по вертикали и горизонтали заведомо
достаточны для заполнения круга. На рис. 3.16 изображен прямоугольник с узор-
ной заливкой, на который наложена маска в виде круга.

> * * .
4 4 4 ,
> • « « • .
4 4 4 4 4 4 4 4
Рис. 3.16. Прямоугольный узор и круглая маска

На рис. 3.17 маска скрывает все части прямоугольника за пределами круга; в ре-
зультате мы получаем круг с узорной заливкой.

+ 4- 4- + -$•
• • • • • • >
(. 4- 4 4 * 4 4 4 %
• • * • •• • • • \
•&••&•¥ "^••4*-^'41"'4'"Ф>
• • • • • • • • •
+ + + + + + + + +
4 + + + 4 + + 4^ +
• • • • • • • • • • *
• + 4- -f ^ > * 4• + -*• +
••-••••••• •••••<
- 4- ^ •¥ Л + + + +.•.+•
> "•- > Ч- 4• Ч- 4- 4- 4- 4
* • • • ' • • • •' • >

•*• +. 4- + •••
Рис. 3.17. Результат применения маски: все внешние части
скрываются, ыостается лишь круг с узорной заливкой
102 Глава 3. Рисование и маски

Следующая программа показывает, как использовать функцию tiler() для созда-


ния круга с узорной заливкой. В целом она устроена довольно прямолинейно:
• Функция pattemCircleO создает дополнительный клип с именем dummy, со-
держащий только одну плитку. Это делается для определения размеров плитки.
Клип dummy стирается узором, поскольку они используют одинаковую глу-
бину.
• Круг строится из четырех кривых, нарисованных функцией curveTo(). Хотя
полученная фигура далека от математически правильного круга, такая ап-
проксимация ускоряет работу приложения. Впрочем, Flash вообще никогда
не строит математически правильные круги (результат всегда строится при-
ч
ближенно для повышения быстродействия), поэтому мы не одиноки в этом
решении!
Итак, перед вами исходный код. Функция tiler() не изменилась по сравнению
с предыдущим листингом, поэтому здесь мы ее не приводим.
function patternCircle(linkagelD:String. target:MovieClip,
clipName:String, depth:Number.
x:Number, у:Number, г:Number):MovieClip {
var r2:Number = r*0.93;
var mc:MovieClip = target.createEmptyMovieClip(clipName, depth);
mc._x = x;
mc._y = y.
// Вычисление размера узора
var dummy:MovieClip = t i l e r ( " t i l e P a t t e r n " . me. "dummy". 0. 0. 0. 1. 1);
var size:Number = Math.ceiK (2*r) / dummy.Jieight) + 1:
// Рисование узора
var pattern:MovieClip = t i l e r ( " t i l e P a t t e r n " . me. "pattern".
0, -r. -r, size, size);
// Построение круга
var circle:MovieClip = mc.createEmptyMovieClipC'mask". 1);
circle.lineStyleCundefined. 0x0. 100);
circle.moveTo(-r. 0):
circle.beginFil1(0x0. 100);
circle.curveTo(-r2. -r2. 0. - r ) ;
circle.curveTo(r2. -г2. г. 0);
circle.curveTo(r2, r2, 0, r ) ;
circle.curveTo(-r2. г2. - г . 0);
circle.endFilK);
// Круг назначается маской для узора
pattern.setMask(circle):
// Возвращение созданного клипа
return me;
}
щуСлrcle = patternCircle("tilePattern". t h i s . "myCircle". 1. 270. 200. 100);

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

Негативные области позволяют легко создавать мозаичные плитки для заполне-


ния прямоугольных областей (см. трюк 16); эти плитки также могут использо-
ваться для заполнения областей произвольной формы посредством применения
масок.

ТРЮК Имитация мозаик Эшера


№18 Создание узоров, отдаленно напоминающих работы М. К. Эшера.

Форма мозаичных плиток не ограничивается простыми геометрическими фигу-


рами. В этом трюке рассматриваются принципы разбиения плоскостей для соз-
дания сложных узоров.
Даже тот, кто никогда не слышал имени М. К. Эшера, наверняка встречал мно-
гие знаменитые работы этого голландского художника. Мы не оформляли ли-
цензию на воспроизведение работ Эшера в книге, однако при желании их не-
трудно найти в Веб - например, на сайте www.mcescher.com. Во многих известных
работах Эшера плоскость разбивается на плитки одинаковой или разной формы,
идеально стыкующиеся друг с другом), - в виде птиц, рыб, рептилий и т. д.
Множество примеров подобных мозаик можно найти в Веб. Для этого проведи-
те в Google поиск по ключевым словам «tesselation» или «divided plane» (тессе-
ляция - всего лишь научный термин, обозначающий мозаику с идеальным при-
леганием плиток).

Разбиение плоскости
Методика определения негативных областей (см. трюк 16) станет хорошей от-
правной точкой для решения поставленной задачи. В этой методике плитка с по-
зитивными и негативными областями использовалась для имитации геометри-
ческих узоров, однако сами плитки были квадратными, а мозаика состояла из
простых геометрических фигур. А если вдруг потребуется создать узор в стиле
Эшера со сложным взаимным переплетением фигур? Как придать плиткам бо-
лее интересную форму, не ограничивающуюся простыми квадратами и шести-
угольниками, но при этом обеспечить их идеальную стыковку?
Фокус заключается в том, чтобы начать с геометрически правильной формы
и преобразовать ее во что-то еще более интересное. Давайте снова начнем с квад-
рата, потому что с ним проще всего работать.
Нарисуйте квадрат и преобразуйте его в символ анимационного клипа клави-
шей F8. Разместите рядом с ним на сцене еще несколько экземпляров символа
анимационного клипа, чтобы в итоге получилась сетка 3 x 3 , изображенная на
рис. 3.18. Дважды щелкните на центральном клипе, чтобы войти в режим редак-
тирования «на месте».
Теперь измените, скажем, левую сторону квадрата, выгнув ее при помощи ин-
струмента Selection. Изменения отражаются на всех девяти экземплярах клипа,
как показано на рис. 3.19; теперь вы видите, как будет выглядеть сетка 3x3
104 Глава 3. Рисование и маски

из новых плиток. Однако из рисунка видно, что некоторые плитки скрывают


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

Рис. 3.18. Построение сложного мозаичного узора начинается


с простой квадратной сетки

Рис. 3.19. Выгнутая сторона придает плитке более интересную форму

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

л
III
tlllill
кliSili
{. \ ISI,
V:. ;:r:i||:i!^
Рис. 3.20. Повторение изгибов с двух сторон обеспечивает
идеальное разбиение плоскости

ПРИМЕЧАНИЕ
Секрет идеального прилегания плиток — всегда добавлять с одной стороны
плитки то, что было убрано с другой стороны.

Конечно, результат получился весьма далеким от работ Эшера... А если при-


смотреться? Вы можете создать плитку произвольной формы, «вырезая» фраг-
менты с одного края и «вставляя» их с другого края. Далее посмотрите на кон-
тур полученной фигуры и подумайте, на что она похожа. Нарисуйте глаз и перья -
возможно, у вас получится птица; с чешуей и плавниками плитка может стать
похожей на рыбу и т. д.
Повторяющаяся плитка не обязана занимать всю площадь. До настоящего мо-
мента мы изменяли контуры фигуры, но вы также можете увеличить интервалы
между плитками - для этого достаточно просто масштабировать редактируе-
мый клип. Сетка 3 x 3 автоматически изменяется; плитки разделяются дополни-
тельными интервалами, как показано на рис. 3.21. Теперь можно создать более
сложный узор, потому что «сцепление» обязательно лишь в месте соприкосно-
вения плиток. Фактически, мы предполагаем, что интервалы становятся частью
плитки, и рассматриваем их как «позитивную область».
Достаточно осознать, что плитки могут и не закрывать всю область, а просто
должны стыковаться друг с другом, и вы сможете создать новый набор фигур
наподобие изображенных на рис. 3.22.
Фигура в левом верхнем углу рис. 3.22 вообще не похожа на мозаичную плитку,
но она является таковой - в этом нетрудно убедиться, взглянув на узор в нижней
части рисунка. На этот раз определение негативных областей производится одно-
временно с изменением внешнего контура. Заодно плитку можно повернуть: все
выполненные операции симметрично отражаются на сетке до тех пор, пока вы
остаетесь в режиме редактирования «на месте». В сущности, мы используем свой-
ство симметричности матрицы 3 x 3 относительно линий, проходящих через
центр матрицы.
106 Глава 3. Рисование и маски

Рис. 3 . 2 1 . При масштабировании среднего клипа в режиме редактирования «на месте»


остальные экземпляры также автоматически уменьшаются в размерах

v / 2

f f f
Рис. 3.22. Узор из вертушек

Конечно, узор из вертушек - не ахти какое достижение, но это лишь начало.


Создав матрицу 3 х 3 из вертушек, я преобразовал их в нечто больше похожее на
мозаики Эшера (рис. 3.23). При этом мне пришлось следить за тем, чтобы изги-
бы крыльев и шей хорошо прилегали друг к другу даже при сдвиге. Для этого я
сначала создал большие позитивные области (в частности, квадраты были умень-
шены для увеличения интервалов между ними), после чего заполнил их крыль-
ями, хвостами и шеями. Небольшой поворот всей матрицы 3 x 3 имитирует
легкий наклон летящей стаи (обратите внимание: если вместо всей матрицы мы
повернем только центральный квадрат в режиме редактирования «на месте», то
каждая плитка останется на своем месте, но повернется вокруг своей оси). А ес-
ли подрисовать уши и нос, негативные области на рис. 3.23 начинают походить
на спящих кроликов!
Новые, более сложные плитки принципиально отличаются от обычных прямоу-
гольных плиток только одним: величина смещения плитки не может быть полу-
чена простым обращением к свойствам _height и _width клипа. Вместо этого сме-
щения приходится вычислять вручную на основании позиций плиток при их
размещении. Тот же код, который использовался ранее (см. трюк 17), подойдет
и для нашей мозаики с летящими птицами.
Исправление неточности свойства _alpha 107

Рис; 3.23. Стая летящих птиц... Почти Эшер

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

Исправление неточности
ТРЮК

№19 свойства „alpha


Свойство _alpha анимационных клипов может возвращать неточные ре-
зультаты. Проблема решается созданием пользовательского внутреннего
аналога этого свойства, повышающего точность и плавность переходов.
Свойство MovieClip._alpha используется для задания и получения уровня про-
зрачности клипа. Однако Flash выполняет внутреннее округление значения это-
го свойства, поэтому его значение, полученное в результате выборки, может отли-
чаться от последнего заданного значения. В этом трюке мы создаем пользова-
тельское свойство для решения проблем, связанных с ошибками округления встро-
енного свойства Flash _alpha.
Свойство MovieClip._alpha хранится во внутреннем представлении в виде целого
числа от 0 до 255. Хотя ActionScript заявляет о работе со значениями альфа-
канала по шкале от 0 до 100 %, на самом деле это неправда. Следующий фраг-
мент демонстрирует потенциальное накопление ошибок округления:
var clip:MovieClip = this.createEmptyMovieClipC
"clip". this.getNextHighestDepthO):
clip._alpha = 0:
1 0 8 Г л а в а 3. Рисование и маски

for(var i = 1: i <= 100; {


clip._alpha++;
trace(i+"% = " + clip._alpha + "% alpha");
}
Код создает пустой клип и изменяет его свойство _alpha от 1 до 100 с прираще-
нием 1... во всяком случае, так предполагалось. В действительности Flash преоб-
разует каждое из значений из интервала от 0 до 100 % к ближайшему значению
на шкале от 0 до 255. Несколько последних значений, сгенерированных этим
фрагментом, выглядят так:
95% = 74.21875*. alpha
96% = 75 alpha
972 = 75.78125% alpha
98% = 76.5625% alpha
99% = 77.34375% alpha
100% = 78.125% alpha
К тому моменту, когда по нашим расчетам, альфа-канал должен достигнуть 100 %,
Flash накапливает такую ошибку округления, что отображаемое значение со-
ставляет 78,125% - погрешность превышает 20%! Как это могло произойти?
Дело в том, что каждый раз, когда мы задаем свойство _alpha, значение округля-
ется до ближайшей величины из интервала от 0 до 255. Но при последующей
выборке значение _alpha округляется с понижением, в результате при каждом
приращении значение увеличивается менее чем на 1%.
Чтобы предотвратить ошибку округления, следует либо использовать альфа-уров-
ни, не подвергаемые округлению, либо написать программу так, чтобы задавае-
мое значение альфа-канала сохранялось в пользовательском свойстве.

Пять значений, не создающих ошибки округления


Ошибка округления значения свойства _alpha возникает из-за того, что значе-
ния из интервала от 0 до 100 % преобразуются в интервал целых чисел от 0 до
255. Хотя большинство процентов не имеет целого представления в диапазоне
0-255, у пяти значений такие аналоги существуют: 0, 25, 50, 75 и 100 %.
Допустим, вы хотите задать альфа-уровень клипа «почти прозрачным». Тогда
лучше всего остановиться на значении 25 %, потому что в этом случае клип
будет прозрачным ровно на 25 %. Это объясняется тем, что значение 25 % по
шкале от 0 до 100 % имеет целое представление в интервале 0-255, а именно 64.
В этом нетрудно убедиться:
var clip:MovieClip = this.createEmptyMovieC1ip("clip",
this.getNextHighestDepthO);
clip._alpha = 25:
trace(clip._alpha); // Выводит 25
clip._alpha = 20;
trace(clip._alpha); // Выводит 19.921875
Если задать свойству _alpha значение 25% и прочитать его, мы получаем ту же,
неизмененную величину 25%. При других значениях (например, 20%) возвраща-
емое значение близко к заданному, но не совпадает с ним.
Исправление неточности свойства _alpha 109

Создание зеркального свойства


Конечно, пять альфа-уровней, округляемых без ошибки, - штука хорошая, если
вы собираетесь задать их и оставить без изменения, но при создании анимирован-
ных переходов от одного альфа-уровня к другому этот вариант не подойдет. В та-
ких случаях приходится писать код, не зависящий от точности округления _alpha.
Например, следующая программа создает переход альфа-уровня от 0 до 100 %
и заставляет Flash использовать правильные значения:
function fader(me. startAlpha, endAlpha) {
mc.fadel = startAlpha;
mc.fade2 = endAlpha;
mc.onEnterFrame = fade;
}
function fadeО {
this._alpha - this.fadel++;
if (this.fadel >= this.fade2) {
this._alpha = this.fade2;
delete this.fadel:
delete this.fade2:
delete this.onEnterFrame;

var clip:MovieClip = this.createEmptyMovieClipC'clip".


this.getNextHighestDepth()):
var size:Number = 100:
clip._x = 275;
clip._y = 200:
clip.lineStyleCO. 0x0. 100):
clip.beginFillCOxOOOOFF. 100);
clip.moveTo(-size/2. -size/2);
clip.lineTo(size/2, -size/2);
clip.lineTo(size/2. size/2):
clip.lineTo(-size/2. size/2);
clip.endFilK):
clip._alpha = 0;
faderCclip. 0. 100);
Поскольку значение, полученное при обращении к свойству _alpha, может быть
неточным (округленным по отношению к ранее заданному), мы считаем, что пола-
гаться на него не следует. Вместо того чтобы увеличивать _alpha напрямую, про-
грамма получает значение отдельного свойства fadei и задает его свойству _alpha.
Этот прием предотвращает постепенное накопление ошибок. Вместо того чтобы
проверять значение _alpha и смотреть, достигло ли оно 100 %, мы проверяем свой-
ство fadei, так как оно не содержит погрешности. При достижении пороговой ве-
личины (в нашем случае 100 %) свойству _alpha явно задается нужное значение.

ПРИМЕЧАНИЕ
Альфа-прозрачность замедляет воспроизведение анимации в Flash из-за необ-
ходимости обработки пикселов как изображения, так и фона. Если в результате
ошибки округления альфа-уровень будет представлять собой дробную величи-
ну менее 100 %, это замедлит работу Flash. После перехода мы задаем alpha
значение 100, чтобы предотвратить это падение быстродействия.
110 Глава 3. Рисование и маски

Предотвращение ошибок округления


с использованием классов/прототипов
При создании анимации с интенсивным использованием альфа-эффектов допол-
нительный код, решающий проблемы с ошибками округления _alpha, усложняет
чтение и сопровождение программы. В таких случаях подумайте о решении про-
блемы при помощи пользовательского класса. В следующем примере мы созда-
ем новый класс с именем AlphaClip, который должен храниться во внешнем фай-
ле AlphaClip.as. Класс определяет функции чтения и записи своего внутреннего
свойства alphalnternal, не подверженного ошибкам округления MovieClip._alpha.
Обратите внимание: AlphaClip не объявляется субклассом MovieClip, а лишь хра-
нит ссылку на экземпляр этого класса в одном из свойств.
// Этот код ActionScript 2.0 должен храниться
// во внешнем файле AlphaClip.as
class AlphaClip {
private var alphalnternal:Number;
private var target:MovieClip;

public function AlphaClip(mc:MovieClip) {


target = me:
alphalnternal = mc._alpha;
}
public function get _alpha():Number {
return alphalnternal;
}
public function set_alpha(alphaIn:Number):Void {
target._alpha = alphaln;
alphalnternal = alphaln:

Допустим, на сцене существует анимационный клип с именем myClip; прямые


операции чтения и записи свойства MovieClip._alpha могут привести к рас-
хождениям между заданным значением свойства и тем, которое будет получено
при последующем чтении. Но если заменить его свойством _alpha нашего поль-
зовательского класса AlphaClip, возвращаемое значение будет совпадать с за-
данным, поскольку во внутренних операциях класса используется более точное
свойство AlphaClip.alphalnternal; тем самым предотвращается накопление ошибок
округления. Мы определяем методы доступа, чтобы разработчик мог работать со
знакомым свойством _alpha, не обращаясь напрямую к внутреннему свойству
alphalnternal.
var myAlpha:AlphaClip = new AlphaClip(myClip);

// Прямое изменение свойства _alpha (старый способ)


myClip._alpha = 20:
trace(myClip._alpha); // Выводит: 19.921875
// Косвенное изменение myClip._alpha через myAlpha._alpha
myAlpha._alpha = 20:
trace(myAlpha._alpha); // Выводит: 20
Исправление неточности свойства _alpha 111

Поставленная задача решена, но на практике пользоваться таким решением не-


удобно, потому что разработчик должен помнить о необходимости создавать
экземпляр AlphaClip помимо основного клипа каждый раз, когда он хочет избе-
жать потенциальных ошибок округления MovieClip._alpha. Более формальный
объектно-ориентированный подход ActionScript 2.0 заключается в создании суб-
класса, расширяющего встроенный класс MovieClip (то есть наследующего от него).
Вариант с наследованием обладает существенным преимуществом: разработчику
не нужно создавать отдельные экземпляры AlphaClip и MovieClip для одного клипа.
Впрочем, он все равно должен помнить о том, что для решения проблемы с ок-
руглением альфа-уровня вместо экземпляра MovieClip нужно создать экземпляр
AlphaClip.
В предыдущем примере вместо формального наследования использовался упро-
щенный механизм композиции. Другими словами, вместо того чтобы расширить
класс MovieClip с ключевым словом extends, мы внедрили в класс AlphaClip от-
дельный экземпляр MovieClip (свойство target).
И все же для удобства разработчика было бы предпочтительнее заменить Movie
Clip._alpha напрямую, без создания экземпляров отдельного субкласса. Исходя
из этих соображений, мы воспользуемся стилем ActionScript 1.0 и изменим класс
MovieClip посредством присоединение свойств и методов к его прототипу. Этот
код также работает в ActionScript 2.0:
.// Определение методов доступа
getAlpha = function () {
return this.alphalnternal;
}:
setAlpha = function (alphaln) {
this._alpha = alphaln:
this.alphalnternal = alphaln:
}:
initAlpha = function () {
return 100;
}:
// Добавление нового свойства MovieClip.alpha (без подчеркивания!)
MovieClip.prototype.addProperty("alpha". getAlpha. setAlpha);
MovieClip. prototype, alpha Internal = initAlphaO;
На этот раз метод addProperty() создает новое свойство MovieClip с именем alpha
(без подчеркивания), для чтения и записи которого используются методы дос-
тупа. Свойство работает точно так же, как и MovieClip._alpha, но оно избавлено от
проблем с округлением за счет использования промежуточной переменной
alphalnternal.
Следующий фрагмент создает в обработчике onEnterFrame эффект растворения,
который останавливается при уменьшении свойства alpha до нуля:
myClip.onEnterFrame = functionO {
this.alpha--:
i f (this.alpha == 0) {
delete this.onEnterFrame;
traceC'done")
112 Глава 3. Рисование и маски

Если бы вместо пользовательского свойства alpha (без подчеркивания) исполь-


зовалось встроенное свойство _alpha (с подчеркиванием), обработчик onEnterFrame
никогда бы не завершил свою работу, потому что значение _alpha никогда не
уменьшилось бы до нуля:
myClip.onEnterFrame = functionO {
this._alpha--;
i f (this._alpha == 0) {
delete this.onEnterFrame;
traceC'done")

Итоги
Анимированные альфа-эффекты интенсивно используют вычислительные мощ-
ности процессора, поэтому потенциальная неточность свойства _alpha способна
сильно замедлить работу приложения. Клип с альфа-уровнем 99,6078 % внешне
не отличается от клипа с альфа-уровнем 100 % (то есть полностью непрозрачно-
го), но воспроизводится гораздо медленнее! Чтобы написать эффективный код
анимации альфа-эффекта, необходимо знать о потенциальных ошибках округле-
ния свойства _alpha и уметь справляться с ними.
Вероятно, борцы за чистоту ООП брезгливо поморщатся при виде решения в сти-
ле ActionScript 1.0, основанного на применении прототипов, однако этот синтак-
сис поддерживается в ActionScript 2.O. Помните, что субклассы ActionScript 2.0
компилируются в тот же байт-код, что и решение с применением прототипов.
Используйте тот вариант, который вам кажется более удобным (наследование
на базе прототипов, композиция или формальное наследование).

Использование сложных фигур


в качестве масок
Flash не поддерживает маски с внутренними отверстиями (например,
в форме бублика). Как обойти это ограничение?
Маски - один из аспектов Flash, которые на первый взгляд находят мало прак-
тических применений, однако опытные Flash-разработчики хорошо знают, что
маски задействованы едва ли не в каждом нетривиальном графическом эффекте
Flash. Как объяснялось в начале главы 1, маски могут назначаться как на стадии
разработки, так и на стадии выполнения.
Flash MX стал первой версией с поддержкой сценарных масок, то есть масок,
динамически назначаемых на стадии выполнения методом MovieClip.setMask().
Естественно, разработчик должен учитывать влияние сценарных масок на быст-
родействие приложения.
В бета-версии Flash MX фирма Macromedia разрешила использовать в качестве
масок фигуры произвольной сложности, но позднее отменила эту возможность
по соображениям быстродействия. Одним из самых яростных противников зап-
Использование сложных фигур в качестве масок 113

рета на использование сложных масок стал Эрик Нацке (http://www.natzke.com).


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

Сложные маски
Маски Flash должны быть сплошными. Если в качестве маски используется слож-
ная фигура (например, бублик), Flash упрощает ее. В этом нетрудно убедиться
на следующем простом примере.
В новом документе присвойте первому слою имя background, затем добавьте над
ним два уровня с именами maskLayer и actions (рис. 3.24).

Рис. 3.24. Подготовка слоев для демонстрационного примера

На слое background создайте заполненный прямоугольник, накрывающий всю


сцену. Назначьте ему линейную градиентную заливку, как показано на рис. 3.25.
Нажмите клавишу F8, чтобы преобразовать прямоугольник в символ анимаци-
онного клипа, и присвойте ему имя back в диалоговом окне Symbol Properties.
Введите имя экземпляра backClip на панели свойств. Заблокируйте слой.

iiiiiiiie
• •• 1Ё1Й! |Я1Щ|1§1

Рис. 3.25. Градиент


114 Глава 3. Рисование и маски

На слое maskLayer создайте фигуру в виде бублика (рис. 3.26). Нажмите клави-
шу F8, чтобы преобразовать ее в символ анимационного клипа. Присвойте сим-
волу имя mask, задайте клипу имя экземпляра maskClip.


I
i
L Л •

i
:
'•:•• • •, •••,:•:. '.; : i |- / г •

Рис. 3.26. Фигура в виде бублика над прямоугольником с градиентной заливкой

Наконец, свяжите следующий сценарий с кадром 1 слоя actions:


function dragDrop(mc:MovieClip){
mc.onPress = functionO {
this.startDrag(true):
this.onMouseMove = functionO {
updateAfterEventO:

}
mc.onMouseUp = functionO
delete this.onMouseMove;
this.stopDragO;

}ragDrop(maskCp
d il):
backCpil.setMask(maskCp
il);
Небольшое отступление: плавное перетаскивание клипа является задачей на-
столько распространенной, что для ее решения стоит создать специальный класс.
Далее приведен пример класса для выполнения плавного перетаскивания:
// Этот код ActionScript 2.0 должен храниться
// во внешнем файле SmoothDrag.as
class SmoothDrag {
public function SmoothDrag(targetClip:MovieClip) {
dragDrop(targetClip);
}
private function dragDrop(mc:MovieClip):Void {
Использование сложных фигур в качестве масок 115

mc.onPress = functionO {
mc.onMouseMove = functionO {
updateAfterEventO;

}
mc.onMouseUp = functionO
delete mc.inMouseMove;
mc.stopDragO;

При наличии такого класса программа сокращается до пары строк:


var myClipDraggerSmoothDrag = new SmoothDrag(maskClip);
backClip.setMask(maskClip):
Однако мы продолжим разработку с исходной версией, не использующей класс.
Функция dragDrop() позволяет перетаскивать maskClip мышью; при отпускании
кнопки мыши клип «сбрасывается». Казалось бы, после назначения maskClip
маской для backClip мы должны видеть только ту часть backClip, которая нахо-
дится под maskClip.
Но на самом деле будут видны все области backClip, находящиеся внутри пери-
метра maskClip. Flash превращает сложную маску-«бублик» в простой круг
(рис. 3.27).

Рис. 3.27. Бублик превращается в круг

Для масок Flash устанавливается одно важное ограничение: они должны иметь
непрерывный периметр. Таким образом, если прорезать в «бублике» небольшую
щель, его контур будет непрерывным. Проблема в том, что после вырезания
щели О-образный бублик превратится в букву С. Щель должна быть настолько
маленькой, чтобы Flash игнорировал ее при выводе, но достаточно большой для
того, чтобы вся фигура рассматривалась как единая форма с непрерывным пери-
метром. Для этой цели будет использоваться прорезь в виде волосяной линии.
Выделите экземпляр maskClip и дважды щелкните на нем, чтобы перейти в ре-
жим редактирования «на месте». Активизируйте инструмент Line и нарисуйте
волосяную линию по радиусу «бублика», как показано на рис. 3.28.
116 Глава 3. Рисование и маски

•Ы-ihairtne-
У Urn
tool

Рис. 3.28. Добавление волосяного разреза к маске в виде бублика

В ы д е л и т е н а р и с о в а н н у ю л и н и ю и в ы п о л н и т е к о м а н д у Modify • S h a p e • Convert
Lines to Fills, чтобы преобразовать линию в фигуру. Обратите внимание: толщина
созданной линии меньше 1 пиксела (на моем компьютере она составляет 0,3 пик-
села). Теперь удалите фигуру. После удаления на «бублике» остается щель тол-
щиной 0,3 пиксела. Если увеличить масштаб и сравнить изображение с сеткой
пикселов, как показано на рис. 3.29, становится видно, что толщина линии мень-
ше 1 пиксела.

Рис. 3.29. Щель толщиной менее 1 пиксела

Хотя Flash считает, что мы создали букву С с единым непрерывным перимет-


ром, механизм визуализации рисует фигуру в виде буквы О без каких-либо про-
резей. Убедитесь в этом, выполнив команду Control • Test Movie.
Возможен один из двух результатов. Если повезет, вы увидите маску в форме
бублика без всяких пробелов, как на рис. 3.31. Если не повезет, на маске будет
видна волосяная линия, как в левой части рис. 3.30 (справа та же линия изобра-
жена при большом увеличении).

Рис. 3.30. Маска с тонким разрывом (слева) и она же при большом увеличении (справа)

При возникновении проблемы, изображенной на рис. 3.30, воспользуйтесь ин-


струментом Subselection и уменьшите разрыв. Иногда проблему удается решить
при помощи режима Snap to Pixel: переместите край прорези, удаленный от ли-
Интерференционные картины и волновые эффекты 117

нии привязки, и совместите его с линией. В итоге должна получиться идеальная


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

Рис. 3 . 3 1 . Идеальная маска в форме бублика

В трюке 21 будут продемонстрированы некоторые интересные эффекты, создан-


ные с помощью бесполезных на первый взгляд масок.

Интерференционные картины
ТРЮК

№21 и волновые эффекты


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

Рис. 3.32. Интерференционная картина, нарисованная при помощи масок


118 Глава 3. Рисование и маски

Эффект на рис. 3.32 был создан при помощи двух наборов концентрических
колец с прорезями (см. трюк 20), гарантирующими, что в масках, несмотря на их
внешний вид, отсутствуют замкнутые области. При размещении фигур друг над
другом получается однородный круг, но если сместить одну фигуру и назначить
ее маской для другой, получится узор, изображенный на рис. 3.32. А если умень-
шить толщину кругов и сблизить их, картина приобретает по-настоящему пси-
ходелический вид (рис. 3.33).

Рис. 3.33. Интерференционная картина с масками,


состоящими из концентрических колец

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

Рис. 3.34. Волновой эффект, созданный применением маски к изображениям листьев

Итоги
Многие разработчики недооценивают возможности масок. Хотя в документации
Flash сказано, что маски предназначены для скрытия контента, в действительно-
Сглаживание краев на растровых изображениях 119

сти эта формулировка не дает должного представления о том, что можно сде-
лать при помощи масок. Область применения масок чрезвычайно широка - от
экзотических переходных эффектов до сугубо утилитарных пользовательских
компонентов. Когда сценарные маски впервые появились в Flash, они стали на-
стоящим даром небес для квалифицированных разработчиков. Позднее народ
осознал ограниченность простых масок. Но после знакомства с представленным
трюком препятствий на вашем пути станет гораздо меньше!
Еще один пример нетривиального использования масок встречается при описа-
нии трюка с листанием страниц (см. трюк 25).

Сглаживание краев на растровых


ТРЮК

№22 изображениях
Векторная графика при любом разрешении отличается хорошим сгла-
живанием краев, но" в некоторых ситуациях приходится использовать
растровые изображения. От очевидных дефектов краев растровых изо-
бражений можно избавиться при помощи альфа-канала или векторных
краев.
Иногда растровая графика оказывается предпочтительнее векторной, особенно
при работе с текстурными объектами (в отличие от областей с однородной или
почти однородной заливкой, которые лучше представляются в векторной графи-
ке). Именно эта причина обусловила применение растровых изображений в не-
которых современных анимациях (хорошие примеры - http://www.centrifuga.net/
desiderata.html и http://www.centrifuga.net/gab.html).
Серьезным недостатком растровых изображений является пикселизация. В на-
стоящем трюке представлены два способа борьбы с неровностями краев на рас-
тровых изображениях. Как правило, пикселизация сильнее всего проявляется
при резких различиях между цветами изображения и его фона (на границах
с менее резкими переходами цветов пикселизация обычно не столь заметна). На
техническом жаргоне эти зубчатые линии обычно называются «пилой». Впро-
чем, такая ступенчатость характерна для любых цифровых данных (в том числе
и звуковых - см. трюк 58) при недостаточной частоте выборки, которая и явля-
ется причиной появления артефактов. Методика решения проблемы носит на-
звание сглаживания (antialiasing). Одно из решений основано на применении
альфа-прозрачности: размывка областей, прилегающих к краям растрового изоб-
ражения, улучшает слияние с фоном и одновременно предотвращает эффект
ореола (когда изображение окружается по периметру светлыми пикселами).

Размывка краев растровых изображений


Предположим, мы хотим импортировать в Flash растровое изображение с рис. 3.35.
На расстоянии смотрится очень мило, но при увеличении пограничных облас-
тей крыльев становятся отчетливо видны ужасные зазубрины (рис. 3.36).
120 Глава 3. Рисование и маски

Рис. 3.35. Растровое изображение бабочки

Рис. 3.36. Неровности контура, заметные при увеличении

Один из способов избавиться от неровностей основан на размывке краев в Photo-


shop перед импортированием графики в Flash.
Загрузите изображение в Photoshop. Если потребуется, «сплющите» изображение,
чтобы все пикселы находились на одном слое Photoshop с именем Background. Photo-
shop не обладает простыми средствами задания альфа-уровня для пикселов этого
слоя. Щелкните правой кнопкой мыши (Windows) или щелкните с нажатой клави-
шей «HI (Mac) на этом слое на панели Layers, выберите в контекстном меню команду
Duplicate Layer. Подтвердите имя, предложенное по умолчанию (Background copy).
Выделите фоновую область вокруг изображения при помощи инструмента Photoshop
Magic Wand. Чтобы предотвратить появление ореола, выполните команду Select •
Modify • Expand и расширьте выделение на 1 пиксел. Удалите фон нажатием кла-
виши Delete; результат показан на рис. 3.37.
Сглаживание краев на растровых изображениях 121

Рис. 3.37. Изображение бабочки без фона

В процессе удаления фона были утрачены усики бабочки, но в Flash мы заменим


их двумя векторными кривыми.
Далее производится размывка - постепенное изменение, цвета, скрывающее
пикселизацию краев.
Не снимайте выделения с контура, а если оно было случайно снято - восстано-
вите его, щелкнув инструментом Magic Wand в любой точке изображения, не
содержащей пикселов (то есть помеченной клеточным узором). Выполните ко-
манду Select • Feather и задайте параметру Feather значение 2 пиксела. Исполь-
зуя инструмент Eraser (100% непрозрачный), сотрите контур вдоль периметра
выделенной области. На рис. 3.38 показано, как выглядит край растрового изоб-
ражения до и после выполнения операции.

Рис. 3.38. Изображение до (слева) и после (справа) размывки края в Photoshop


122 Глава 3. Рисование и маски

Если потребуется, повторите размывку с интервалом в 1 пиксел.


Наконец, сохраните изображение в формате PNG командой File • Save As. Photo-
shop предложит выбрать сохранение файла в чересстрочном (Interlaced) или обыч-
ном (Non-interlaced) формате. Выберите второй вариант. Импортируйте файл
в Flash командой File • Import • Import to Library; перетащите ресурс из библиоте-
ки на сцену, чтобы использовать его на временной диаграмме.
На рис. 3.39. видно, что после размывки крыло бабочки выглядит гораздо менее
пикселизованным, чем на исходном растре.

Рис. 3.39. Край размытого (слева) и неразмытого (справа) растра при увеличении

Размывка края производится изменением альфа-уровня, а не цветовым перехо-


дом; если поместить бабочку на любой фон, она так же нормально сольется с фо-
ном. Хотя такое решение расширяет возможности работы с изображением, в неко-
торых случаях изменение альфа-канала нежелательно - особенно если изображение
будет воспроизводиться в Flash на однородном цветном фоне.

Добавление векторного контура


ТРЮК

№23 к растровому изображению


Если графика должна содержать и текстуры, и четко очерченный край, воз-
никает противоречие. Векторные фигуры обеспечивают четкие очертания,
но не позволяют использовать сложные текстуры. Растры обеспечивают
сложные текстуры, но не имеют четких краев. Возьмите все лучшее от
векторной и растровой графики и создайте растр с векторным контуром.
В некоторых видах графики (например, в логотипах или других графических
конструкциях, содержащих текст или «острые» края, отличающиеся от плавно
закругленного крыла бабочки) методика размывки (см. трюк 22) приводит к по-
тере четкости краев оригинала. К счастью, можно пойти по обратному пути и соз-
дать векторные очертания для растровых объектов.
Давайте попробуем спрятать неровности под векторным контуром или удалить
их при помощи векторной маски.
Описанные далее операции с растровым изображением выполняются в Photoshop,
но аналогичного результата можно добиться и в других графических редакто-
рах, включая Fireworks.
Добавление векторного контура к растровому изображению 123

Выделите изображение, созданное в предыдущем трюке (см. трюк 22), и экспор-


тируйте его в формат P N G командой File • Save As. Также необходимо экспорти-
ровать второе изображение, в котором все ненулевые пикселы окрашены в чер-
ный цвет (рис. 3.40). В Photoshop это делается командой Image • Adjustment •
Brightness/Contrast. Переведите оба ползунка в диалоговом окне Brightness/Contrast
в крайнее левое положение, чтобы все пикселы окрасились в черный цвет.

Рис. 3.40. Черный силуэт (слева) исходного изображения бабочки (справа)

И м п о р т и р у й т е о б а и з о б р а ж е н и я в F l a s h к о м а н д о й File • Import • Import t o S t a g e .


Выделите черный силуэт и преобразуйте его в векторную форму командой
Modify • Bitmap • Trace Bitmap - получится черная векторная фигура. Если опре-
делить для нее контур, он будет точно соответствовать внешним очертаниям
растрового изображения.
Мы можем либо создать контурную линию, как на рис. 3.41, либо использовать
фигуру как стандартную векторную маску. Второй способ более очевиден, но
зато первый более эффективен с точки зрения производительности, потому что
Flash не приходится многократно применять маску (а это может быть весьма
существенно, если растр позднее потребуется анимировать)

Рис. 3 . 4 1 . Контур растрового изображения

Преобразование PNG в векторную форму не приводит к созданию черной фигу-


ры, заключенной в белую фигуру (как при импортировании растрового изобра-
жения с фигурой на белом фоне). Поскольку в файле PNG фон отсутствует,
124 Глава 3. Рисование и маски

a Flash правильно преобразует пикселы с нулевым альфа-уровнем в «отсутствие


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

Рис. 3.42. Создание контура.

Произведите разбивку растра командой Modify • Break Apart. Это позволит рабо-
тать с растром, применяя векторные инструменты.
Переместите векторный контур с текущего слоя на один слой с растровым изоб-
ражением. Перемещение проще всего выполняется через буфер обмена:
1) заблокируйте все слои кроме слоя, на котором находится векторный контур;
2) нажмите клавиши Ctrl+A (Windows) или «Н>+А (Мае), чтобы выделить контур.
Скопируйте его в буфер клавишами Ctrl+X (Windows) или §€+Х (Мае);
3) разблокируйте слой, на котором находится растровое изображение. Заблоки-
руйте все остальные слои. Убедитесь в том, что текущее выделение отсутствует,
щелкните правой кнопкой мыши (Windows) или щелкните с нажатой клави-
шей Ж (Мае) и выберите в контекстном меню команду Edit • Paste in Place.
Выделите остальные пикселы за пределами контура и нажмите клавишу Delete.
Наконец, осторожно удалите контур (рис. 3.43) - вокруг растрового изображе-
ния появляется идеально четкая векторная граница!
Исправление ошибки сдвига 125

Рис. 3.43. После удаления контура открывается четкая векторная граница

Растровое изображение превратилось в гибридную конструкцию, обладающую


преимуществами как векторной графики (четкие края), так и растровой графи-
ки (сложные текстуры). Что еще интереснее, остается возможность редактиро-
вания векторного края. Да, вы не ошиблись - при необходимости его даже мож-
но анимировать (рис. 3.44).

Рис. 3.44. Анимация векторного контура растрового изображения

Итоги
Настоящий раздел убедительно показывает, что для интеграции растров в четко
очерченный векторный мир Flash можно сделать довольно много. Круг возмож-
ностей не ограничивается скрытием неровностей при помощи альфа-масок -
существует и такой вариант, как создание «псевдовекторной фигуры», состоя-
щей из растра с векторным контуром (впрочем, правильнее было бы назвать ее
векторным контуром с растровой заливкой).

Исправление ошибки сдвига


В Flash Player версий 6 и ниже растровые изображения искажаются и отоб-
ражаются в неверной позиции. Необходимо выяснить, как сместить рас-
тровое изображение в нужное место и внести поправку на искажение
в этих версиях Flash Player.
Как правило, сложные инструменты не идеальны. Это относится и к Flash Player -
вам придется освоить некоторые трюки для исправления его недостатков. Одним
126 Глава 3. Рисование и маски

из таких недостатков является ошибка сдвига растровых изображений. Она по-


явилась в ранних версиях Flash Player и была исправлена лишь недавно в Flash
Player 7.
Даже тем, кто создает анимацию в Flash MX 2004, придется решать эту пробле-
му при экспортировании роликов для Flash Player версии 6 и ниже. А если учесть,
что Flash Player 7 еще не получил повсеместного распространения, наверняка
разработчикам придется еще некоторое время иметь дело с этой проблемой.
Flash прежде всего использует векторный механизм визуализации, а функции
отображения растровой графики в Flash Player содержат ряд ошибок, приводящих
к искажению растровых изображений. В результате откомпилированная анимация
Flash в браузере не всегда выглядит так, как при тестировании в среде разработки:
растровые изображения сдвигаются и дергаются даже в том случае, если к ним
не применялись эффекты движения. Ошибка сдвига растровой графики описана
в техническом документе Macromedia 14256 «Bitmaps shift in Macromedia Flash»
(http://www. macromedia. com/support/flash/ts/documents/bitmaps_shift. html).
На практике это означает, что при использовании растровой графики в Flash
часть изображения сдвигается на 1 пиксел вправо и вниз. Обратите внимание:
сдвигается не все изображение, а только некоторые пикселы внутри него. Поми-
мо сдвига происходит искажение графики: одни строки/столбцы пикселов исче-
зают, другие повторяются. Если изображение используется в анимационном
клипе, в зависимости от точки регистрации (начала координат клипа) искаже-
нию подвергаются разные части изображения.
Сказанное проще пояснить наглядным примером. Допустим, у нас имеется
изображение (слева, рис. 3.45). При импортировании в среду разработки Flash
(в том числе и Flash MX 2004) разместите его по границам пикселов, без дроб-
ных значений координат X и У, и экспортируйте его как клип Flash Player 6.
В результате будет получено искаженное изображение, показанное в правой части
рис. 3.45.

Рис. 3.45. Исходное изображение (слева) и результат ошибки сдвига (справа)

Графические данные сдвигаются вниз и вправо. Хотя левый столбец и верхняя


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

Неправильные способы решения проблемы


Данная ошибка хорошо известна в сообществе Flash, хотя большинство разработ-
чиков плохо представляет, как решить эту проблему. К сожалению, получил рас-
пространение целый ряд «решений», которые приносят больше вреда, чем пользы.
Итак, при исправлении ошибки сдвига растров постарайтесь избегать следую-
щих приемов (или, по крайней мере, применяйте их осознанно и осторожно):
Исправление ошибки сдвига 127

• применения к изображению 99 % альфа-уровня. Этот способ избавляет от мер-


цания в кадрированной анимации, но искажает цвета изображения (пусть и
незаметно) и замедляет воспроизведение анимации на фоне изображения.
Кроме того, он не решает проблему со сдвигом графического содержания;
• использования прозрачной границы толщиной 2 пиксела. Прием создает до-
полнительные неудобства при реализации (все изображения приходится со-
здавать с прозрачной границей) и не решает проблему сдвига содержания,
а, скорее, скрывает ее от пользователя;
• включения режима Allow Smoothing в свойствах растрового изображения в биб-
лиотеке. Это избавляет от неприятного мерцания при переходе от подвижно-
го изображения к статическому, но не имеет отношения к ошибке сдвига и не
решает проблемы;
• разбиения изображения и его перемещения по частям. Фактически, проблема
делится на несколько частей и перемещается в другие, менее заметные фраг-
менты изображения;
• малозаметного масштабирования изображения. Хотя масштабирование предот-
вращает нежелательные смещения пикселов, оно все равно приводит к моди-
фикации исходного изображения.
Представленные «решения» могут быть эффективными до некоторой степени,
но в действительности они не решают проблему, поэтому рекомендовать их я бы
не стал (кроме масштабирования, которое может пригодиться в одном специфи-
ческом случае - с м . далее).

Исправление ошибки (правильный способ)


При тщательном анализе выясняется, что ошибка происходит только при поло-
жительных значениях координат X и Y изображения внутри клипа или на сцене.
Таким образом, простейшее решение заключается в перемещении изображения
в область клипа, в которой Flash Player для вычисления позиций каждого пиксе-
ла придется использовать отрицательные числа. Сделать это несложно: размес-
тив изображение на сцене в нужной позиции, преобразуйте его в символ анима-
ционного клипа нажатием клавиши F8. В диалоговом окне Convert to Symbol
(рис. 3.46) введите имя символа и, что не менее важно, выберите в качестве
точки регистрации правый нижний квадратик. В результате содержание клипа
(то есть растровое изображение) размещается слева наверху от начала коорди-
нат (в квадранте с отрицательными значениями X и У).

гййЭЗИ ок
! : :
Ш^ШШШЩ^ Щ1ШР^^?^- Й&: •• • • Cancel'

Рис, 3.46. Назначение точки регистрации в диалоговом окне Convert to Symbol


128 Глава 3. Рисование и маски

Перемещение точки регистрации исправляет ошибку сдвига при работе с рас-


тровой графикой в среде разработки Flash - ни искажения, ни мерцания уже не
будет.
И все же одна проблема остается - фирма Macromedia «исправила» ошибку
в Flash Player 7, хотя на самом деле речь идет о простой замене знака! В Flash
Player 7 ошибка сдвига возникает при отрицательных, а не при положительных
значениях X и Y. Это объяснялось тем, что практически все разработчики разме-
щают графику в области положительных координат клипа.

ПРИМЕЧАНИЕ
Получается, что, исправляя ошибку для Flash Player 6, вы создаете ошибку в Flash
Player 7. Если результат должен экспортироваться в формат Flash Player 7, не
используйте этот трюк.

Исправление ошибки в динамически загружаемых


файлах (эффективный способ)
Хотя предыдущее решение позволяет справиться с ошибкой сдвига при работе
с растровой графикой в среде разработки Flash, оно не подходит при загрузке
изображений в Flash методом loadMovieQ. К сожалению, точку регистрации за-
груженного изображения нельзя сместить так, чтобы изображение находилось
в левом верхнем квадранте (с отрицательными координатами X и Y): поскольку
загруженное изображение само является контейнером клипа, его содержимое
окажется в области положительных координат. Например, следующий фрагмент
приводит к ошибочному результату, представленному на рис. 3.45, - графиче-
ское содержание сдвигается вниз и вправо:
// Создание и загрузка изображения на сцене-
thi s.createEmptyMovieClip("mylmage". 1);
this.mylmage.1oadMovie("testImage.jpg"):
Тем не менее, у проблемы существует простое решение. Масштабируя изобра-
жение с ничтожным уменьшением - настолько малым, что оно остается неза-
метным для зрителя, - можно заставить Flash Player использовать точные значе-
ния, вследствие чего итоговое изображение выглядит правильно при вычислении
позиции пиксела. Изменение масштаба должно производиться после загрузки
изображения.
Существует несколько способов незначительного масштабирования изображе-
ний. В следующей программе сразу же после загрузки изображения автомати-
чески выдается команда на изменение размеров, обеспечивающая исправление
ошибки:
// Создание и загрузка изображения в клипе mylmage
// и его размещение на сцене.
this.createEmptyMovieClip("mylmage". 1):
thi s.mylmage.1oadMovie("test Image.jpg"):

// Создание клипа-"наблюдателя" для исправления размеров изображения


// сразу же после его загрузки.
Эффект листания страниц 129

this.createEmptyMovieClip("myImageLoader". 2);
this.mylmageLoader.onEnterFrame = functionO {
i f (this._pa'rent.mylmage._width > 1) {
// Изображение было загружено
this._pareirt. my Image. _xscale = 99.98:
this._pa rent, my Image. _yscale = 99.98;
thi s.removeMovi eCli p():

В общем случае масштабировать изображения не рекомендуется, но в данном


конкретном случае этот прием допустим как оптимальный способ предотвраще-
ния ошибки сдвига. Как правило, искажение, обусловленное изменением разме-
ров, остается незаметным для зрителя. Например, в предыдущем фрагменте из-
менение размеров решает проблему сдвига без изменения ширины и высоты
изображения; если после загрузки изображения вывести свойство _width функ-
цией trace(), вы заметите, что изображение сохранило исходную ширину.
Зё Фернандо

ТРЮК Эффект листания страниц


№25 Создание анимации листания страниц и других эффектов Flash с исполь-
зованием сценарных масок и свойства симметрии.
Многие разработчики при виде нетривиальных эффектов Flash думают: «Ого!
Интересно, как это сделано?» После просмотра чернового варианта этой главы я
не мог отделаться от ощущения, что в ней отсутствует один важный момент: как
придумывать новые графические эффекты или воспроизводить фокусы, создан-
ные другими дизайнерами. На первый взгляд, умение воссоздать эффект, просто
взглянув на анимацию SWF, выглядит некой разновидностью шаманства, но в дей-
ствительности задача вполне реальная, если научиться выделять стандартные
структурные аспекты (наподобие того, как мы воспроизводим музыкальное про-
изведение на гитаре, прослушав его несколько раз).
В этом трюке я покажу, как выполнялось деконструирование модного эффекта
листания страниц. Но сначала давайте рассмотрим базовый структурный аспект -
симметрию. Кстати, в работе нам пригодятся хорошо знакомые маски.

Математический зеркальный коридор


В математике выражение в левой части конструкции со знаком «=» приравнива-
ется к выражению в правой части:
3=1+2;
е = тс2.
Многие дизайнеры, с которыми я знаком, при виде уравнений начинают пя-
титься к двери, потому что они предпочитают мыслить на визуальном уровне.
Конечно, они забывают о том, что приведенные выше уравнения просто отража-
ют визуальную концепцию симметрии.
130 Глава 3. Рисование и маски

Знак равенства можно рассматривать как формальное представление зеркала.


Выражение в левой части равно выражению в правой части. Как только вы осоз-
наете этот факт, в вашем распоряжении появляется мощный инструмент для
создания графических эффектов. (Не путайте знак равенства в обычной матема-
тике с оператором присваивания = в ActionScript: оператор вычисляет значение
выражения в правой части и присваивает его переменной или свойству в левой
части. В данном трюке речь идет о симметрии/равенстве в математическом по-
нимании. Если уж на то пошло, в ActionScript для проверки равенства использу-
ются операторы == и ===.)
Каждый раз, когда вы планируете новый эффект (или пытаетесь воспроизвести
самый популярный фокус этого месяца), прежде всего поищите симметрию. Чтобы
показать, как это делается, мы рассмотрим эффект, который на первый взгляд
кажется очень сложным. Но при всей внешней нетривиальности этот эффект
основан на простой симметрии.

Листание страниц
Недавно арсенал классических трюков Flash пополнился эффектом листа-
ния страниц (один из ранних примеров можно найти по адресу http://wel-
come.hp.com/country/us.en/msg/corp/flashdreamworks.html). Во время началь-
ного обсуждения подборки трюков для включения в книгу мой редактор Брюс
Эпстейн сказал: «Было бы здорово, если бы мы могли описать эффект листа-
ния страниц. Я видел, как Эрик Нацке кратко описывал процесс на семинаре
Flash Forward. Ты знаешь, как это делается?» Я понятия не имел, как реали-
зовать этот трюк, но во время разговора я машинально делал наброски
(я вообще всегда что-нибудь рисую, когда говорю по телефону, - это помога-
ет думать).

Рис. 3.47. Реализация эффекта листания страниц

На рис. 3.47 представлена схема моего решения эффекта листания страниц. Ри-
сунок дает полное представление об идее, на которой базируется весь эффект;
набросав эту схему, я сразу сказал Брюсу: «Думаю, я довольно быстро разберусь
с этим эффектом, ставь его в план».
Эффект листания страниц 131

Что же означает рисунок, и как я пришел к этой мысли?


Прежде всего было ясно, что эффект листания страниц как-то связан с листани-
ем страниц (надо же!), поэтому я нарисовал переворачиваемую страницу.
Далее: я знал, что в большинстве сценарных эффектов в том или ином виде
используется симметрия, поэтому и продолжал смотреть на диаграмму до тех
пор, пока не нашел симметричную структуру. На этот раз она находилась на
самом видном месте. Треугольник, изображающий перелистываемую страницу,
является зеркальным отображением треугольника, находящегося под ним. Два
треугольника симметричны относительно пунктирной линии А (рис. 3.47). В кон-
це анимации с переворачиваемой страницей появляются две страницы, симмет-
ричные относительно корешка книги. Фактически, ось симметрии А перемеща-
ется в положение В. В сущности, сценарий анимации переворота страницы
сводится к перемещению оси симметрии во время анимации!
Симметрия встречается в природе, при работе с фракталами (зеркальное вос-
произведение одного процесса на всех уровнях) и частицами (построение боль-
ших эффектов из множества мелких идентичных эффектов). Природа также ча-
сто вносит элементы симметрии в иерархии, поэтому сама симметрия может
иметь рекурсивную природу, как при ветвлении дерева (см. трюк 6).
Практически все сложные эффекты строятся на базе симметрии. Графические
эффекты Flash, не использующие симметрию (обычно с некоторой долей слу-
чайности, чтобы изображение не казалось слишком симметричным), можно пе-
ресчитать по пальцам.
Схема изображения на рис. 3.47, представляет собой то, что я называю визуаль-
ным уравнением. Как и в математическом уравнении, в нем есть знак равенства,
но речь идет о равенстве в его исходной форме - визуальном представлении
проблемы, а не о переходе к абстрактному миру математических уравнений. Схема
указывает, что некоторые части уравнения симметричны (равны) относительно
пунктирных линий.
Центральная линия со знаком равенства нарисована исключительно для нагляд-
ности - не думайте, что это какое-то стандартное обозначение. Впрочем, в гео-
метрии поперечные знаки равенства на отрезках означают, что эти отрезки име-
ют равную или пропорциональную длину.
Что же, исходные условия ясны. Но как эффект работает на практике? Перехо-
дим к следующей фазе - "формулировке отношений, которые описывают проис-
ходящее во времени.
В процессе анимации (изображенной в виде четырех рисунков слева направо на
рис. 3.48) изменяется прежде всего позиция оси симметрии. Сначала она распо-
лагается под углом 45° в правом нижнем углу переворачиваемой страницы, а за-
тем перемещается в левый верхний угол той же страницы под углом 90° (то есть
принимает вертикальное положение).
Ось симметрии - всего лишь концепция, заложенная в основу эффекта, а не
сам эффект. Помните об этом в процессе обобщения! Чтобы создать эффект,
нужно разбить его на легко реализуемые составляющие. Примерный путь к ре-
шению показан на рис. 3.49.
132 Глава 3. Рисование и маски

§11

Рис. 3.48. Перемещение оси симметрии

Анимация эффекта основана на перемещении двух клипов вокруг оси симмет-


рии. Один клип - зеркальное отражение переворачиваемой страницы (для на-
глядности назовем его reverse_mc). В начальном положении он повернут на 90°
и находится в позиции пунктирного прямоугольника на рис. 3.49. Клип reversejnc
стремится совместить свой правый край с осью симметрии. Другой клип - мас-
ка для клипа reversejnc; назовем его maskReversejnc. В начальном положении
клип наклонен под углом 45°, а в конечном положении он должен занять ту же
позицию, что и reversejnc. Это означает, что в конце анимации клип reversejnc
виден полностью, поскольку ни одна из его частей не скрывается маской.

Маска для зеркального отражения


Текущая страница

W^ г.

[Зеркальное отражение переворачиваемой страницы

Рис. 3.49. Одна из двух масок, контролируемых осью симметрии

Из факта симметрии следует, что светло-серая область на рис. 3.49 (видимая


область новой страницы) симметрична рассматриваемой области. Открываемый
клип остается неподвижным, но его маска ведет себя почти так же, как maskRe-
verse_mc: она двигается аналогично, но симметрично относительно оси. На
рис. 3.50 новая маска обозначена именем maskNewjnc.

maskReverse me

maskNew me

Рис. 3.50. Зеркальная маска


Эффект листания страниц 133

Симметричность двух масок относительно оси объясняет, почему площади пе-


реворачиваемой и открываемой страниц остаются симметричными. В данном
случае мы имеем дело с проявлением иерархии симметрии; вероятно, вы уже
понимаете, что весь эффект представляет собой набор особым образом располо-
женных зеркал!

Итоги
Эффект листания страниц впервые был создан Эриком Нацке (http://
www.natzke .com), выдающимся дизайнером и автором многих впечатляющих
SWF. Именно после знакомства с его работами я осознал, что многие графичес-
кие эффекты базируются на симметрии и эффектах частиц (а иногда - и том
и другом!) Соответствующий образ мысли поможет вам не только воспроизвес-
ти работы Эрика, но и расширить их.
В этом трюке представлены основные концепции эффекта листания страниц,
демонстрирующие общий подход к воссозданию подобных эффектов:
• найдите и выделите базовые структурные элементы (из которых самым рас-
пространенным является симметрия, но также встречаются и другие - на-
пример, фракталы и эффекты частиц). Нарисуйте диаграммы с указанием
места этих концепций в эффекте. Используйте ту систему наглядных обозна-
чений, которая вам покажется наиболее удобной;
• чтобы развить идею, сделайте дополнительные наброски, описывающие пе-
реход от базовой идеи к ее реализации в Flash. Если вы не понимаете, как
создается эффект, скорее всего, в нем используется маска. По собственному
опыту могу сказать, что маски в сочетании со сценариями обычно создают
самые неочевидные эффекты;
• не пытайтесь немедленно преобразовать все концепции в математические
формулы, потому что визуальное предоставление упрощает выделение зако-
номерностей или поиск полезных концепций высокого уровня. Несмотря на
все преимущества, математические уравнения плохо подходят для преобра-
зования в визуальную форму. Они скорее абстрактны, нежели визуальны (ве-
роятно, именно из-за этого большинство дизайнеров испытывает к ним под-
сознательное отвращение!).
В этом трюке основное внимание уделено анализу сути эффекта, а не его реали-
зации. Надеюсь, вы согласитесь с тем, что этот аспект более важен. Освойте его,
и у вас появится ключ, который позволит немедленно раскрыть сущность любо-
го новомодного графического эффекта.
Пример реализации эффекта листания страниц pageturn.fla находится на сайте
книги.
ГЛАВА 4

Анимация
Трюки № 26-34
Настоящая глава посвящена подлинной сущности Flash: анимации. Интерфейс
Flash основан на приемах традиционной покадровой анимации. Временная диа-
грамма Flash является электронным аналогом серии кадров; каждый кадр пред-
ставляет собой квант времени, а отображение последовательных кадров создает
иллюзию движения. Во Flash, как и в традиционных средствах анимации, под-
держивается концепция слоев, используемых для последовательного формиро-
вания анимации от заднего плана к переднему; разные элементы располагаются
на разных глубинах.
Ключевые и промежуточные кадры Flash тоже покажутся знакомыми всем, кто
имел дело с традиционной анимацией: обычно ведущий художник рисует клю-
чевые кадры, а его подручные занимаются черновой работой по построению
промежуточных кадров. В Flash ключевые кадры создает дизайнер, a Flash авто-
матически генерирует промежуточные изображения. Все изменения, вносимые
аниматором (например, перемещение графики на новое место), должны проис-
ходить в ключевых кадрах. Кадр 1 всегда является ключевым, а дополнительные
ключевые кадры создаются командой Insert • Timeline • Keyframe (или клави-
шей F6). Допустим, вы создали графический объект в кадре 1 и разместили его
в левой части сцены. Затем в кадре 19 создается ключевой кадр, и графический
объект перемещается в новую позицию в правой части сцены. Чтобы создать
анимацию, выделите начальный и конечный ключевые кадры на временной диа-
грамме и задайте параметру Tween на панели свойств значение Motion (или вы-
полните команду Insert • Timeline • Create Motion Tween). Flash автоматически ге-
нерирует промежуточные изображения, в результате чего объект перемещается
по сцене за 19 шагов. Чтобы убедиться в этом, достаточно прокрутить воспроиз-
ведение первых 19 кадров.
Графика, размещенная на слое, отображается на сцене до тех пор, пока на этом
слое не встретится пустой ключевой кадр. Например, если вы хотите убрать
графический объект со сцены после кадра 19, вставьте пустой ключевой кадр
в кадре 20 (команда Insert • Timeline • Blank Keyframe или клавиша F5).
Хотя Flash выполняет за разработчика большой объем работы, в этой главе бу-
дут представлены многие трюки, которые пригодятся как опытному аниматору,
так и новичку. Создание анимации требует времени и опыта, поэтому трюки
прежде всего направлены на ускорение работы и упрощение процессов. В отли-
Плавное сценарное движение 135

чие от аниматоров традиционной школы, аниматорам Flash приходится думать


и о времени загрузки, и о скорости работы на стадии выполнения. Мы рассмот-
рим несколько способов автоматизации или сокращения объема работы:
• упрощение анимации (как для аниматора, так и для Flash);
• генерирование сложных анимаций с использованием стороннего инструмен-
тария, особенно при анимации персонажей;
• построение сюжетов из коротких повторяющихся анимаций.
Flash также позволяет генерировать сценарное движение, при котором внешний
вид следующего кадра анимации вычисляется и воспроизводится средствами
ActionScript. Эта форма чаще всего применяется при создании интерактивных
анимаций и в тех случаях, когда анимация определяется математическими пра-
вилами (например, физическими уравнениями).
Учтите, что при использовании сценарной анимации Flash работает в системе
координат печати, а не с математическими координатами. Начало координат
печатной страницы находится в левом верхнем углу, тогда как в традиционной
декартовой системе оно расположено в левом нижнем углу. Это означает, что
начало координат Flash находится в левом верхнем углу сцены, а положитель-
ная полуось Y направлена сверху вниз, как показано на рис. 4.1.

-•X У

•х

Рис. 4 . 1 . Система координат Flash (слева) и традиционная


декартова система координат (справа)

Основным ограничением для сценарного движения является фактор быстродей-


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

ТРЮК Плавное сценарное движение


№26 С увеличением частоты смены кадров механизм визуализации Flash на-
чинает интенсивно поглощать процессорное время. Однако для созда-
ния субъективно плавной анимации не обязательно увеличивать частоту
смены кадров.
Одна из худших привычек Flash-дизайнера - поднимать частоту смены кадров
до абсурдно высокой величины, чтобы анимация казалась более гладкой. Такой
вариант подойдет для простого ролика FLA с одной анимацией, но при постро-
ении большой анимации Flash или сайта нельзя разрешать процедуре перери-
совки экрана поглощать все процессорное время. Если установить частоту сме-
ны кадров равной 95 кадрам в секунду (fps), Flash приходится постоянно строить
136 Глава 4. Анимация

новые изображения и выводить их на экран. Нехватка свободного времени при-


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

Активизация движения пользователем (нарушение


монополии onEnterFrame)
В простейшем случае анимация создается на стадии разработки, индикатор те-
кущей позиции Flash перемещается по шкале временной диаграммы, а кадры
отображаются по очереди. Данный механизм называется покадровой анимацией
и представляет собой электронный аналог серии рисунков. В таком сценарии
самым очевидным способом повышения скорости анимации является повыше-
ние частоты смены кадров (частота смены кадров задается в диалоговом окне
Document Properties, вызываемом командой Modify • Document). Когда аниматор
классической школы начинает осваивать Flash, этот способ кажется ему хорошо
знакомым.
Но когда речь заходит о сценарной анимации Flash, подход приходится менять.
Многих начинающих аниматоров учат, что сценарное движение следует реали-
зовывать через обработчики onEnterFrame. В простых случаях, когда сценарная
анимация привязывается к умеренной частоте смены кадров, такой способ впол-
не разумен. Однако с усложнением анимации приходится совершенствовать
методику ее реализации. В противном случае либо пострадает быстродействие,
либо придется смириться с ,тем, что некоторые из ваших творческих замыслов
реализовать не удастся.
Не стоит полагать, что вся анимация должна находиться под управлением обра-
ботчиков onEnterFrame, - это заблуждение. Так как события onEnterFrame привя-
зываются к частоте смены кадров, самый простой способ создания плавной анима-
ции заключается в повышении частоты, что приводит к более частому генерированию
событий onEnterFrame. Но если пользователь взаимодействует с графикой и ани-
мацией, для управления анимацией гораздо эффективнее использовать обработ-
чик onMouseMove. В частности, анимация перетаскивания объектов мышью яв-
ляется хорошим кандидатом на реализацию через обработчик onMouseMove.
Режимы, в которых пользователь управляет ходом анимации или рисует на эк-
ране указателем мыши, также могут управляться событиями onMouseMove.
Допустим, у нас имеется клип, перетаскиваемый мышью. Чтобы сделать анима-
цию перетаскивания более плавной, вместо повышения частоты смены кадров
лучше воспользоваться обработчиком onMouseMove и организовать перерисовку
сцены во время перемещения указателя мыши.
Следующий фрагмент обеспечит плавную анимацию перетаскивания даже в том
случае, если задать крайне низкую частоту смены кадров (даже 1 fps):
function pressHandlerO {
this.startDragO;
this.onMouseMove = functionO {
Плавное сценарное движение 137

// Обновление сцены во время перетаскивания объекта


updateAfterEventC):
}:
this.onRelease = function О {
this.stopOragO:
delete this.onMouseMove;
}:
this.onReleaseOutside = this.onRelease;
} '• -
// Создание анимационного клипа.и разрешение перетаскивания
var puck:MovieClip = this.createEmptyMovieClipC'puck".
this.getNextHighestDepth()):
puck.1ineStyle(40. OxCCCCCC. 100);
puck.moveTo(-l, 0);
puck.lineToCl. 0);
puck._x = 275;
puck._y = 200;
puck.onPress = pressHandler;
Проанализируем ключевые части этого кода. Основная часть (код, следующий
за определением pressHandler()) создает небольшой анимационный клип и на-
значает функцию pressHandler() его обработчиком события onPress. Код обра-
ботчика выполняется, когда пользователь щелкает на анимационном клипе.
Функция pressHandler() присоединяет к клипу обработчик события onMouseMove,
постоянно обновляющий экран в процессе перетаскивания. При такой реали-
зации Flash осуществляет более частую перерисовку экрана только во время
перетаскивания объекта, тем самым обеспечивается плавность движения без
повышения частоты смены кадров. Эта реализация приведена для того, чтобы
использующие ActionScript 1.0 усвоили суть данной методики. Аналогичная
схема может быть реализована с использованием ООП и ActionScript 2.0
(см. трюк 20).
Тот же принцип используется в следующем листинге, который создает простой
«карандаш» для рисования на экране на базе обработчика события onMouseMove.
Если переместить код из обработчика onMouseMove в обработчик onEnterFrame,
то он будет выполняться даже тогда, когда это не нужно (то есть когда указатель
мыши остается неподвижным):
function penDownO {
this.moveTo(_xmouse. _ymouse):
this.onMouseMove = functionO {
this.lineStyle(null. OxCCCCCC. 100):
this.lineTo(_xmouse. _ymouse);
updateAfterEvent():
}:
this.onMouseUp = functionO {
delete this.onMouseMove;

}
var drawClip:MovieClip = this.createEmptyMovieClipC'drawClip",
thi s.getNextHi ghestDepth()):
drawClip.onMouseDown = penDown;
138 Глава 4. Анимация

Итоги
Мысль об использовании обработчиков onEnterFrame для анимации выглядит
заманчиво, и все же это не единственное событие, применяемое для создания
анимации в Flash. В этом разделе была рассмотрена ситуация, в которой обра-
ботка события onMouseMove обеспечивала более эффективную и плавную ани-
мацию. Эффективность объясняется меньшими затратами вычислительных мощ-
ностей (экран обновляется только при необходимости), а плавность - тем фактом,
что частота возникновения событий onMouseMove не связана с частотой смены
кадров (в отличие от события onEnterFrame).
Хотя анимация на базе обработки события onMouseMove возможна только в том
случае, если действия пользователя связаны с перемещением мыши (например,
при операциях перетаскивании или рисования), при желании можно найти и дру-
гие события, синхронизируемые с обновлением экрана. Например, обновление мо-
жет происходить при получении данных или завершении воспроизведения звука.
Тем не менее, в некоторых случаях анимация должна синхронизироваться по
времени. К счастью, onEnterFrame - не единственное событие, связанное с вре-
менем. Если потребуется создать несколько анимаций с разными частотами сме-
ны кадров, обычно лучше использовать функцию setlntervalQ для раздельного
хронометража событий (см. трюк 27), вместо того чтобы использовать обработ-
чик onEnterFrame для всех анимаций.

ТРЮК Синхронизация анимации по времени


№27 Сценарные субанимации не обязаны синхронизироваться по частоте сме-
ны кадров. Для воспроизведения субанимации с частотой, не зависящей
от частоты смены кадров, применяются таймеры.
Скорость как сценарных, так и обычных анимаций изменяется несколькими спо-
собами. Первый способ - распределение анимации на большее (или меньшее)
количество кадров или изменение частоты смены кадров. Чтобы вставить до-
полнительный кадр на временной диаграмме, нажмите клавишу F5. Чтобы уда-
лить кадр, щелкните на нем правой кнопкой мыши (Windows) или с нажатой
клавишей 8§ (Мае) и выберите в контекстном меню команду Remove Frames.
Для синхронизации сценарной анимации по времени можно увеличить частоту смены
кадров и выполнять обновление экрана в обработчике события onEnterFrame.
Также возможно использование обработчиков других событий (например, onMouse
Move - см. трюк 26), что позволит более рационально организовать обновление
экрана и повысить плавность анимации без увеличения нагрузки на процессор.
Но в некоторых ситуациях анимация должна синхронизироваться по времени,
а не по внешним событиям наподробие перемещения мыши. При высоких тре-
бованиях к плавности анимации вместо завышения частоты смены кадров луч-
ше создать интервальный таймер функцией setlntervalQ. Такое решение обладает
тремя преимуществами:
• Flash не тратит время на частую перерисовку всего экрана (что неизбежно
при простом повышении частоты смены кадров;
Синхронизация анимации по времени 139

• разные составляющие анимации могут воспроизводиться с разной скорос-


тью;
• существует возможность относительно точно задавать скорость анимации не-
зависимо от частоты смены кадров или продолжительности анимации на вре-
менной диаграмме.
Стандартные интервальные таймеры создаются вызовами следующего вида:
интервал = set Interval(обработчик, период, аргументы):
где:
• интервал - идентификатор интервала, возвращаемый функцией setlnterval().
Идентификатор необходим для сброса (то есть остановки) существующих
интервалов;
• обработчик - имя функции, используемой в качестве обработчика события
таймера (то есть функции, автоматически вызываемой по истечении интерва-
ла);
• период - интервал между вызовами обработчика (в миллисекундах);
• аргументы - ноль и более аргументов, передаваемых' обработчику события.
Чтобы передать несколько аргументов, разделите их запятыми (аргумент!,
аргумент!, ..., аргумент_п).
Обработчик события, вызываемый функцией setlnterval(), принципиально отлича-
ется от обычных обработчиков, связываемых с экземплярами (вроде onMouseMove
или onEnterFrame), тем, что при его вызове область видимости отлична от области
видимости метода экземпляра. Чтобы метод вызывался для объекта (то есть в кон-
тексте конкретного экземпляра), используйте альтернативную форму setlnterval():
интервал = setInteryа](объект, "метод", период, аргументы):
где:
• объект - объект (например, экземпляр MovieClip), для которого вызывается
метод, заданный вторым аргументом;
• "метод" - имя метода, вызываемого для объекта с заданными интервалами
(в строковом формате).
Остальные аргументы имеют тот же смысл, что и в предыдущей форме setlnterval().
Если передать в параметре объект значение this, то вызов метода будет произво-
диться в контексте текущего экземпляра (см. трюк 10), то есть обработчик полу-
чит доступ к свойствам текущего экземпляра.
Функцию также можно вызвать в контексте клипа, передав соответствующий
экземпляр в первом аргументе. Следующий вызов setlntervalQ создает интер-
вальный таймер для экземпляра анимационного клипа myClip, который вызыва-
ет метод myEvent() каждую миллисекунду (или около того - все зависит от точ-
ности, которую сможет обеспечить Flash):
interval ID = setlnterval(myClip. "myEvent". 1):
Функция вызывается снова и снова до тех пор, пока интервальный таймер не будет
сброшен. Сброс интервального таймера осуществляется методом clearlntervalQ:
clearlnterval(interval ID);
140 Глава 4. Анимация

При сбросе интервального таймера необходимо проследить за тем, чтобы пере-


менная intervallD была видна в текущем контексте. Чаще всего функция, вызыва-
емая setlnterval(), сбрасывает интервал при выполнении какого-либо условия (или
при первом вызове, если событие является одноразовым).
В другом варианте setlntervalQ вызывает метод экземпляра клипа. Такое реше-
ние гарантирует, что обработчик выполняется в контексте клипа, с которым мы
работаем. В следующем примере интервальный таймер обеспечивает вызов ме-
тода mover() клипа myClip. Метод вызывается каждую миллисекунду (в рамках
точности Flash) и увеличивает свойство myClip._x. Анимация клипа продолжает-
ся до тех пор, пока значение _х не превысит 300.
Но при этом возникает одна проблема: методу mover() неизвестен идентифика-
тор интервального таймера (intervallD), необходимый для его сброса. По этой
причине мы делаем идентификатор свойством клипа, чтобы к нему можно было
обратиться в методе mover() с использованием синтаксиса this.intervallD:
function mover() {
this._x++;
i f (this._x > 300) {
clear-Interval (this.interval ID);
}
updateAfterEventO;
}
//Сохранение идентификатора интервального таймера в свойстве клипа
myClip.interval ID = setlnterval(myClip. "interval". 1):
myClip.interval = mover:
Код
Следующий фрагмент кода демонстрирует преимущества setlnterval() перед обра-
ботчиком onEnterFrame для обновления анимации. Код создает два анимационных
клипа и перемещает их по сцене с шагом в 1 пиксел. Кажется, что клип pucki
движется гораздо быстрее и плавнее, потому что он анимируется с максимальной
быстротой, доступной для Flash Player. Скорость перемещения клипа puck2 оп-
ределяется текущей частотой смены кадров, которая по умолчанию равна 12 fps.
mover = functionO {
this._x++ = speed:
i f (this._x > 550) {
clearlnterval(this.interval):
}
updateAfterEventO:

function enterFrameMover():Void {
this._x += speed;
i f (this._x > 550) {
delete this.onEnterFrame:

}
function drawBall(clip:MovieClip. x:Number. у:Number):MovieClip
var mc:MovieClip = this.createEmptyMovieClip(clip.toString().
thi s.getNextHi ghestDepth()):
Быстрая и компактная анимация символов 141

mc.lineStyle(40. OxCCCCCC. 100):


mc.moveTo(-l, 0);
mc.lineTod, 0);
me._х = х;
mc._y = у;
return me;
}
var speed:Number = 1;
var puckl:MovieClip = drawBalKpuckl. 20. 200):
var puck2:MovieClip = drawBall(puck2. 30. 300);
puckl.interval Mover = mover;
puckl.interval = setlnterval(puckl. "intervalMover". 1);
puck2.onEnterFrame = enterFrameMover;
Обратите внимание на то, как создается интервальный таймер:
• идентификатор, возвращаемый при вызове setlnterval(), относится к типу Number;
• идентификатор должен быть известен внутри метода, чтобы мы могли сбро-
сить интервальный таймер в конце анимации. Идентификатор можно пере-
дать в аргументе, но в данном случае мы включаем его в клип puckl в виде
переменной interval.
Конечно, очень высокая частота смены кадров (например, 95 fps) обеспечит бы-
строе и плавное воспроизведение обоих клипов, но у этого способа есть два
недостатка. Во-первых, зависимость анимации от частоты смены кадров услож-
няет изменение скорости разных графических элементов. Во-вторых, если заста-
вить все двигаться слишком быстро, Flash Player не сможет обеспечить затребо-
ванную частоту смены кадров. Решение с setlntervalQ позволяет избирательно
задавать те объекты анимации, для которых высокая скорость действительно
критична (см. трюк 71). Стоит заметить, что при ускорении всего SWF-ролика
максимальная частота смены кадров, которой вам удастся достичь, гораздо ниже
той, которая достигается при ускорении отдельных частей.

Итоги
Хотя кое-кто жалуется на недостаточную быстроту Flash Player, существует много
способов ускорить работу кода. Правильный выбор обработчиков событий (см.
трюк 26), благодаря которому код выполняется только в случае необходимости,
делает анимацию более плавной и улучшает ее субъективное быстродействие.
Другие трюки из области оптимизации приводятся в главе 9.

Быстрая и компактная анимация


ТРЮК

№28 символов
Ручное построение анимации занимает целую вечность. Несколько фо-
кусов «для служебного пользования» от аниматора, работавшего на сту-
дии Диснея, избавят вас от части тяжелой работы.
При работе над анимацией Flash всегда приходится решать вопрос, как добиться
цели минимальными средствами, поскольку пропускная способность канала
142 Глава 4. Анимация

и быстродействие Flash являются величинами ограниченными. Одним из фоку-


сов, позволяющих свести к минимуму объем работы и нагрузку на канал связи,
является цикл ходьбы. Создание многократно повторяемой анимации левого и
правого шагов, которая на экране выглядит как плавная и непрерывная анима-
ция шагающего человека, существенно экономит ресурсы по сравнению с пол-
ной анимацией с разными шагами.
Трюк, представленный в этом разделе, был создан в процессе работы по веб-
дизайну, которой я занимался совместно с Адамом Филипсом, аниматором
из студии Диснея и обладателем ряда призов. У Диснея ему приходилось ра-
ботать над оптимизацией анимации с получением'минимального количества
кадров - этот навык был в полной мере использован им в веб-комиксах (http://
www.biteycastle.com). Мы рассмотрим некоторые приемы, которые использова-
лись для сокращения количества кадров для анимации персонажа по имени
Скриббл.

Стилизованная походка
В процессе работы над реалистичным циклом ходьбы приходится решать две
проблемы:
• ходьба не сводится к простой перестановке ног - голова смещается вверх
и вниз, руки двигаются в воздухе, а корпус слегка покачивается. Если не вклю-
чить все эти элементы в анимацию, возникает впечатление, что на идущего
надели жесткий, негнущийся костюм;
• скорость ходьбы должна соответствовать скорости движения. Звучит тривиаль-
но, но вам, наверняка, попадались видеоигры или дешевые мультфильмы,
в которых персонажи словно скользят вдоль пола. Эффект возникает из-за
того, что скорость движения не совпадает с частотой перестановки ног.
Для создания реалистичного цикла ходьбы необходимо множество кадров и хо-
рошее чутье аниматора.
Одно из возможных решений проблемы - создание цикла ходьбы, в котором
нарушение перечисленных правил несущественно. Создайте упрощенную ани-
мацию (с меньшим количеством кадров), которая будет выглядеть эксцентрич-
ной и непохожей на нормальную походку; персонаж даже может ненадолго за-
висать в воздухе, что сведет к минимуму эффект скольжения. При грамотной
реализации стилизованная походка даже сделает вашего персонажа более ори-
гинальным.
Крайним случаем такого рода служит Тасманийский дьявол из мультфильма
студии «Warner Bros». Он двигается настолько быстро, что его невозможно раз-
глядеть, - по экрану просто проносится вихрь из одной точки в другую. Это
хороший пример того, как простота анимации изначально закладывается в кон-
цепцию персонажа.
Сайт, над которым работали мы с Адамом, обладал оригинальным интерфей-
сом - вместо того чтобы перемещаться по сайту при помощи мыши, посетитель
водил за ней персонажа по имени Скриббл. Если Скриббл не занимался чем-то
иным (например, обижался, разглядывал найденный предмет или просто думал
о чем-то своем), он следовал за указателем мыши.
Быстрая и компактная анимация символов 143

Например, если указатель мыши находился справа от Скриббла (рис. 4.2), он


переходил в текущую позицию указателя с использованием цикла ходьбы, изоб-
раженного на рис. 4.3.

Рис. 4 . 2 . Персонаж стоит на месте, указатель мыши находится справа

Рис. 4 . 3 . Эффективный цикл ходьбы

В окончательном варианте Скриббл двигался очень быстро - слишком быстро, чтобы


зритель мог заметить сокращенное количество кадров в анимации. Кроме того,
он много времени проводил в воздухе, сводя к минимуму эффект скольжения.
Конечно, если два дизайнера работают над одним проектом, простыми решени-
ями дело никогда не ограничивается. В данном случае было решено, что анима-
цию следует осуществлять в трех измерениях. Скриббл и указатель мыши долж-
ны были двигаться в псевдотрехмерном мире. Вроде бы такой подход должен
существенно усложнить анимацию, верно? Чтобы реализовать достаточно плав-
ный эффект трехмерного вращения текста, необходимо до 20 кадров. Трехмер-
ный цикл ходьбы потребует гораздо больше кадров, потому что меняется не
только направление/ориентация объекта, но и сам объект (Скриббл).
На рис. 4.4 показано, как Адам решил эту задачу.
На радиальных линиях представлены циклы ходьбы Скриббла в соответствую-
щих направлениях. Чтобы свести к минимуму великое множество кадров, задей-
ствованных в реализации трехмерного цикла ходьбы, Адам использовал ряд не-
очевидных приемов:
• Цикл ходьбы влево представляет собой зеркальное отражение цикла ходьбы впра-
во. Это стало возможным благодаря тому, что раскраска изображения Скриббла
не зависит от направления - фигура в любом случае остается черной. Таким
образом, три фазы ходьбы влево представляют собой зеркальные отражения
трех фаз ходьбы вправо. Чтобы создать зеркальное отражение графического
144 Глава 4. Анимация

объекта или символа, вызовите панель Transform (Window • Design Panels •


Transform), снимите флажок Constrain и измените знак масштабного коэффици-
ента по горизонтали или вертикали (в зависимости от того, по какой оси
строится отражение). Например, чтобы создать зеркальное отражение символа
по вертикальной оси, задайте горизонтальный масштабный коэффициент -100.

Рис. 4.4. Трехмерный цикл ходьбы

Графика ходьбы вверх совпадает с графикой ходьбы вниз; отличие только


в глазах (либо они рисуются на голове, либо нет).
Альтернативные средства построения анимации 145

• Каждый цикл ходьбы содержит множество повторяющихся элементов. Кад-


ры, на которых левая нога стоит на земле, фактически, повторяют кадры с опу-
щенной ногой в зеркальном отражении, поэтому между этими кадрами мо-
жет выполняться оптимизация.
• Движение Скриббла ограничивается восемью основными направлениями.
• Используемая анимация (размашистая подпрыгивающая походка) нормаль-
но смотрится на разных скоростях. В реальном мире движения при ходьбе
отличаются от движений при беге, поэтому мы специально разработали сти-
лизованную походку, подходящую для любой скорости. Проделать нечто по-
добное для реалистичной анимации лошади не удастся, потому что шаг, рысь
и галоп выглядят по-разному.
С учетом всех оптимизаций полный трехмерный цикл ходьбы состоит всего из
10-20 кадров. Объем пересылаемых данных снижается до минимума!

Итоги
Хотя идеи, заложенные в основу этого трюка, после прочтения кажутся триви-
альными, в веб-анимации они встречаются не так уж часто. Аналогичная мето-
дика применима к любой циклической анимации (например, полету птицы).
Идеально плавная анимация нужна не всегда. Более того, довольно часто сни-
жение количества кадров лучше передает движение и делает его более ориги-
нальным. Конечно, не стоит забывать и о таких положительных аспектах, как
сокращение времени загрузки и объема работы!
Если вам захочется узнать, как выглядит Скриббл в деле, ознакомьтесь с одной
из наших ранних работ scribbleWalk.fIa на сайте книги. Также обратите внимание
на код кадра 1 уровня actions в загруженном файле. В этом коде также применен
ряд других оптимизаций, но их поиск поручается читателю для самостоятель-
ной работы.

ТРЮК Альтернативные средства построения


№29 анимации
Как бы мы ни любили Flash, это не единственная среда разработки.
Существуют и другие программы для построения анимационной гра-
фики.
Flash занимает первое место среди анимационных и мультимедийных платформ,
ориентированных на Веб, но существуют и другие варианты. Даже если исклю-
чить программы среднего звена вроде Toonboom (http://www.toonboom.com)
и Macromedia Director (http://www.macromedia.com/software/director), а также спе-
циализированные приложения вроде генераторов текстовых эффектов и Swift
3D (http://www.swift3d.com), остается ряд программ, заслуживающих вашего вни-
мания. Пакет Processing (http://www.processing.org) интересен тем, что он ориен-
тирован на создание сценарной анимации, но, в отличие от Flash, не отягощен
«историческим наследием» анимации на временной диаграмме.
146 Глава 4. Анимация

Koolmoves (http://www.koolmoves.com), специализированный пакет для анима-


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

Processing

Сейчас Flash двигается в том же направлении, что и Веб в целом. Macromedia


усиленно продвигает концепцию разработки R1A (Rich Internet Application), ука-
зывает на повсеместное распространение Flash, на простоту перехода на эту плат-
форму и ее практичность. Конечно, так было не всегда - когда-то Flash считался
выбором «неформалов» в области веб-дизайна. Я до сих пор хорошо помню свои
посещения первых конференций Flash Forward (http://www.flashforward2004.com),
на которых демонстрировалось множество замечательных, творческих и совер-
шенно некоммерческих разработок.
Как ни печально, Flash уже не является неоспоримым королем в области незави-
симых цифровых мультимедийных технологий. Возможно, корона скоро перей-
дет к Processing (http://www.processing.org), прикладному интерфейсу графичес-
кого программирования, который без малейшего труда может быть освоен любым
программистом ActionScript. На рис. 4.5 приведены примеры работ Алессандро
Капоццо (Alessandro Capozzo) (http://www.ghostagency.com).

*&

Рис. 4.5. Графика, созданная в Processing

Processing работает на базе Java. Это язык программирования и среда разработ-


ки, при проектировании которых ставились две основные цели:
• обучить сообщество художников и дизайнеров азам программирования на
визуальном уровне;
• создать «электронный альбом», в котором бы художники могли создавать
анимацию на программном уровне.
Альтернативные средства построения анимации 147

Самые замечательные свойства Processing - быстрота, бесплатное распростра-


нение и работоспособность в любом браузере с поддержкой Java. Возможно, в сек-
торах некоммерческой веб-графики и математических исследований этот пакет
превзойдет Flash по популярности.
Может, вы считаете, что я преувеличиваю? Приведу список имен, известных
в сообществе Flash, которые уже активно используют Processing:
• Cinema Redux: Брендан Доус (http://www.brendansawes.com);
• Gallery of Computation: Джаред Тарбелл (http://www.complexification.net);
• Point Man: Энт Идеи (http://www.arseiam.com/proce55ing/man);
• Sonic wire sculpture: Амит Питару (http://www.pitaru.com);
• Кейт Питере (http://www.bit-101.com).
Как видите, Processing все активнее вторгается в нашу жизнь.

KoolMoves

На первый взгляд, KoolMoves (http://www.koolmoves.com) представляет собой


усеченную, дешевую версию среды разработки Flash, по набору возможностей
находящуюся где-то между Flash 3 и Flash 4, - однако этот пакет обладает ря-
дом возможностей, которые более нигде не встречались.
Особого внимания заслуживает скелетная анимация (рис. 4.6), позволяющая
определять нетривиальные иерархические связи между анимируемыми элемен-
тами, - сделать нечто подобное в Flash очень трудно. Учитывая, что KoolMoves
стоит всего $49, к тому же существует пробная бесплатная версия (которая не
позволяет сохранять результаты, но во всем остальном абсолютно функциональ-
на), с этим пакетом стоит познакомиться поближе, особенно если вам приходит-
ся часто создавать анимации без сценариев. Поклонников сценарной анимации
KoolMoves вряд ли заинтересует (тем более что они сейчас наверняка отложили
книгу и загружают Processing).

Рис. 4.6. KoolMoves поддерживает скелетную анимацию,


имитирующую строение тела персонажа

Итоги
У среды разработки Flash существует немало альтернатив; одни используют
формат SWF (и требуют Flash Player для воспроизведения), другие работают
148 Глава 4. Анимация

с собственными форматами. Проект Adobe LiveMotion прекратил существова-


ние и больше не поддерживается. Среди других вариантов стоит особо выде-
лить следующие:
• Ming (http://ming.sourceforge.net) - библиотека функций С, которые могут
использоваться из распространенных сценарных языков, работающих на сто-
роне сервера (таких как Perl, Python, PHP и Ruby), для динамического по-
строения SWF-файлов. Результат загружается в клиентский SWF в виде вло-
женного клипа или используется для замены текущего SWF в Flash Player.
Обратите внимание: Ming только генерирует новые SWF, но не модифициру-
ет уже существующие файлы;
• Flash является самой распространенной платформой для создания мульти-
медийного содержания в Веб, однако SWF - далеко не единственный фор-
мат итогового документа. SVG (Scaleable Vector Graphics), как и Flash, является
векторной средой. Графика SVG строится на базе текстовой разметки XML,
а это означает, что содержимое файла более доступно для поисковых систем,
чем двоичный формат SWF. Документы SVG молено создавать в любом тек-
стовом редакторе. Сейчас существует уже несколько систем разработки SVG,
но все они значительно уступают Flash MX 2004. Тем не менее, большинство
браузеров не распознает содержание SVG (см. http://www.macromedia.com/
software/player_census/flashplayer), к тому же модуль SVG занимает больше
места, чем Flash Player, и обычно его бывает труднее установить. Из-за повсе-
местного распространения Flash Player SVG скорее рассматриваться может
как интересная альтернатива для особых случаев, нежели как полноценная
замена Flash и формата SWF. Знакомство с SVG лучше всего начать со спис-
ка SVG FAQ (http://www.svgfaq.com) и SVG Cafe (http://www.svg-cafe.com) -
на этих сайтах вы получите информацию от людей, которые знают SVG луч-
ше, чем кто-либо другой. Будьте готовы к каверзным вопросам или обвине-
ниям по поводу Flash/SWF (а также неистовой дезинформации со стороны
людей, которые подобным образом самоутверждаются). На октябрьской кон-
ференции МАХ в Солт-Лейк Сити, штат Юта, фирма Macromedia продемон-
стрировала версию Flash Player с ограниченной поддержкой SVG. Из этого
можно сделать вывод, что в будущем Flash Player будет поддерживать ото-
бражение контента SVG, хотя и не в полном объеме спецификации SVG;
• Flex (http://www.macromedia.com/software/flex) - сервер представления от
Macromedia, динамически генерирует SWF-файлы на XML-подобном языке
(называемом MXML). Flex также использует ActionScript 2.0 для вывода воз-
можностей управления сценариями за пределы стандартных средств вре-
менной диаграммы. Flex ориентируется на коммерческих Java-разработчи-
ков. Этот продукт должен избавить среду Flash от основных недостатков, на
которые чаще всего указывают разработчики, программирующие на стороне
сервера, - а именно реализовать возможность разработки на текстовом, а не
визуальном уровне, а также использования редактора и системы управления
исходными текстами по выбору разработчика. Иначе говоря, Flex сочетает
многие сильные стороны SVG и Flash.
Принцип «Deja New» 149

Принцип «Deja New»


Повторяющиеся анимации экономят ресурсы, но быстро приедаются.
Создавая неповторяющиеся циклы, вы сделаете анимацию более разно-
образной, не повышая затрат ресурсов и не прибегая к ActionScript.
Кадрированная анимация хорошо подходит для аниматоров, не владеющих на-
выками программирования, но она страдает от целого ряда ограничений. Самое
очевидное ограничение - Пониженная интерактивность по сравнению со сце-
нарной анийацией. В некоторых приложениях Flash это не создает проблем,
особенно в неинтерактивных мультфильмах.
В анимации часто используется еще одна возможность, которая в общем случае
не реализуется без сценариев: случайное или не повторяющееся движение. Кад-
рированная анимация проходит по строго фиксированному плану, никогда не
содержит случайных элементов, а все повторения полностью совпадают.
Предположим, имеются две кадрированных анимации в двух разных клипах, на
10 и на 20 кадров. Если в цикле запустить их в рамках одной общей анимации,
ролик будет повторяться каждые 20 с. Анимация становится однообразной, а это
ослабляет впечатления пользователя.
Другой пример: допустим, вы хотите создать 30-секундный ролик с движущи-
мися облаками. Конечно, можно построить 30-секундную анимацию, но это зай-
мет много времени. Вместо этого лучше создать анимацию с одним или несколь-
кими облаками, несколько раз продублировать ее и позаботиться о том, чтобы
изображение не повторялось. Но если эта 30-секундная циклическая анимация
будет использоваться в качестве фона для 5-минутного ролика, она снова начнет
повторяться. В идеале небо должно состоять из множества отдельных анимиро-
ванных клипов, формирующих почти не повторяющееся изображение.
Стандартное решение этой проблемы - запереться на неделю в комнате, изучая
ActionScript и возможности Math.random(). Умное решение - использовать про-
стые числа в кадрированных анимациях.
Простым называется число, которое нацело делится только на 1 и на само себя.
Простые числа в интервале от 1 до 100: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
47, 53, 59, 61, 67, 71, 73, 79, 83, 89 и 97. Если потребуется дополнить этот список,
проведите поиск в Веб по ключевым словам «prime number» или «prime series».
Главной особенностью простых чисел является их неделимость. С точки зрения
математики это означает, что наименьшим общим кратным двух простых чисел
является их произведение.
А что это означает для нашей ситуации? Если имеются две анимации длиной
п и т, где пит- простые числа, то третья анимация, содержащая первые две,
не будет повторяться первые п х т кадров. Следовательно, если изменить две
кадрированные анимации так, что их длина в кадрах будет выражаться просты-
ми числами (например, 11 и 19), анимация, содержащая первые два клипа, не
будет повторяться на промежутке максимальной длины, определяемой произве-
дением длин двух исходных клипов. Повторение происходит только один раз
150 Глава 4. Анимация

каждые 209 кадров (20,9 с при частоте смены кадров 10 fps), а не каждые 20
кадров (2 с),, как при использовании клипов длиной 20 и 10. Неплохо, если
учесть, что более длинная анимация состоит из 19 кадров. Итак, если каждая
кадрированная анимация, выполняемая в цикле, имеет длину, выраженную про-
стым числом (и отличную от длины других анимаций), повторения будут разде-
лены максимальными промежутками.
Наверное, лучшим примером использования простых чисел в FLA служит мой
самый первый Flash-файл. Мне хотелось создать анимированную картинку от-
дыхающей бабочки. Движения бабочек, как и большинства одушевленных объек-
тов, хаотичны и непредсказуемы:
• крылья периодически складываются и раскрываются, даже если бабочка не
собирается взлетать;
• усики двигаются;
• все тело насекомого слегка подрагивает.
На рис. 4.7 представлено несколько начальных кадров ролика - моего первого
опыта в компьютерной анимации.

Рис. 4.7. Анимация бабочки

Но я понятия не имел, как сделать анимацию бабочки случайной и жизненной,


в отличие от механических, явно искусственных кадрированных циклов. Тогда
мой опыт работы с Flash составлял всего пару часов, и я ничего не знал о языке
ActionScript (который, впрочем, в той версии был весьма ограничен - в тот же
день я освоил все 15 или 20 возможных операций!).
В итоге я решил использовать разные анимации для трех частей:
• анимация крыльев - 97 кадров;
• анимация усиков - 31 кадр;
• анимация подрагивания тела бабочки - 41 кадр.
Таким образом, между повторениями анимации проходило 97 х 31 х 41 кадров,
или приблизительно 3 часа (при 12 fps). Конечно, никто не будет рассматривать
анимацию так долго, но поскольку это была моя первая Flash-анимация, я был
не так уж далек от этой цифры.
Как попасть в «Матрицу» 151

Чтобы увидеть окончательный вариант анимации с бабочкой, загрузите файл


butterfly.fla с сайта книги.

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

Как попасть в «Матрицу»


Реконструкция знаменитого эффекта «падающего зеленого текста из
фильма «Матрица»
Предположим, мы хотим создать быструю версию «водопада из зеленых букв»
из кинотрилогии «Матрица» без применения сценариев. В эффекте задейство-
ваны случайно падающие символы катаканы (о том, что такое катакана, можно
узнать по адресу http://japanese.about/com/library/weekly/aa052103a.htm).
Первый символ text представляет собой простую временную диаграмму с тремя
ключевыми кадрами (рис. 4.8).

Рис. 4 . 8 . Временная диаграмма с тремя ключевыми кадрами для символа text

Три ключевых кадра отображают три статических текстовых поля, показанных


на рис. 4.9. Хотя цикл анимации получается крайне однообразным, никто этого
не заметит, потому что все происходит очень быстро.
Эффект «зеленого водопада» в «Матрице» состоит из множества букв, случай-
ным образом «падающих» по экрану. Чтобы создать действительно случайное
падение текста, нам пришлось бы полностью запрограммировать эффект на сце-
нарном уровне; поверхностное же знакомство с Flash-сообществом показывает
следующее: 1) далеко не каждый знает, как это делается; 2) многие люди хотят
воссоздать эффект из «Матрицы», но считают, что для этого обязательно нужно
знать язык сценариев.
Что ж, создать действительно случайную анимацию из кадрированных загото-
вок невозможно, но представленная далее анимация повторяется только один
152 Глава 4. Анимация

раз через каждые 14 535 931 кадров (примерно две недели при 12 fps), так что
может считаться почти случайной.
В моем варианте реализации используется пять кадрированных анимаций, каж-
дая из которых выделена в отдельный клип. В каждом клипе текст падает сверху
вниз (рис. 4.10).

щ «
• .

1
п|

т ж
т
з| \ы
\4\
: я&я.

\п\ h
] ж№\ d
|э| am
s
1*1*1

w и
*
Рис. 4.9. Три статических текстовых поля, используемые
в качестве основы для построения анимации

Анимации имеют разную длину в кадрах. Клип waterfall 19 содержит 19 кадров,


а клип waterfall37 - 37 кадров. Имена всех пяти клипов в библиотеке изображе-
ны на рис. 4.11.
На рис. 4.12 изображены три последовательных кадра в созданном эффекте.
Каждый столбец представляет один из пяти одновременно запущенных клипов.
Клипы воспроизводятся циклически, поэтому изображение в конечном счете
повторяется. Но поскольку длины всех пяти анимаций представлены простыми
числами (см. трюк 30), до повторения должно пройти 19 х 23 х 29 х 31 х 37 кад-
ров - весьма долгий промежуток времени.
Если вам нравится ощущение дежа вю, ждать придется довольно долго. Впро-
чем, любого поклонника первого фильма трилогии дежа вю ни к чему хорошему
не приведет, и от него лучше держаться подальше. При желании добавьте звук
падающей воды, чтобы еще точнее воспроизвести эффект из «Матрицы».
Как попасть в «Матрицу» 153

Рис. 4 . 1 0 . Кадрированная анимация с текстом, падающим сверху вниз

Movie Clip
Movie Clip
Movie Clip
Movie Clip

Рис. 4 . 1 1 . Библиотека с символами клипов, длины которых


выражаются простыми числами
154 Глава 4. Анимация

Рис. 4.12. Три кадра итоговой анимации

Итоги
Повторение циклов анимации довольно часто встречается даже в коммерчески
успешных анимационных проектах. Например, главный герой едет на машине,
и в окнах подозрительно часто мелькает одна и та же комбинация уходящих
вдаль деревьев, пригородных домов и припаркованных машин. А когда видишь,
что в саду перед домами с номером 56 играют одни и те же дети, все становится
ясно. Такое происходит из-за того, что даже в высокобюджетных проектах ани-
мация обходится дорого, поэтому постановщик старается по возможности сэко-
номить. И все же подобные ухищрения не должны бросаться в глаза, а трюк
с простыми числами помогает скрыть циклическое повторение отдельных анима-
ций. Реализм компьютерных спецэффектов растет, и даже сцены из реальной жизни
содержат повторяющиеся элементы. Например, огромная толпа в Вашингтоне
из фильма «Форест Гамп» в действительности состоит из маленькой группы лю-
дей, многократно повторенной. В фильме «Шоу Трумэна» обитатели фальшиво-
го городка регулярно повторяют одни и те же действия (машины кружат по
кварталу и т. д.), причем главный герой в исполнении Джима Керри замечает это.
Возможно, на уроках математики вы думали, что с простыми числами имеют дело
только математики. Оказывается, даже Тому и Джерри не обойтись без них.

Анимация персонажа,
ТРЮК

№32 сгенерированного компьютером


Если вам некогда рисовать персонажей для анимаций Flash вручную, вос-
пользуйтесь приложением Poser фирмы Curious Labs.
Ветераны помнят, какой эффект произвело появление первой псевдотрехмер-
ной анимации на сайтах Flash в эпоху расцвета Flash 4. Первые пользователи
Анимация персонажа, сгенерированного компьютером 155

этой методики (такие как Мануэль Клемент - http://www.mano1.com) создавали


все вручную, но с появлением специализированных модулей экспортирования
30-графики в Flash и автономных приложений (прежде всего Swift 3D - http://
www.swift3dd.com) появилась возможность автоматизации процесса.
Приложения вроде Swift 3D хорошо подходят для создания элементов трехмер-
ных интерфейсов и других объектов, имеющих правильную форму. Конечно, это
полезная возможность, и все же в повседневной работе Flash-дизайнерам обыч-
но приходится решать несколько иные задачи. Во многих Flash-роликах задей-
ствованы псевдотрехмерные персонажи, которые почти всегда реализуются по
старинке, то есть рисуются от руки.

Автоматизация анимации персонажа в Poser


Приложение Poser 5 фирмы Curious Labs (http://www.curiouslabs.com), ранее
называвшейся MetaCreations, предназначено специально для создания трехмер-
ных фигур. В отличие от других программ создания трехмерных персонажей
(таких, как пакет Character Studio от 3D Studio Max), оно довольно просто осва-
ивается. Любой, кому доводилось работать в Swift 3D, быстро начнет работать
в Poser 5. Кроме того, в отличие от многих специализированных программ ани-
мации персонажей, Poser стоит относительно недорого.
Возможно, вам придется потратить некоторое время на изучение программы, но
зато вам не придется вручную рисовать все анимации персонажей. На ручное
создание типичной анимации Flash уходят месяцы, поэтому затраченное время
быстро окупается.
Не падайте духом, если в Веб вам встретятся плохие отзывы о Poser. Они отно-
сятся в основном к «нулевой» версии Poser 5, которая действительно имеет це-
лый ряд проблем. После установки всех исправлений Poser становится надеж-
ным и устойчивым инструментом.
Существует два способа использования Poser совместно с Flash:
• создание реалистичных анимированных фигур, которые берутся за образец
при построении ваших собственных анимаций. Именно для этой цели изна-
чально создавался Poser - как электронная версия деревянных манекенов,
используемых некоторыми художниками;
• непосредственное создание анимаций и их экспортирование в Flash в форма-
те SWF (по аналогии с экспортированием трехмерной анимации в Flash из
Swift 3D).
Наше знакомство с Poser начнется с рассмотрения второго способа, поскольку
в нем задействованы многие возможности, встроенные в Poser специально для
экспортирования в Flash.

Использование Poser для непосредственного


создания анимаций
Хотя Poser позволяет проектировать персонажей и анимационные последова-
тельности, возможности этой программы будут продемонстрированы на приме-
ре экспортирования анимации, использующей готовую модель.
156 Глава 4. Анимация

При запуске Poser 5 на экране отображается стандартная модель в стандартной


позе, как показано на рис. 4.13.

. • :•:• ..... • :-.

• : • :• s • •

Рис. 4.13. Начальное окно Poser 5

Выделите любую часть стандартной фигуры и нажмите клавишу Delete, чтобы


удалить ее. Когда на экране появится диалоговое окно с предложением подтвер-
дить операцию, щелкните на кнопке Yes.
В библиотеке Poser (если библиотека не отображается справа, выполните ко-
манду Window • Libraries) выполните команду Figures • Additional Figures •Cartoons;
на экране появляются персонажи, изображенные на рис. 4.14. Щелкните на фи-
гуре Минни (Minnie).
Минни появляется в главном окне в стандартной для трехмерных моделей пер-
сонажей Т-образной позе (корпус выпрямлен, руки вытянуты в стороны). Мы
хотим создать для нее анимацию. Выполните в библиотеке команду Pose • Cartoon
Poses • Minnie. Выберите позу Point, изображенную на среднем кадре р и с 4.15.
Анимация позы состоит из 28 кадров (на это указывает число в правом верхнем
углу эскиза позы).
Анимация персонажа, сгенерированного компьютером 157

Рис. 4 . 1 4 . Встроенные персонажи Poser: Дедушка, Мик и Минни

Изображение Минни в главном окне изменяется и приводится в соответствие


с выбранной позой, как показано на рис. 4.15.

Рис. 4 . 1 5 . Эскиз позы Point (слева): трехмерная модель Минни изображает


первый кадр позы в главном окне (справа)
158 Глава 4. Анимация

Возможно, фигуру Минни стоит немного сдвинуть назад на сцене Poser, чтобы
она полностью помещалась на сцене Flash при анимации в формате SWF (дело
в том, что сцена Poser имеет квадратную форму, тогда как сцена Flash обычно
представляет собой прямоугольник, и при просмотре в Flash верхняя и нижняя
части фигуры будут усечены). Для этого найдите на экране кнопки Editing Tools
(если они не отображаются, выполните команду Window • Editing Tools). Щелк-
ните на кнопке Translate In/Out (рис. 4.16) и перетащите указатель мыши вверх
или вниз, чтобы передвинуть Минни назад или вперед.

Рис. 4.16. Кнопка Translate In/Out в Poser

Чтобы экспортировать анимацию в Flash SWF, выполните команду Animation •


Make Movie; на экране появится диалоговое окно Make Movie, показанное на
рис. 4.17. Выберите в списке Sequence Type строку Macromedia Flash (.swf). В группе
Frame Rate установите переключатель Use This Frame Rate и выберите частоту
смены кадров для ролика SWF. По умолчанию в Poser используется частота
смены кадров 30 fps. При существенном снижении частоты ниже уровня 30 fps
анимация становится излишне дерганой, поэтому лучше задать частоту смены
кадров на уровне 30 fps или около того.

Movie: |Untitled . • :•' : .

j l sh ! s> Ж-! • • ' • U s e t h i s ; f r a m e r a t e :

4.fiiSlijtton.: |Жй;:Ш^ .-. .


:
: •:,. w] .-•...:• - Tiroe Sp-an:
SUrt 0 B E

' Quality 111 Ш : i ^l •


anrr 0 00 01 00

R a s h S e t t i n g s C a n c e l

Рис. 4.17. Диалоговое окно Poser Make Movie

Щелкните на кнопке Flash Settings в диалоговом окне Make Movie. Параметры


диалогового окна Flash Export (рис. 4.18) определяют способ преобразования гра-
фики в векторный формат. Параметры, представленные на рис. 4.18, подходят
для большинства оптимизируемых SWF (4 цвета, Quantization=AII Frames, флаж-
ки не устанавливаются).
Выбор оптимального количества цветов зависит от созданного персонажа. Па-
литра Минни сильно сокращена, поэтому персонаж экспортируется в вектор-
ный формат с минимальным количеством цветов. Помните: чем больше цветов
выбрано, тем больше создается векторов.
Анимация персонажа, сгенерированного компьютером 159

tSH Export
Number of colors:
Quantization: (* M Frames

Г" Overlap Colors •better.maybe larger)


f~ Draw outer lines'

Рис. 4.18. Диалоговое окно Poser Flash Export

Щелкните на кнопке OK, чтобы подтвердить параметры в окне Flash Export. По-
вторный щелчок на кнопке ОК создает SWF-ролик.
Чтобы импортировать сгенерированный ролик в Flash, создайте новый или от-
кройте существующий файл FLA и выполните команду File • Import • Import to
Stage.
Анимация отображается в виде серии ключевых кадров на одном слое. Графи-
ческие формы объединяются в группы. Как и при всех операциях экспортирова-
ния, следующим шагом должна стать оптимизация анимации. Оптимизация дан-
ных Poser очень близка к оптимизации данных Swift 3D.
Возможно, вам помогут следующие рекомендации:
• отмените группировку содержания каждого кадра, затем выполните оптими-
зацию (Modify • Shape • Optimize) и/или сглаживание (Modify • Shape • Smooth);
• Poser, как и Swift 3D, не преобразует часто используемые фигуры в символы
для повторного использования. Вы должны сами найти такие фигуры и ре-
шить проблему. Например, ноги и юбку Минни явно можно заменить не-
большим количеством символов, которые могут многократно использоваться
в разных кадрах.
На рис. 4.19 представлен процесс оптимизации с применением развертки конту-
ров, а также стандартных приемов и графических инструментов Flash.
Более опытные Flash-дизайнеры предпочитают импортировать изображения из
Poser в виде опорных растровых изображений и трассировать их в векторную
форму, как показано на рис. 4.20. Я тоже предпочитаю этот способ; несмотря на
некоторое увеличение объема ручной работы, он сохраняет дух «ручной прори-
совки» и экономит время. Кроме того, такая графика лучше оптимизируется.
160 Глава 4. Анимация

Рис. 4.19. Оптимизация анимации, экспортированной из Poser в Flash

Рис. 4.20. Выходные данные Poser могут импортироваться в Flash


и использоваться как основа для построения анимации

Итоги
Poser часто используется совместно с Photoshop для построения любой графи-
ки, в которой задействованы модели персонажей. Совместно с Flash эта про-
грамма используется довольно редко.
Хотя создание трехмерных персонажей и их анимация в Poser с последующей
ручной оптимизацией каждого кадра в Flash занимают довольно много времени,
по сравнению с ручной реализацией эта процедура способна сэкономить целые
месяцы тяжелой работы (особенно при наличии опыта работы в Swift 3D).
Эффекты частиц 1G1

Аниматоры традиционной школы, предпочитающие рисовать своих персонажей


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

ТРЮК Эффекты частиц


№33 Эффекты частиц (взрывы, искры, дождь, снег и т. д.) делают анимацию
более реалистичной.
При создании кадрированной анимации очень трудно реализовать стандартные
эффекты частиц - снег, звездные потоки, переливающуюся воду и т. д. Flash не
имеет встроенной поддержки эффектов частиц, а анимация тысяч крошечных
клипов в разных направлениях займет много времени. Но в действительности
создавать разнообразные эффекты проще, чем кажется на первый взгляд.
В простейшем варианте частица движется в одном направлении - сверху вниз.
Начнем с моделирования «падающих частиц» с использованием механизма вло-
жения клипов. Поворот клипа позволяет создать множество разнообразных эф-
фектов без особых усилий с вашей стороны.
function mover():Void {
this._y += this.speed;
if (this._y > 400) {
this._y = 0:
this.speed = Math.random()*10+5:

}
var path:MovieClip = this.createEmptyMovieClipC'path". 0):
var dot:MovieClip = this.path.createEmptyMovieClipC'dot". 0);
dot.lineStyleCO. 0x0. 100);
dot.moveTo(0. 10);
dot.lineTo(0. 15):
dot.speed = Math.randomO * 10 + 5;
dot.onEnterFrame = mover;
Приведенный фрагмент создает клип path, в котором создается другой клип
с именем dot. Затем клип dot перемещается от верхнего края экрана вниз. Возни-
кает резонный вопрос: для чего мы создали path? В этом и заключается суть
трюка - поворачивая path, можно изменить направление перемещения dot. По-
пробуйте добавить следующий фрагмент в конец предыдущего листинга и по-
смотрите, как это делается.
// Перемещение клипа в точку (100.100), чтобы он
// оставался видимым даже при повороте,
path._x = path._y = 100;
path._rotation = 50;
Поворачивая path, мы изменяем направление движения dot. Более того, масшта-
бированием path в процессе перемещения dot можно создавать сложные эффек-
ты ускорения без лишней работы.
162 Глава 4. Анимация

Звездный поток
В следующем листинге приведена измененная версия этого кода. Обратите вни-
мание: операции масштабирования и поворота выделены жирным шрифтом.
Программа предполагает, что сцена была окрашена в черный цвет (выполните
команду Modify • Document, щелкните на образце и выберите черный цвет).
function moverО {
// Перемещение частиц во времени
this._y += this,speed:
this.yscale =+= 10;
this.speed++:
i f (this._y > 500) {
this._y = 0:
this.speed = Math.random()*10;
this._yscale = 100:

function starField(x, y. n) {
// Построение звездного потока заданных размеров из п звезд
for (var i = 0: i < n: i++) {
var star = this.createEmptyMovieClipC'star" + i. i):
var dot = star.createEmptyMovieClip("dot". 0):
star._rotation = Math.randomQ * 360;
star._x = x;
star._y = y;
dot.lineStyleCO. OxFFFFFF. 100);
dot.moveTo(0. 10):
dot.lineTo(0. 15):
dot.onEnterFrame = mover:
dot.speed = Math.random()*10;
}
starField(275. 200. 100):
В этом коде мы создаем множество клипов star, каждый из которых принимает
на себя роль клипа path, рассмотренного в предыдущем примере. Каждый клип
star поворачивается под случайным углом (рис. 4.21).
Клипы star также подвергаются масштабированию; растяжение траектории (клип
star) во время движения dot ускоряет перемещение и создает иллюзию того, что
при приближении к зрителю объект движется быстрее.
Трюк с масштабированием path во время движения dot может использоваться
для создания эффекта гравитации (см. трюк 38). В следующем листинге те же
приемы имитируют Движение воды:
function mover():Void {
this._у += this.speed:
this._yscale =+= 10:
this.speed++:
i f (this._y > 500) {
this._y = 0:
this.speed = Math.randomO * 10:
Эффекты частиц 163

this, yscale = 100;

function waterfall(xl. x2. n) {


for (var i = 0; i < n; i++) {
var star:MovieClip = this.createEmptyMovieClipC'star" + i . i)
star._x = Math.randomO * x2 + x l ;
star._y = 0;
var dot = star.createEmptyMovieClip("dot", 0);
dot.lineStyle(0. OxFFFFFF, 100);
dot.moveTo(0. 10);
dot.lineTo(0. 15);
dot.onEnterFrame = mover;
dot.speed = Math.random()*10:

}
waterfall(200. 300. 800);

Рис. 4 . 2 1 . Звездный поток, созданный с применением эффектов частиц

Последний эффект, приведенный далее, имитирует снегопад. Произвольное из-


менение угла траектории частиц создает хаотический набор движущихся час-
тиц, похожих на снежинки:
function mover() {
this._y += this.speed;
i f (this._y > 500) {
this._y - 0;
this.speed = Math.randomO * 10 + 5;

}
function snow(a. n)
1В4 Глава 4. Анимация

for (var i = 0; i < n: i++) {


var star:MovieClip = this.createEmptyMovieClipC'star" + i . i ) ;
star._x = Math.randomО * 550;
star._rotation = (Math.randomO * 2 * a) - a
star._y = 0;
var dot:MovieC1ip = star.createEmptyMovieClip("dot". 0):
dot.lineStyleCO. OxFFFFFF. 100);
dot.moveTo(0. 10);
dot.lineTo(0, 15);
dot.onEnterFrame = mover:
dot.speed = Math.random()*10 + 5;

}
snow(30. 800);

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

ТРЮК Морфинг сложных фигур


№34 Морфинг относительно редко применяется на практике, поскольку его
результаты часто оказываются непредсказуемыми. Проблема решается
упрощением фигур и выравниванием количества замкнутых контуров.
Одним из простейших и часто используемых применений морфинга, то есть
анимации изменения формы фигур, является преобразование текста. Чтобы соз-
дать анимацию такого рода, активизируйте инструмент Text и введите какую-
нибудь букву (например, «е») в кадре 1. Вставьте ключевой кадр (F6) в кадре 10,
удалите в нем букву «е» и замените ее буквой «с». В каждом из ключевых кад-
ров выделите букву и выполните команду Modify • Break Apart, чтобы преобразо-
вать текст в векторную форму (если текст состоит из нескольких букв, команда
Modify • Break Apart должна выполняться дважды). Выделите один из промежу-
точных кадров и выберите команду Shape, в раскрывающемся меню Tween на
панели свойств. Переместите индикатор текущей позиции по временной диаг-
рамме и проследите за тем, как происходит морфинг.
Превращение «е» в «с» вроде бы должно выполняться тривиально, но Flash сби-
вается с толку и создает лишние промежуточные петли (рис. 4.22).
Алгоритм морфинга, используемый в Flash, не любит, когда одна фигура содер-
жит внутренние замкнутые области (например, верхнюю петлю буквы «е»),
а в другой фигуре таких областей нет.
Морфинг сложных фигур 165

Из рисунка понятно, что происходит при морфинге. Flash вполне разумно пыта-
ется преобразовать внешний контур «е» во внешний контур «с», но не знает, что
делать с внутренним контуром, поскольку у буквы «с» такого контура нет. Та-
ким образом, без введения дополнительных линий сделать ничего не удастся.

Рис. 4 . 2 2 . Некачественный морфинг «е» в «с» происходит из-за того,


что фигуры имеют разное количество замкнутых контуров

Ранее уже был описан прием создания прорезей в фигурах (см. трюк 20). Ис-
пользуя его, вы, фактически, обманываете Flash и заставляете его думать, что
сложная фигура (с несколькими замкнутыми контурами) имеет более простую
форму. Аналогичный трюк может использоваться и для сближения разнород-
ных фигур, обеспечивающего более гладкий морфинг.
Применяя ту же методику, мы просто надрезаем петлю буквы «е», чтобы обе
буквы имели одинаковое количество замкнутых контуров. Местонахождение
разреза выбирается таким образом, чтобы Flash было проще преобразовать одну
фигуру в другую. Возможно, с выбором придется немного поэкспериментиро-
вать, но вскоре у вас разовьется необходимая интуиция. В нашем случае разрез
лучше всего расположить в любом месте вдоль горизонтальной линии, образую-
щей нижнюю сторону петли в букве «е». Выберите волосяную линию в свой-
ствах инструмента Line на панели свойств и проведите линию в выбранной точ-
ке. Преобразуйте линию командой Modify • Shape • Convert Lines to Fills и удалите
ее. Контур замкнутой области сливается с внешним контуром, и фигура стано-
вится одноконтурной.
Как видно из рис. 4.23, на этот раз морфинг дает гораздо лучший результат.
Лишние петли исчезают, a Flash принимает вполне разумные решения при уп-
равлении переходом. Теперь Flash правильно преобразует контур «е» в контур
«с», поскольку каждая буква имеет только один замкнутый контур.

Рис. 4.23. Выравнивание количества замкнутых контуров в крайних точках


анимации существенно повысило качество морфинга
166 Глава 4. Анимация

Проблема несовпадения количества замкнутых областей объясняет, почему Flash


так плохо преобразует буквы с изолированными элементами (такие как «i» и «j»)
в «монолитные» буквы вроде «t». Проблема представлена на рис. 4.24.

Рис. 4 . 2 4 . Некачественный морфинг «i» в «t»

Обходное решение - удалить точку из «i» непосредственно перед морфингом,


как показано на рис. 4.25.

Ь'-\

Рис. 4.25. Качественный морфинг «i» в «t» обеспечивается удалением


точки непосредственно перед преобразованием
Морфинг сложных фигур . 167

Но если преобразование выполняется в обратном направлении, то есть от «t» к «i»,


вам придется либо использовать трюк с прорезью и разбить «t» на две замкну-
тые области, либо дождаться завершения морфинга и добавить точку над «i».

Итоги
Векторная графика снижает объем пересылаемых данных, но из-за потенциальных
затрат на обработку Flash накладывает ряд ограничений на ее использование -
например, предполагая, что начальная и конечная формы морфинга имеют оди-
наковое число замкнутых контуров. Как было показано раньше, для преодоле-
ния этих ограничений абсолютно необходимо хорошо разбираться в них. А как
только вы поймете, что Flash вычисляет промежуточные состояния не только
для начальной и конечной фигур, но и для замкнутых контуров, проблему мож-
но считать наполовину решенной.
ГЛАВА 5

Трехмерная графика и физика


Трюки № 35-41
Flash Player не блещет особой скоростью обработки данных и построения ани-
маций. Из-за этого в Flash возникают проблемы с анимацией, требующей интен-
сивного обсчета, - в частности, с трехмерной графикой. Flash не содержит спе-
циализированных команд ActionScript и не использует аппаратную поддержку
трехмерной графики в отличие от пакета Macromedia Director (поддерживающе-
го формат Shockwave 3D).
Тем не менее, если хорошо знать систему и ее ограничения, многие препятствия
удается обойти - просто нужно воспользоваться нестандартным подходом или
упростить проблему. И если уж на то пошло, возможность поворачивать и мас-
штабировать трехмерную модель наручных часов перед покупкой выглядит впе-
чатляюще, но большинство покупателей получает больше впечатлений от хоро-
шей фотографии и графического дизайна в описании продукта.
Трехмерную графику лучше использовать не саму по себе, а совместно с другим^
технологиями. Например, трехмерную анимацию можно объединить с традицион-
ной анимацией, в которой эффект объема создается способностями художника. Хо*-
рошим примером объединения двухмерной и трехмерной анимации служит Flash-
комикс «HitchHiker Part Two» на сайте Bitey Castle (http://www.oohbitey.com/
hh2Window.html). Анимация автомобиля была создана в Swift 3D (http://
www.swift3d.com), а затем наложена на двухмерную фоновую анимацию.
Псевдотрехмерные эффекты поддерживаются графическими интерфейсами боль-
шинства современных операционных систем, и в Flash предусмотрена возмож-
ность создания псевдотрехмерных окон и кнопок. Трехмерные эффекты в пол-
ной мере используются на таких сайтах, как layerbit (http://www.layerbit.com).
Впрочем, реклама Phaeton на английском сайте Volkswagen является примером
гораздо более умеренного применения сценарных трехмерных эффектов - она
выходит на грань возможностей работы с трехмерной анимацией во Flash в ре-
альном времени, но не переступает ее.
Имитация трехмерной графики . 169

ТРЮК
Имитация трехмерной графики
№35 Flash не обладает полноценной поддержкой трехмерной графики, но чтобы
добиться желаемого эффекта, можно разместить фрагменты двухмер-
ного изображения так, словно они находятся в трехмерном простран-
стве.
Flash не обладает поддержкой трехмерной графики, однако объемный эффект
можно имитировать различными способами. Одно из решений - разбить двух-
мерное изображение на срезы и расположить их так, чтобы создать иллюзию
объема.
Примеры использования данного трюка встречаются на многих сайтах - напри-
мер, трехмерная голова на сайте sofake (зайдите на сайт http://www.sofake.com,
щелкните на десятом белом квадратике в нижней части основной страницы и от-
кройте ссылку haircut.swf), а также «Предводитель свободного мира» Энди Фулдса
(откройте страницу http://www.foulds2000.freeserve.co.uk/index_v2.html и щелкни-
те на восьмом квадрате над заголовком Amusements). Тем не менее, впервые
я столкнулся с ним еще во времена Flash 4; тогда его использовали Руйен Зарин
(http://www.zarinmedia.com) и Энт Идеи (http://www.arseiam.com). Энт Идеи раз-
работал превосходный механизм для работы с трехмерными срезами, расширяю-
щий концепцию поворота и масштабирования (щелкните на ссылке 3D на странице
http://www.arseiarri.com/index2.htm). Он позволяет перемещать срезы в трехмер-
ном, а не в двухмерном пространстве, как в этом трюке.
Ранее говорилось о том, как для создания анимации импортировать GIF-файл
в Flash и воссоздать его с расширенными возможностями анимации (см. трюк 4).
В этом трюке используется талисман издательства O'Reilly - долгопят с облож-
ки книги «Learning the vi Editor». Мы перенесем его в трехмерный мир. На
рис. 5.1 долгопят не выглядит объемным; чтобы полностью оценить эффект, за-
грузите файл critterO2.fla с сайта книги.

Имитация дополнительного измерения


с применением срезов
Представьте, что вы нарезаете яблоко параллельно сердцевине. Если ломтики
будут достаточно тонкими, вы получите множество плоских поперечных срезов.
Сложив их в том же порядке, в котором они располагались в яблоке, вы получи-
те трехмерную имитацию яблока.
Данный трюк работает по тому же принципу: мы создаем несколько двухмерных
срезов объекта и перемещаем их так, как если бы они располагались друг над
другом в исходном объекте. При правильной реализации результат выглядит
как трехмерная фигура, обладающая объемом.
170 Глава 5. Трехмерная графика и физика

O ' R E I L L Y ®

ШШШШШШЩШШШШ&ШШШ

©
O ' R E I L L Y

O ' R E I L L Y ®

Рис. 5 . 1 . Объемный долгопят

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

Рис. 5.2. Срезы

Улавливаете? Перед вами простая маска в форме круга, центр которой находит-
ся на носу долгопята (ближайшая к зрителю точка в трехмерном пространстве).
Тем не менее, если наложить срезы друг на друга на плоском экране, никакой
иллюзии объема не появится; все, что мы увидим, - это исходное изображение
Имитация трехмерной графики 171

долгопята. Чтобы добиться желаемого эффекта, мы имитируем то, что происхо-


дит при повороте тела. Если долгопят поворачивается направо (влево по отно-
шению к зрителю), то срезы тоже поворачиваются и открывают его левый бок
(справа от зрителя). При небольшом угле поворота трехмерное движение можно
имитировать простым сдвигом срезов. Верхний, то есть ближний к зрителю срез
слегка смещается влево, а нижний срез (дальний от зрителя) слегка сдвигается
вправо. На этом базовом принципе основана работа трюка - стоит понять его,
и все остальное станет относительно простым.
Чтобы создать срезы, мы кадрируем расширяющийся круг и используем его по-
следовательные состояния для применения масок к исходному клипу с долгопя-
том. Анимация маски останавливается на кадре 19, так что на кадре 20 мы видим
последний срез с полным изображением зверушки без маски. Чтобы увидеть
срезы, загрузите файл critterO2.fla с сайта книги, включите редактирование сим-
вола critter in 3D в библиотеке и переместите индикатор текущей позиции по
временной диаграмме символа, как показано на рис. 5.3.

••ияЯтт я >.
о ' к а•. -
• аи .
. tj::
* % I-.->.:ISli,

Ш -•

Рис. 5.3. Анимированная круглая маска последовательно открывает


изображение долгопята
172 Глава 5. Трехмерная графика и физика

Чтобы отобразить на сцене 20 срезов, свяжите 20 экземпляров клипа critter in 3D


с главной временной диаграммой. Временная диаграмма каждого среза останав-
ливается на одном из 20 кадров анимации.
this.attachMovieC'menu". "menujnc". 1000);
// Размещение заголовка O'Reilly
menujnc._x = 200;
menujnc._y =270;
// Создание объекта инициализации для клипов.
// размещаемых на сцене.
var init:Object = new ObjectO;
i n i t . _ x = 200;
i n i t . _ y = 200;
var siiceDepth:Number = 2 0 :
// К сцене присоединяются 20 экземпляров клипа, остановленных
// на разных кадрах для создания срезов.
for (var i:Number = 1: i < sliceDepth + 1: i++) {
var vritterName:String = " c r i t t e r " + (sliceDepth - i ) :
var critter:MovieClip =this.attachMovie("critter".
critterName. sliceDepth - i.. i n i t ) ;
critter.gotoAndStop(i);
c r i t t e r . o f f s e t = ((sliceDepth - i ) - (sliceDepth / 2)) * 0.05;
critter.onEnterFrame = i n i t C l i p ;
}
Свяжите этот код с кадром 1 главной временной диаграммы. 20 срезов (с имена-
ми от critter20 до critteri) размещаются на глубинах от 20 до 1 в позиции (200,
200). Пока ничего необычного. Обратите внимание на следующую строку:
critter.gotoAndStop(i);
Она останавливает каждый экземпляр на одном из 20 кадров анимации, созда-
вая таким образом 20 уникальных срезов.
Еще одна важная строка:
critter.offset = ((sliceDepth - i ) - (sliceDepth / 2)) * 0.05;
В каждый клип добавляется свойство offset, значения которого лежат в интервале
от -0,5 до 0,5. Свойство offset определяет сдвиг среза влево или вправо в ответ
на смещение указателя мыши (наша дрессированная зверушка следит за мы-
шью).
Далее приводятся обработчики событий, управляющие перемещением отдель-
ных срезов. Функция initClipQ назначается обработчиком события onEnterFrame
для каждого среза; это простой сценарий инициализации, который удаляет сам
себя после одногократного выполнения.
initClip = function () {
// Инициализация среза
this.startX = this._x:
this.startY = this._y:
delete (this.onEnterFrame);
this.onMouseMove = mover;
}:
mover = function 0 {
Имитация трехмерной графики _ _ _ _ ^ _ 173

// Перемещение среза с учетом его позиции в стопке срезов,


var distX = t h i s . o f f s e t * (_xmouse - this._x) / 50:
var distY = t h i s . o f f s e t * (_ymouse - this._y) / 50;
this._x = this.startX + distX;
this._y = this.startY + distY;
updateAfterEventO;
}:
После завершения инициализации функция mover{) будет выполняться при каждом
перемещении указателя мыши. Приведенный обработчик события onMouseMove
практически идентичен коду движения глаз долгопята в обработчике onEnterFrame
(см. трюк 4). Главное различие заключается в том, что в имитации трехмерности
свойство offset слегка смещает каждый срез.
Вот и все, что необходимо сказать об эффекте трехмерности. Концепция на удив-
ление проста, реализация - тоже.
Почему в новом варианте программы используется не то событие, которое исполь-
зовалось ранее для анимации глаз? Во время движения мыши Flash генерирует
события onMouseMove с максимально возможной частотой. События onEnterFrame
генерируются с частотой смены кадров. Когда мышь остается неподвижной, со-
бытия onEnterFrame все равно генерируются, но в процессе движения события
onEnterFrame генерируются реже событий onMouseMove. Чтобы убедиться в этом,
попробуйте запустить оба обработчика одновременно: пусть обработчик onMouseMove
увеличивает переменную при каждом вызове, а обработчик onEnterFrame эту же
переменную уменьшает. Вы увидите, что во время перемещения указателя мы-
ши счетчик растет, потому что в этом время onMouseMove вызывается чаще
onEnterFrame.
Итак, мы выбираем событие, способное обеспечить максимально быстрый от-
клик в той области, на которую направлено внимание пользователя; по этой
причине основные вычислительные мощности (см. трюк 71) концентрируются
в трехмерной анимации, потому что мы предполагаем, что пользователь будет
внимательно смотреть на нее. Анимация глаз слишком тривиальна, и выделение
дополнительных ресурсов не улучшит ее вида, поэтому в данном случае мы ис-
пользовали событие onEnterFrame для снижения нагрузки на процессор.
Ширина и высота срезов также могут меняться в процессе перемещения. При
повороте объекта влево или вправо ширина среза отличается от той, которая
видна спереди. Аналогично при повороте объекта вверх или вниз изменяется
высота среза. Включение фрагмента, выделенного жирным шрифтом, в основной
сценарий анимации иногда (но не всегда!) делает эффект более реалистичным:
mover = function О {
// Перемещение среза с учетом его позиции в стопке срезов,
var distX = t h i s . o f f s e t * (_xmouse - this._x) / 50;
var distY = t h i s . o f f s e t * (_ymouse - this._y) / 50;
this._x = this.startX + distX;
this._y = this.startY + distY;
this._width = 100 - Math.abs(distX)
this.Jieight = 100 - Math.abs(distY)
updateAfterEvent( );
174 Глава 5. Трехмерная графика и физика

Итоги
Теперь, когда вы уловили общий принцип, наш эффект имитации трехмерности
можно было бы усовершенствовать. Фактически, базовая методика отображает
срезы изображения на конус. Если отвести указатель мыши очень далеко от
долгопята, конус становится четко различимым, как показано на рис. 5.4.

Рис. 5.4. Отображение срезов на конус создает искажения

Маска состоит из простых кругов с последовательно изменяющимся диаметром,


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

ТРЮК Панорамные изображения


№36 Немного изобретательности — и вы сможете создавать трехмерные па-
норамы, имитируя эффект присутствия.
Панорамные изображения - прием визуализации, при котором зритель как бы
стоит в центре трехмерного окружения. Изображение можно поворачивать, при-
чем для имитации визуальной глубины в текстурное изображение вносятся
деформации. Методика панорамирования получила широкое распространение
с возникновением таких технологий, как QuickTime VR (http://www.apple.com/
quicktime/qtvr/authoringstudio) от Apple.
Панорамный контент встречается повсеместно, особенно на сайтах турагентств
и бюро путешествий. Тем не менее, большинство решений основано на примене-
нии Java или сторонних модулей, что снижает вероятность их просмотра зрите-
лем, не говоря уже о лицензиях на разработку и развертывание. Хотя на практи-
ке встречается несколько способов панорамирования (сферическое, кубическое
и т. д.), наибольшее распространение получили цилиндрические панорамы, в ко-
Панорамные изображения 175

торых текстура проецируется на стены круглой «комнаты». Цилиндрические


панорамы просты в создании, к тому же, они быстро строятся, что позволяет
Flash Player отображать их с приемлемым быстродействием.
Хотя Flash Player не обладает возможностями и быстродействием некоторых
инструментов просмотра панорамных изображений, он не требует установки
дополнительного программного обеспечения (a Flash Player поддерживается чаще,
чем Java или любой другой сторонний модуль). Кроме того, он позволяет управ-
лять панорамным изображением прямо из Flash-ролика, что позволяет добавить
интерактивные элементы или интегрировать его с другим контентом. Более того,
разработка и распространение не потребуют дополнительных лицензионных
платежей.

Создание панорамных изображений


Панорамное изображение (или просто панорама) представляет собой длинную
горизонтальную полосу с видом окружения (рис. 5.5).

Рис. 5.5. Панорамное изображение

Подобные изображения обычно создаются многократной съемкой с одной точки


поворачивающейся камерой, закрепленной на треноге. Как правило, получен-
ные кадры сшиваются для создания плоского цилиндрического вида. Существуют
различные способы создания и редактирования панорам - от камер, автомати-
чески создающих панорамные фото, до специализированных программ.
Хотя методика создания панорамных изображений выходит за рамки книги, на
самом деле все не так сложно, как может показаться. Тема подробно рассматри-
вается на таких сайтах, как Panoguide.com (http://www.panoguide.com); здесь вы
найдете краткое руководство, по программному обеспечению для редактирова-
ния панорам (http://www.panoguide.com/software/recommendations.html) и галерею
с готовыми панорамами (http://www.panoguide.com/gallery).
Работу над панорамным изображением в Flash мы начнем с файла pano.jpg, за-
гружаемого с веб-сайта книги (в файле pano.fla содержится итоговый вариант
Flash-ролика).

Обработка изображения в Flash


Чтобы имитировать трехмерную панораму, мы нарежем панорамное изображе-
ние на полоски (рис. 5.6.) разных размеров и масштаба, соответствующих раз-
ным глубинам. Для решения задачи будут использоваться множественные эк-
земпляры и маски (см. трюк 35).
176 Глава 5. Трехмерная графика и физика

Хотя на стадии выполнения отображается только область, выделенная на рис. 5.6


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

—|-|
г-|
—1
,,„ ,„.,
- -

- - LJ

Рис. 5.6. Вертикальные срезы панорамы

Для работы с панорамными изображениями обычно используется формат JPEG.


Создайте панораму (или загрузите файл pano.jpg - с сайта книги либо из галереи
Panoguide) и импортируйте файл в Flash (команда File • Import • Import to Library).
Начнем с определения простых переменных, которые будут использоваться в кли-
пе с изображением:
var viewWidth:Number = 450:
var viewHeight:Number = 400;
var precision:Number - 8:
var viewFOV:Number = 60:
где:
viewWidth - ширина исходного панорамного изображения;
viewHeight - высота исходного панорамного изображения;
precision - ширина каждой полосы изображения. Присваивание этой пере-
менной значения 1 гарантирует максимальную точность, но требует слишком
больших вычислительных ресурсов, непозволительных для Flash. Оптималь-
ное значение подбирается вручную посредством тестирования, но начинать
рекомендуется с высокого качества (малых величин) - например, 8. Увели-
чивайте ширину полос только в том случае, если эффект кажется слишком
медленным. Чтобы лучше понять, как работает эффект, попробуйте задать
высокое значение (скажем, 50) - в этом случае становятся хорошо видны
полосы, образующие эффект;
viewFOV - поле зрения в градусах. Переменная определяет величину искаже-
ния, обусловленного масштабированием полос при отходе от центра изобра-
Панорамные изображения 177

жения. Величина напрямую зависит от размера и форматного соотношения


изображения, поэтому ее и приходится задавать вручную. На практике обыч-
но используются значения в интервале от 60 до 80°. Значение Г соответству-
ет отсутствию трехмерного эффекта, то есть, фактически, наложению графи-
ки на плоскость вместо искривленной поверхности. Значение 180° означает
аномально высокое искривление (эффект «рыбьего глаза»).
После задания всех значений изображение необходимо нарезать на полосы. Для
начала нам понадобится функция, генерирующая полосы, которые будут исполь-
зоваться в качестве масок:
this.createBox = function (name:String, x:Number, у:Number.
w:Number, h:Number, target :MovieClip):!iovieClip {
// Функция создает прямоугольники масок
i f (target == undefined) {
target = t h i s :
}
var box:MovieClip = target.createEmptyMovieClip(name.
this.currentDepth++);
box._x = x:
box._y = y;
// Рисование прямоугольника средствами Drawing API
box.lineStyle(undefined);
box.moveTo(0. 0):
box.beginFil 1(0x0.00000. 30):
box.lineTo (w. 0);
box.lineTo (w. h):
box.lineTo (0. h);
box.lineTo (0. 0);
box.endFill();
return (box):
}:
Затем создаются новые изображения, каждое в своей позиции в соответствии
с заданными параметрами (viewWidth, viewHeight, precision и viewFOV). Мы дубли-
руем исходное изображение (предполагается, что оно было предварительно им-
портировано в библиотеку) и создаем для него маску. Файл pano.fla на сайте
книги содержит полностью прокомментированную версию кода (приводится
в сокращенном виде для экономии места):
var xpos:Number = 0:
var currentDepth:Number = 100:
var photoList:Array = [ ] ; •
while (viewWidth^precision != 0) {
viewWidth++:
}
var boxCount:Number = 0;
var stripMask.-MovieClip:
var stripPhoto:MovieClip;
var posX:Number;
var ang:Number:
var h:Number:
var viewTotal-.Number = (viewHeight * 180) / viewFOV:
178 Глава 5. Трехмерная графика и физика

for (var i = 0; i < viewWidth; i+= precision) {


// Вычисление высоты и масштаба для текущей полосы
posX = ((viewWidth / 2) - ( i + (precision / 2 ) ) ) :
ang = Math.asin(Math.abs(posX / (viewTotal / 2 ) ) ) ;
h = (Math.cos(and) * (viewTotal / 2) - viewTotal / 2) * - 1 ;
// Создание области маски
stripMask = this.CreateBox("box_" + boxCount.
i . s, precision. viewHeight);
// Дублирование полосы
stripPhoto= this.photo.duplicateMovieClip("photo_" + boxCount.
1000 + boxCount);
stripPhoto._y = -h:
stripPHoto._xscale = ((viewHeight + h * 2) / photo._height) * 100;
stripPHoto._yscale = stripPhoto._xscale:
stnpPhoto.setMask(stripMask);
photoList.push({photo:stripPhoto. mask:stripMask.
scale:stripPhoto._xscale / 100});
boxCount++;
}
photo._visible = false;
Итак, изображение нарезано на полосы, каждой полосе назначен клип маски,
и полосы масштабированы с правильными коэффициентами. Сцена содержит
большое количество отдельных клипов, каждый из которых виден сквозь «про-
резь» клипа маски при его перемещении слева направо (то есть клип маски
остается неподвижным, пока перемещается маскируемое изображение).
Ссылки на клипы были помещены в массив photolist для упрощения доступа.
Теперь нам понадобится код, который разместит все изображения в правильных
позициях и сформирует изображение, показанное на рис. 5.6.
this.redrawStrips = functionO {
// Перерисовка (повторное позиционирование) всех полос.
// Маски остаются на своих местах,
var tpos:Number;
var epos:Number = 0;
// Создание локальных переменных для обработки
// свойств каждой полосы
// шх: свойство _х клипа маски
// mw: свойство _width клипа маски
// pw: свойство _width клипа полосы
// s: коэффициент масштабирования полосы
var mx:Number;
var mw:Number;
var pw:Number;
var s:Number;
for (var i = 0; i < this.photoList.length; i++) { •
mx = photoList[i].mask._x:
mw = photoList[i].mask._width;
pw = photoLi st[i].photo._width;
s = photoList[i].scale;
tpos = mx - ((epos + xpos) * s);
// Обновление позиции полосы.
Панорамные изорражения 179

// При необходимости происходит циклический возврат к началу,


while (tpos > mx + mw) {
tpos -= pw;
}
while (tpos + pw < mx) {
tpos += pw;
}
// Заполнение промежутка между началом и концом панорамы
i f ( (tpos > mx) && (tpos < mx + mw) ) {
// Дублирование для заполнения (влево)
var alt:MovieClip = photoList[i].photo.duplicateMovieClipC
"alternatePhoto". 998);
a l t . _ x = tpos - pw;
var altM:MovieClip = photoList[i].mask.duplicateMovieClip(
"alternateMask". 997):
alt.setMask(altH);
} else i f ( (tpos + pw > mx) && (tpos + pw'< mx + mw) ) {
// Дублирование для заполнения (вправо)
var alt:MovieClip = photoList[i].photo.duplicateMovieClip(
"alternatePhoto". 998);
a l t . _ x = tpos + pw:
var altM:MovieClip = photoList[i].mask.duplicateMovieClip(
"alternateMask". 997);
alt.setMask(altM):
}
// Перемещение клипа текущей полосы
photoListCi].photo._x - tpos;
epos += mw / s;

Фрагмент получает переменную смещения позиции xpos и перемещает все изоб-


ражения вверх или вниз в зависимости от масштаба каждой полосы. В конце
процесса каждая полоса перемещается вверх или вниз так, чтобы полосы приня-
ли вертикальное расположение, показанное на рис. 5.6.
Наконец, мы задаем исходную позицию и производим перерисовку, чтобы поло-
сы заняли положенные места:
this.xpos = 0 ;
this.redrawStripsQ;
Пока что программа строит статический панорамный вид, но мы предоставим
пользователю возможность поворачивать поле обзора, чтобы он ощутил эффект
глубины и мог лучше рассмотреть панораму. Существует несколько типичных
пользовательских интерфейсов, обеспечивающих возможность прокрутки пано-
рамы. Например, пользователь может нажать кнопку мыши и прокрутить изоб-
ражение (другой вариант - использовать нажатие кнопок мыши для прокрутки
влево и вправо). В нашем примере панорама прокручивается в зависимости от
позиции указателя мыши. Если указатель находится слева от центра экрана, то
при нажатии кнопки мыши панорама прокручивается влево. Прокрутка вправо
выполняется аналогичным образом. Скорость прокрутки зависит от того, на-
сколько удален от центра указатель мыши. В итоговом FLA-ролике указатель
180 Глава 5. Трехмерная графика и физика

мыши заменяется простым клипом в виде стрелки arrow, показывающим направ-


ление прокрутки.
В предыдущем фрагменте перед вызовом метода redrawStrips(), управляющего
позицией полос, а следовательно - и прокруткой, присвается значение перемен-
ной xpos. Заменяя в ролике Flash указатель мыши клипом arrow, необходимо
включить в него и код обработки перемещений мыши.
arrow.onMouseMove = function О {
t h i s . i s l n s i d e = this._parent._xmouse > 0 &&
this._parent._xmouse < this._parent.viewWidth &&
this._parent._ymouse > 0 &&
this._parent._ymouse < this._parent.viewHeight;
i f (this.islnside) {
// Указатель мыши находится над панорамой - заменить
// стандартный указатель стрелкой,
i f (!this._visible) {
Mouse.hideO;
thos._vi sible = true;
}
i f (this._visible) {
// Отобразить кадр со стрелкой, направленной влево или вправо
// в зависимости от текущего положения указателя.
this.gotoAndStop((this._parent._xmouse < this._parent.viewWidth / 2) ?
"left" : "right");
}
} else {
// Указатель мыши расположен не над панорамой - отобразить
// стандартный указатель мыши вместо пользовательского,
if (this._visible) {
Mouse.show();
this.visible = false;

}
arrow.onMouseDown = function О {
// Если кнопка мыши нажата, изменить xpos для создания эффекта прокрутки
// при вызове redrawStripsO
this.onEnterFrame = function О {
i f (this.islnside) {
this._parent.xpos -= ((this._parent.viewWidth / 2) - t h i s . j O / 10;
// Максимальная скорость перемещения
this._pa rent. redrawStripsO;

arrow.onMouseUp = functionO {
this.onEnterFrame = undefined:
}:
Приведенный код реализует только панораму с возможностью прокрутки вле-
во/вправо, а прокрутка по вертикали не поддерживается; однако он достаточно
прост и при необходимости легко модифицируется.
Оптимизированный трехмерный плоттер 181

Если вы не боитесь трудностей, попробуйте имитировать панораму, наложен-


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

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

Оптимизированный трехмерный
ТРЮК

№37 плоттер
Создание компактного и быстрого механизма для рисования простых трех-
мерных объектов на сцене Flash.
Полноценная трехмерная графика возможна лишь при подаче двух разных изоб-
ражений в глаза зрителя. На основании различий в изображениях мозг зрителя
вычисляет пространственную глубину каждого объекта (так называемое стерео-
скопическое зрение). Например, в очках для просмотра стереофильмов исполь-
зуются красные и синие фильтры (или фильтры с вертикальной и горизонталь-
ной поляризацией), при помощи которых на каждый глаз подаются разные
изображения - на киноэкран проецируются два разных изображения со смеще-
нием, а мозг конструирует из них единую картинку. Однако в так называемой
трехмерной компьютерной графике вместо вывода разных изображений трех-
мерный объект проецируется на плоскость. Если закрыть один глаз, рисунок не
изменится, просто мозг зрителя делает разумные предположения относительно
глубины элементов изображения на основании масштаба и положения теней.
Создать простейший механизм трехмерного вывода не так сложно, как может
показаться. В этом трюке приведена математическая база для написания просто-
го трехмерного плоттера, преобразующего координаты точки в трехмерном про-
странстве (х, у, z) в двухмерные координаты (х, у) на плоскости сцены Flash.
Как и большинство графических программ, Flash использует систему коорди-
нат, показанную на рис. 5.7: ось Y направлена сверху вниз (а не снизу вверх, как
в декартовой системе координат). Ось X идет в обычном направлении, то есть
слева направо.
Flash поддерживает только двухмерную графику (оси X и У). Чтобы имитировать
ось Z, мы аппроксимируем глубину применением масштабирования. На рис. 5.8
182 Глава 5. Трехмерная графика и физика

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


смещение по оси Z также может привести к изменению позиций X и Y.

Рис. 5.7. Ось У в системе координат Flash направлена сверху вниз

Рис. 5.8. Перемещение куба вдоль оси Z

Масштабный коэффициент для координат х и у на расстоянии z при просмотре


через камеру с фокусным расстоянием / 0 равен /„/( / 0 + z).
Для воспроизведения точки трехмерного пространства (х, у, z) на плоскости (х, у)
с масштабом 5 можно воспользоваться следующими аппроксимациями:
scale = f 0 / (fo+z)
xLoc = x * scale
yLoc = у * scale
s = 100 * scale
Хотя масштаб полноценного трехмерного объекта изменяется в зависимости от
глубины (ближние грани выглядят более крупными, чем дальние), простоты ради
мы интерпретируем объект как существующий в одной точке пространства. Та-
кая аппроксимация обеспечивает приемлемую точность (кроме очень больших
или очень близких к камере объектов).
Данная аппроксимация легко реализуется на программном уровне - фактиче-
ски, программа превращается в простейший трехмерный плоттер. Создайте но-
вый ролик FLA со стандартными размерами сцены (550 х 400), назначьте ему
Оптимизированный трехмерный плоттер 183

частоту смены кадров 24 fps. Свяжите следующий код с кадром 1 главной вре-
менной диаграммы:
function moveSpheresO {
// Функция перемещения сферы
for (var i:Number = 0: i < n: i++) {
pX[i] += pXS[i];
i f (Math.abs(pX[i]) > wSize) {
pXS[i] = -pXS[i]:
}
pY[i] +« pYS[i];
i f (Math.abs(pY[i]) > wSize) {
pYS[i] = -pYS[i];
}
pZ[i] += pZS[i] * scale;
i f (Math.abs(pZ[i]) > wSize) {
pSZ[i] = -pZSCi];
}
threeDPlotter(i);

}
function threeDPlotter(i) {
scale = flength/(flength + p Z [ i ] ) ;
world["p"+i]._x = (pX[i] * scale);
world["p"+i]._y = (pY[i] * scale);
world["p"+i]._xscale = world["p"+i]._yscale = 100 * scale;
}
// ОСНОВНОЙ КОД
var fLength:Number = 150;
var wSize:Number = 100;
var centerX:Number = 275:
var centerY:Number = 200;
var n:Number = 30;
var pX:Array = new ArrayO;
var pX:Array = new ArrayO;
var pY:Array = new ArrayO;
var pZ:Array = new ArrayO;
var pXS:Array = new ArrayO;
var pYS:Array = new ArrayO;
var pZS:Array = new ArrayO;
// Построение модели трехмерного мира
thi s.createEmptyMovi eCli p("worl d". 0);
world._x = centerX;
world._y = centerY;
// Инициализация сфер
for (var i:Number = 0; i < n; i++) {
world.createEmptyMovieClipC'p" + i. i ) ;
world["p"+i].lineStyle(10. 0x0. 100):
world["p"+i].moveTo(0, 0):
184 Глава 5. Трехмерная графика и физика

world["p"+i].lineTo(l. 0):
pX[i] = pY[i] = pZ[i] = 0;
pXS[i] - Math.randomO * 5;
pYS[i] = Math.randomO * 5;
pZS[i] = Math.randomO * 5:
threeDPlotter(i):
}
// Настройка обработчика события onEnterFrame
this.onEnterFrame = moveSpheres;
При выполнении этого кода в трехмерном мире перемещаются 30 сфер (рис. 5.9).
Вскоре вы поймете, почему сферы рисуются в виде простых черных кругов, без
эффектных бликов.

• • • < • • •

• 4
• • • « • •

• •

Рис. 5.9. Точки в трехмерном мире {два разных момента времени)

Проанализируем некоторые участки основного кода. Сначала в нем определя-


ются следующие переменные:
• fLength - фокусное расстояние;
• centerX, centerY - положение начала координат трехмерного мира (относи-
тельно сцены Flash);
• п - количество точек в анимации;
• wSize - расстояние от начала координат до каждой грани трехмерного куба,
определяющего границы трехмерного мира. Поскольку начало координат на-
ходится в центре куба, ребра куба имеют длину 2*wSize.
Структура трехмерного мира изображена на рис. 5.10.
В трехмерном мире местонахождение и скорость точек задаются следующими
параметрами:
• рХ, pY, pZ - координаты (х, у, г) точек анимации;
• pXS, pYS, pZS - скорость и направление (то есть вектор скорости) каждой
точки.
Затем мы создаем анимационный клип с именем world, в котором создаются
клипы всех сфер, от р, до р .
Функция moveSpheresO постоянно обновляет позиции сфер и заставляет их от-
ражаться от граней нашего кубического мира. Она также вызывает функцию
Оптимизированный трехмерный плоттер 185

threeDPIotterQ, которая преобразует пространственные координаты (х, у, z) в по-


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

Рис. 5.10. Трехмерный мир

p o s i t i o n ( p X , pY, p Z )

velocity (pXS, pYS, pZS)

Рис. 5 . 1 1 . Местонахождение и скорость точки в трехмерном мире

Использование черных кругов (то есть кругов с однородной заливкой) позволя-


ет обойтись без хранения информации об относительной глубине точек, то есть
без буфера глубины, поскольку зритель не может определить, какая точка
186 Глава 5. Трехмерная графика и физика

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


необходимых для построения динамической трехмерной сцены.
Трехмерная сцена строится внутри клипа world, чтобы позицию начала коорди-
нат можно было изменять простым перемещением клипа world (при этом не
приходится вносить дополнительные смещения на каждом кадре вычислений,
что привело бы к замедлению построения сцены).

Итоги
Несмотря на свою тривиальность, представленный механизм способен стать на-
чальной точкой для построения более совершенных механизмов трехмерной гра-
фики:
• соединяя точки отрезками, можно строить трехмерные векторные модели
(см. трюк 85);
• введение буфера глубины (z-буфера) повысит реалистичность представления
трехмерного мира. В частности, это позволит использовать сферы с бликами
вместо простых черных кругов.
Построение трехмерных изображений в реальном времени интенсивно расходу-
ет ресурсы процессора. Как было показано в текущем разделе, упрощение этой
задачи позволяет быстро создать эффект с минимальными затратами ресурсов.

ТРЮК Гравитация и трение


№38 Многие явления реального мира (такие как гравитация и трение) влияют
на скорость перемещения объектов во времени. Простые уравнения
с ускорением позволяют моделировать эти изменения и создавать ре-
алистичные эффекты движения объектов в имитируемых физических ус-
ловиях.
Некоторые физические эффекты трудно реализовать в сценарной анимации без
наличия математической базы. Впрочем, вычисления с ускорением реализуются
проще, чем может показаться на первый взгляд. Силы гравитации и трения, как
и все силы, воздействующие на объекты с массой, ускоряют или замедляют дви-
жение объекта. При выполнении итерационных вычислений (всегда применяе-
мых при анимации спрайтов во времени) математика оказывается на удивление
простой.
При моделировании реального движения на объект довольно часто воздейству-
ет сразу несколько сил, ускоряющих и замедляющих его перемещение (напри-
мер, силы притяжения и трения, действующие на тело во время падения). Если
силы уравновешены (как сила тяги реактивного самолета уравновешивает силу
сопротивления воздуха), скорость объекта остается постоянной, то есть объект
двигается с нулевым ускорением. Весь фокус заключается в простом суммиро-
вании сил для определения их совокупного воздействия на объект.
Гравитация и трение 187

Такие силы, как сила притяжения, создают постоянное ускорение. Иначе гово-
ря, скорость объекта изменяется во времени с постоянным приращением. Ско-
рость объекта в конце интервала равна сумме его начальной скорости и произве-
дения значения ускорения на продолжительность интервала:
newV = oldV + (ускорение * время)
Позиция объекта в конце интервала равна сумме начальной позиции и скорости,
умноженной на продолжительность интервала:
newPos = oldPos + (newV * время)
Если позиция и скорость вычисляются настолько часто, что скорость при каж-
дой итерации может считаться постоянной, а продолжительность интервала при-
нимается за 1, то уравнение позиции упрощается до следующего вида:
newPos = oldPos + newV
Проще говоря, это означает: «Чтобы вычислить новую позицию, следует взять
старую позицию и прибавить к ней текущую скорость». Например, если машина
едет со скоростью 60 км/ч, то за один час она сместится на 60 км от исходной
позиции. Таким образом, в каждом кадре анимации мы смещаем позицию на
небольшую величину в направлении вектора скорости.
В конце интервала вычисляется новое значение скорости, учитывающее ускоре-
ние. Уравнение скорости по знакомому принципу упрощается до вида
newV = oldV + ускорение
Переведем: «Чтобы вычислить текущую скорость, следует взять исходную ско-
рость и прибавить к ней значение ускорения». Например, если машина едет со
скоростью 60 км/ч, и за одну секунду ее скорость увеличивается на 10 км/час, то
через одну секунду ее скорость составит 70 км/ч. В каждом кадре анимации к
скорости прибавляется величина приращения в направлении вектора ускорения
(для силы притяжения этот вектор обычно направлен вниз).
Ускорение, обусловленное силой притяжения Земли, составляет примерно
9,8 м/с 2 . Впрочем, если вы не пытаетесь моделировать конкретные физические
условия, для ускорения можно использовать любую постоянную величину.
Сила трения покоя (сила трения, действующая на неподвижное тело) должна
быть больше силы трения качения (которая действует, скажем, на катящийся
мяч). Сила трения воздуха обычно возрастает пропорционально скорости объекта,
поэтому мы воспользуемся простым коэффициентом трения, считая итоговое
воздействие пропорциональным текущей скорости.
Следующая программа генерирует несколько частиц (см. трюк 33) и анимйру-
ет их, заставляя двигаться под воздействием силы притяжения и трения возду-
ха:
function f a l l ( ) {
// Прибавление ускорения, обусловленного гравитацией
this.speedY +- GRAVITY:
// Учет воздействия силы трения
this.speedY *= FRICTION:
188 Глава 5, Трехмерная графика и физика

// Предполагается, что .обе силы


// воздействуют исключительно в направлении Y.
this._y += this.speedY;
// При соприкосновении с "полом" клип подпрыгивает вверх
i f ( t h i s . _ y > 400) {
this._y = 400:
this.speedY = -this.speedY * ELASTICITY;

function dragO {
// Когда пользователь щелкает на клипе, активизировать режим
// перетаскивания и прекратить его анимацию
// на базе события onEnterFrame.
this.startDragO ;
delete this.onEnterFrane:
// Чтобы сэкономить на вызове функции, можно воспользоваться
// вызовом следующего вида:
// this.onMouseMove = updateAfterEvent:
// поскольку обработчик onMouseMoveO вызывает только одну функцию.
// Тем не менее, мы используем следующее определение функции
// на случай, если потребуется реализовать дополнительные возможности
// (скажем, проверку границ, предотвращающую перетаскивание клипа
// за пределы сцены).
this.onMouseMove = functionO {
updateAfterEventO:

}
function dropO {
// Инициализация анимации и выход из режима перетаскивания клипа.
// Исходная скорость по оси Y равна нулю,
this.speed.у = 0:
this.stopDragt):
this.onEnterFrame = fall;
// ОСНОВНОЙ КОД
// Создание 20 клипов со сферами
for (var i = 0: i < 20; i++) {
var ball:MovieClip = this.createEmptyMovieClipC'ball" + i. i ) :
ball.lineStyle(6. 0x0. 100):
ball .moveTo(0. -3):
ball .UneToCl. -3):
ball._x = Math.randomO * 550;
ball._y = Math.randomO * 200:
ball.speedY = 0:
ball.onEnterFrame = fall;
ball.onPress = drag;
ball.onRelease = ball.onReleaseOutside = drop;
}
// Инициализация физических констант
var GRAVITY:Number = 0.5;
var FRICTION:Number = 0.995;
Гравитация и трение 189

var ELASTICITY:Number =0.85:


// Рисование линии нулевого уровня
this.lineStyleCO. OxDDDDDD. 100);
this.moveTo(0. 400):
this.lineTo(550. 400);
Чтобы имитировать эоздействие гравитации, мы выполняем для каждого кадра
следующую строку, изменяющую скорость в направлении Y:
this.speedY += GRAVITY:
Если шар падает, гравитация увеличивает скорость и ускоряет падение. Если
шар поднимается, гравитация уменьшает скорость и замедляет набор высоты.
Словом, все происходит точно так же, как с мячом, ударившимся о землю.
Воздействие трения имитируется следующей строкой:
this.speedY *= FRICTION:
Если коэффициент FRICTION меньше 1, то шар замедляет движение независимо
от его направления (как под воздействием настоящей силы трения). Если он
равен 1, сила трения отсутствует. Наконец, если FRICTION больше 1, то на тело
действует «отрицательная» сила трения, и оно получает импульс наподобие ре-
активного, в результате чего движение тела не замедляется, а ускоряется.
Когда мяч ударяется о пол и отпрыгивает, желательно имитировать потерю энер-
гии, типичную для подобных столкновений. Коэффициент эластичности приме-
няется в строке
this.speedY *- ELASTICITY:
Если коэффициент ELASTICITY меньше 1, то при столкновении шар теряет часть
энергии, как и в реальном мире. Если он равен 1, шар абсолютно эластичен (при
отсутствии силы трения он бы вечно подпрыгивал на одну и ту же высоту). Если
задать коэффициенту ELASTICITY значение больше 1, то с каждым ударом шар
будет подпрыгивать все выше и выше.

Итоги
Поскольку анимация выполняется на уровне кадров, уравнения движения в ней
выглядят проще, чем те уравнения, которые мы изучали на уроках физики. Дви-
жение на уровне кадров всегда описывается линейными уравнениями, благода-
ря чему сценарии становятся короткими и эффективными. Попробуйте реализо-
вать движение не только по оси У, но и по оси X (подсказка: гравитация по оси X
не действует, поэтому шару необходимо придать начальную горизонтальную
скорость).
В анимацию можно внести всевозможные дополнения: попробуйте изменить
коэффициент гравитации (и даже сделать его отрицательным, чтобы объекты не
притягивались, а отталкивались). Если задать нулевой уровень гравитации, кар-
тина приобретет такой вид, словно камера находится над бильярдным столом.
Разместите на сцене бегунки для управления гравитацией, силой трения и элас-
тичностью - и экспериментируйте! При желании добавьте звуки или реализуй-
те деформацию шара при ударе.
190 Глава 5. Трехмерная графика и физика

ТРЮК
Имитация броска
№39 Чтобы сделать интерфейс более реальным, попробуйте реализовать эф-
фект броска: объект перетаскивается мышью, а при отпускании кнопки
продолжает двигаться в прежнем направлении.
Как было показано ранее, воздействие ускорения (см. трюк 38) и силы трения,
включая сопротивление воздуха, гораздо проще имитировать на уровне отдель-
ных кадров, а не посредством реализации физических уравнений.
В этом трюке представлен простой способ имитации бросания объектов.
В момент броска определяется воображаемый вектор силы. Направление векто-
ра определяет начальное направление перемещения объекта, а его длина про-
порциональна силе броска (и, соответственно, определяет дальность полета бро-
шенного объекта).
В Flash сила броска неизвестна, так как в этом виртуальном мире не существует
понятий силы и массы, поэтому мы имитируем движение другим способом, кото-
рый выглядит довольно реалистично. Как это обычно бывает при имитации фи-
зических процессов в Flash, модель должна быть близка к идеалу лишь до той
степени, до которой ее эффект выглядит реалистично. На практике сгенерирован-
ное движение не является абсолютно точным, но, по крайней мере, близко к нему.
На рис. 5.12 изображен шар в момент броска. Пользователь молсет щелкнуть
на шаре и протащить его по сцене (шар двигается в направлении, в котором
двигался указатель мыши в момент отпускания кнопки).

Рис. 5.12. Бросание объекта

Если измерить расстояние, на которое шар передвигается за один кадр, то сила


броска Flash пропорциональна расстоянию d между двумя последними позици-
ями шара (предполагается, что позиция шара измеряется с постоянными интер-
валами - например, с частотой смены кадров). Расстояние между двумя пози-
циями пропорционально скорости перетаскивания. Когда вы отпускаете кнопку
мыши, шар следует в направлении «броска».
Программная реализация эффекта броска приведена в следующем листинге (стро-
ки пронумерованы для удобства). Функция drawPipQ рисует шар, а функция
throwClipQ определяет обработчики событий, управляющие инициализацией брос-
ка. Обработчик onMouseMove отслелшвает разность между последней известной
и текущей позициями шара и сохраняет их в виде вектора (dirX, dirY). Вектор
определяет как направление, так и силу броска.
Чтобы увидеть наглядное представление вектора силы, раскомментируйте все
закомментированные строки между двумя наборами комментарием "^Диагнос-
тика** (строки 24-26 и 50-52). Так вы легко поймете, как работает этот код.
Имитация броска 191

Цикл анимации начинается с события onPress (строка 15) при нажатии кнопки
мыши на клипе ball; обработчик события активизирует режим перетаскивания.
Точка отпускания обнаруживается либо обработчиком события onRelease (цикл
«нажатие кнопки мыши - перетаскивание - отпускание»), либо обработчиком
события onReleaseOutside, если указатель мыши вышел за пределы сцены (в этом
случае вы просто «роняете» шар, не бросая его). Обработчики событий onRelease
и onReleaseOutside начинаются в строке 31, они создают интервальный таймер,
который вызывает функцию moverQ для управления анимацией шара после
броска.
Функция mover() использует переменные dirX и dirY для управления перемеще-
нием шара. С течением времени вертикальная составляющая вектора наращивает-
ся константой GRAVITY, а составляющие dirX и dirY уменьшаются с коэффициентом
FRICTION. Инертная масса шара косвенно моделируется константой MOMENTUM.
Чем больше значение MOMENTUM, тем больше амплитуда вектора силы.
Интервал сбрасывается (строка 17) в функции onPress (начало - строка 15) при
повторном щелчке на шаре. В этот момент цикл броска начинается заново.
1 // Код ActionScnpt 2.0
2 function drawPip(clip:MovieClip. clipName:String, clipDepth:Number.
3 x:Number, у:Number):MovieClip {
4 var pip:MovieClip = clip.createEmptyMovieClip(clipName, clipDepth);
5 pip.lineStyle(20. 0x0. 100);
6 pip.moveTo(0, 0);
7 pip.lineToCl. 0);
8 pip-_x = x:
9 pip._y = y:
10 return pip;
11 }
12 function throwClip(clip:MovieClip):Void {
13 clip.oldX = clip._x;
14 clip.oldY = clip._y;
15 clip.onPress = functionO {
16 clip.startDrag(true. -265. 190. 265. -200);
17 clearlnterval(clipMove):
18 clip.onMouseMove = functionO {
19 clip.dirX = MOMENTUM * (clip._x - clip.oldX);
20 clip.dirY = MOMENTUM * (clip._y - clip.oldY):
21 clip.oldX = clip._x;
22 clip.oldY = clip._y:
23 // ** Диагностика **
24 // clip.line = clip.createEmptyMovieClipC'line". 0):
25 // clip.line.lineStyle(4. 0x0. 100);
26 // clip.line.lineTo(5 * clip.dirX. 5 * clip.dirY);
27 /7 ** Диагностика **
28 updateAfterEventO;
29 };
30 };
31 clip.onRelease = clip.onReleaseOutside = functionO {
32 clip.stopDragO;
33 delete clip.onMouseMove;
192 Глава 5. Трехмерная графика и физика

34 clipMove = setlnterval(mover, 1. clip);


35 }:
36 }
37 function mover(clip):Void {
38 i f (Math.abs(clip._x) > 265)' {
39 clip.dirX = -clip.dirX;
40 }
41 i f (clip._y > 190) {
42 clip.dirY = -clip.dirY:
43 clip._y = 190:
44 }
45 clip.dirX = clip.dirX * FRICTION:
46 clip.dirY = (clip.dirY * FRICTION) + GRAVITY:
47 clip._x += clip.dirX;
48 clip._y += clip.dirY;
49 // ** Диагностика **
50 // clip.line = clip.createEmptyMovieClipC'line". 0):
51 // clip.line.lineStyle(4. 0x0. 100);
52 // clip.line.lineTo(5 * clip.dirX, 5 * clip.dirY):
53 // ** Диагностика **
54 updateAfterEvent():
55 }
56 var MOMENTUM:Number * 0.8;
57 var GRAVITY:Number =0.5:
58 var FRICTION:Number = 0.99:
59 this._x = 275:
60 this._y = 200:
61 this.lineStyle(20. 0x0. 100);
62 this.moveTo(-275. -200):
63 this.lineTo(-275. 200);
64 this.lineTo(275. 200);
65 this.lineTo(275. -200);
66 var ball :MovieCl.ip = drawPipCthis. "ball". this.getNextDepthO. 0, 190);
67 throwClip(ball);

Итоги
Программистам, работающим в стиле Flash MX, стоит обратить внимание на то, что
в обработчиках событий никогда не используется текущий объект this. Вместо этого
имя целевого клипа передается в аргументах функций. Такое решение работает го-
раздо эффективнее - чтобы убедиться в этом, попробуйте заменить clip на this в са-
мом часто выполняемом коде события (обработчик onMouseMove, строки 18-30).
Flash Player 7 оптимизирован для быстрой обработки данных, передаваемых в ар-
гументах (см. трюк 100); данный стиль кодирования является предпочтитель-
ным для кода ActionScript 2.O. Оптимизация основана на том факте, что Flash
Player сохраняет данные в нескольких аппаратных регистрах (вместо обраще-
ния к переменным в памяти).
Если заменить ссылки на клипы, передаваемые в аргументах, псевдопеременной
this, Flash Player не применяет регистровую оптимизацию, поэтому программа
работает медленнее.
Обнаружение множественных столкновений 193

Обнаружение множественных
ТРЮК
№40 столкновений
Обнаружение столкновений используется в играх и имитациях. Попробу-
ем усовершенствовать стандартный механизм обнаружения коллизий
Flash для нетривиальной анимации.
Flash позволяет обнаруживать столкновения между двумя клипами методом
MovieClip.hitTest(). Метод возвращает true, если столкновение было обнаружено,
или false при отсутствии столкновений.
Само понятие «столкновение» тоже понимается по-разному. Столкновением
можно считать контакт точки с краем клипа, а также ограничивающими прямо-
угольниками двух клипов (то есть прямоугольниками, окружающими клипы при
их выделении в среде разработки). Обе ситуации будут рассмотрены далее.
Предположим, на сцене находятся два клипа: clipA и clipB. Следующий код акти-
визирует режим перетаскивания клипа clipA и выводит значение true для каждо-
го кадра, в котором ограничивающие прямоугольники clipA и clipB перекрывают-
ся. В противном случае выводится значение false.
clipA.onEnterFrame = function О {
hit = clipA.hitTest(clipB):
trace(hit):
}:
cl ipA.startDrag(true);
Данный способ обнаружения столкновений имеет один серьезный недостаток:
столкновения обнаруживаются при соприкосновении ограничивающих прямоу-
гольников даже в том случае, если пикселы внутри клипов не перекрываются.
На рис. 5.13 две круговые области клипов не имеют общих точек, но метод hitTest()
из предыдущего листинга возвращает true, потому что ограничивающие прямоу-
гольники перекрываются.

Рис. 5.13. Метод hitTest() возвращает true, если перекрываются


ограничивающие прямоугольники

Первое возможное решение - обнаруживать столкновения вручную. Для кру-


гов это делается легко: если расстояние между центрами кругов меньше сум-
мы радиусов, значит, круги перекрываются. Следующий фрагмент проверяет
194 Глава 5. Трехмерная графика и физика

столкновения между кругами, при этом расстояние между точками вычисляется


по теореме Пифагора:
function circleHHTest (circlel. circle2) {
var a = circlel._x - circle2._x:
var b = circlel._y - circle2._y:
clist = Math.sqrt(Math.pow(a. 2) + Math.pow(b, 2));
return dist < Math.abs(circlel._width/2 - circle2._width/2):
}
В другом варианте используются графические объекты почти прямоугольной
формы, практически целиком заполняющие ограничивающую область клипа.
Идея не столь глупа, как может показаться на первый взгляд: она часто приме-
нялась при программировании первых видеоигр (кстати, именно из-за этого ко-
рабли космических агрессоров бывали более или менее прямоугольными).
Обнаружение столкновений также часто производится по отношению к точке
и клипу. Следующий фрагмент проверяет, принадлежит ли текущая позиция
указателя мыши клипу clipA:
this.onEnterFrame = functionO {
hit = clipA.hitTest(_xmouse. _ymouse. true):
trace(hit):
}:
Фрагмент возвращает true, если указатель мыши находится на одном из пиксе-
лов клипа clipA (включая пикселы с нулевым альфа-каналом и даже скрытые,
если клип был скрыт кбмандой clipA._visible=false).
ActionScript не содержит встроенных средств проверки столкновений между
отдельными пикселами двух клипов. Проверка столкновений возможна либо
между ограничивающими прямоугольниками двух клипов, либо между точкой
и пикселами клипа.
Хотя теоретически можно проверять столкновения между любыми двумя кли-
пами, на практике количество клипов ограничивается в зависимости от того,
насколько быстро Flash может выполнять вычисления. При взаимодействии боль-
шого количества клипов процессор просто не успевает перебрать тысячи воз-
можных комбинаций. Встроенных событий, оповещающих о столкновениях, не
существует, поэтому, чтобы узнать о произошедших столкновениях, вам придет-
ся постоянно проверять их вручную. При сколько-нибудь значительном количе-
стве клипов такие операции выполняются очень медленно.
И все же спасительный выход существует (а не будь его, разве можно было
бы назвать это «трюком»?) Многие разработчики не понимают, что метод
MovieClip.hitTest() при проверке столкновений распознает вложенные клипы.
Если упорядочить временные диаграммы в «иерархию столкновений» вложен-
ных клипов, столкновение между одним клипом и сотней других может быть
обнаружено единственной проверкой. Также возможен вариант создания оптими-
зированного механизма проверки столкновений, который работает только в том
случае, если некоторые столкновения уже произошли (вместо проверки всех воз-
можных столкновений в каждом кадре). Давайте посмотрим, как это делается.
Обнаружение множественных столкновений 195

Иерархия столкновений
На практике обычно требуется обнаружить столкновения между одним объек-
том и группой других объектов, будь то молекулы газа в физической имитации,
орда космических агрессоров или стены лабиринта. Допустим, мы хотим выя-
вить столкновения с одним графическим объектом, представляющим игрока
(игрового персонажа, находящегося под управлением пользователя).
В медленном способе проверки столкновений каждый клип рассматривается как
отдельная сущность. Таким образом, если в видеоигре на экране находится од-
новременно 20 инопланетных кораблей, придется проверять столкновения меж-
ду кораблем игрока и каждым инопланетянином по отдельности.
Вместо этого правильнее объединить всех инопланетян в один клип (например,
alienSwarm). Полученная иерархия изображена на рис. 5.14.

JeveS-sSenSwarm.afersJ

Рис. 5.14. Иерархия инопланетян внутри клипа alienSwarm

После этого столкновения между инопланетянами и кораблем игрока проверя-


ются как столкновения между клипами alienSwarm и ship независимо от количе-
ства инопланетных кораблей. Еще важнее то, что процесс обнаружения не за-
медляется даже при большом количестве инопланетян в группе!
Чтобы опробовать эту методику, создайте клип с именем ship и убедитесь в том,
что его точка регистрации находится возле вершины (рис. 5.15). Треугольник
представляет космический корабль игрока.

Рис. 5.15. Точка регистрации находится возле носа космического корабля

Создайте второй клип с именем asteroid (рис. 5.16), присвойте ему идентифика-
тор компоновки asteroid. Положение точки регистрации в этом клипе несуще-
ственно.
196 Глава 5. Трехмерная графика и физика

Разместите клип ship в нижней части сцены, где обычно находится корабль иг-
рока в классической игре «Space Invaders».

Рис. 5.16. Символ клипа asteroid

Добавьте следующий код в первый (и единственный) кадр временной диаграм-


мы. Как обычно, этот код рекомендуется разместить на отдельном уровне actions,
выделенном специально для этой цели:
function shipMoveO {
// Обнаружение нажатий клавиш и соответствующее перемещение клипа ship,
i f (Key.isDown(left)) {
ship._x -= playerSpeed:
}
i f (Key.isDown(right)) {
ship._x += playerSpeed:
}
// Проверка столкновений
if (asteroidBelt.hitTest(ship._x, ship._y. true)) {
traceC'collision"):
}
updateAfterEventO;
function asteroidMoveO {
// Перемещение астероида
this._y += this.asteroidSpeed:
if (this._y > 400) {
this._x = Math.randomO * 550:
this._y = 0:
}
function createAsteroidsO {
// Создание анимационного клипа asteroidBeit. Внутри клипа
// создаются 20 вложенных клипов, представляющих астероиды:
// от asteroidO до asteroidl9.
this.createEmptyMovieClip("asteroidBelt". 0):
initAsteroid = new ObjectO; • s
for (i = 0: i < 20: i++) {
initAsteroid._x = Math.randomO * 550:
initAsteroid._y = Math.randomO * 400:
initAsteroid.asteroidSpeed = Math.round(Math.random() * 3) + 2 ) :
initAsteroid.onEnterFrame = asteroidMove;
asteroidBelt.attachMovieC'asteroid". "asteroid" + i . i . initAsteroid)

}
// Инициализация
left = Key.LEFT:
Обнаружение множественных столкновений 197

right = Key.RIGHT:
playerSpeed = 10;
asteroidSpeed = 3;
shiplnterval = setlnterval(shipMove. 10):
createAsteroidsO:
Функция createAsteroidsO создает клип с именем asteroidBelt, содержащий 20 вло-
женных клипов с именами asteroidO- asteroid 19. Астероиды постепенно переме-
щаются по экрану.
Клип ship перемещается клавишами <— и ->. Цель игрока - уклониться от столк-
новения с астероидами.
Анимация корабля управляется событием setlnterval() и получает гораздо боль-
шую долю ресурсов Flash Player (см. трюк 71). Астероиды управляются обра-
ботчиками onEnterFrame, поэтому их анимация выполняется на более низкой
частоте (частоте смены кадров).
Если корабль игрока сталкивается с одним или несколькими астероидами, на
панели Output выводится слово «collision»'для каждого кадра, в котором такое
столкновение произошло. Ключевой фактор, обеспечивающий высокое быстро-
действие, - единая проверка столкновений для всего пояса астероидов:
i f (asteroidBelt.hitTest(ship._x. ship._y. true)) {
trace("collision"):

Столкновения в обратной иерархии


Иерархии столкновений позволяют существенно повысить быстродействие, но
работают только в одном направлении. Например, можно обнаружить столкно-
вение между поясом астероидов и кораблем игрока, но нам не удастся обнару-
жить столкновение между лучом лазера и отдельными астероидами (такая про-
верка необходима, чтобы астероиды взрывались при попадании в них).
Но даже в таких ситуациях иерархия столкновений оказывает неоценимую по-
мощь - она сообщает о самом факте столкновения. Наличие такой информации
позволяет оптимизировать код обнаружения столкновений - функция обнару-
жения столкновений между лазером и отдельными астероидами заведомо вы-
полняется только в том случае, если столкновение уже произошло.
Для примера рассмотрим один из возможных сценариев.
Сначала проверяется столкновение между лазером и поясом астероидов. Если
столкновение обнаружено, мы знаем, что лазер попал в какой-то астероид, -
хотя пока неизвестно, в какой именно.
Сравним свойства _х или _у отдельных астероидов с позицией лазера и исклю-
чим астероиды, находящиеся слишком далеко. Тем самым из проверки будут
исключены почти все астероиды.
Для оставшихся астероидов проводится индивидуальная проверка столкнове-
ний (функцией MovieClip.hitTestO).
Вторичная функция проверки столкновений (для отдельных астероидов) будет вы-
полняться гораздо реже первичной функции hitTestO (для всего пояса астероидов).
198 Глава 5. Трехмерная графика и физика

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

Итоги
Поиск столкновений не должен создавать проблем для имитаций, требующих вы-
сокого быстродействия. Объединение графических объектов в иерархию позволит
существенно сократить время, необходимое для обнаружения столкновений.
В типичной игре-«стрелялке» должно присутствовать несколько функций обна-
ружения столкновений; две выполняются часто, а одна - редко. В нашем сцена-
рии первые две функции проверяют столкновения между кораблем игрока и фло-
том захватчиков, а также между лазером игрока и флотом захватчиков. Если
вторая проверка дает положительный результат, выполняется более редкая (но
более детализированная) проверка столкновений между лазером и каждым вра-
жеским кораблем внутри флота.

ТРЮК Поворот к заданной точке


№41 Во многих играх и имитациях требуется повернуть графический объект,
представляющий игрока, к заданной точке. Используйте угловое пере-
мещение для разворота спрайтов в нужном направлении.
Компьютерная графика во многом отличается от реальной жизни. Графические
объекты могут двигаться в произвольном направлении, тогда как в реальной
жизни объект обычно сначала поворачивается в некотором направлении и толь-
ко потом двигается. Более того, если реальный объект уже двигается, он не мо-
жет мгновенно сменить направление. Из-за инерции поворот в новом направле-
нии требует некоторого времени, поэтому объект двигается по криволинейной
траектории, пока не будет ориентирован в нужном направлении.
Повысить реализм движения компьютерных объектов можно несколькими спо-
собами:
• придайте графическому объекту такой вид, как будто он всегда ориентирован
в правильном направлении (например, используйте шар, обладающий свой-
ством радиальной симметрии, или «летающую тарелку», которая может дви-
гаться в любом направлении без разворотов);
• постоянно перемещайте целевую точку, к которой стремится ваш анимиро-
ванный клип. Если точка движется по сложному закону, зрителю покажется,
что клип тоже движется по аналогичным правилам. Приложение проектиру-
ется таким образом, что сам код не обладает особой сложностью или разум-
ным поведением. В большинстве видеоигр противники преследуют персона-
жа, представляющего игрока. Поскольку игрок (будем надеяться!) двигается
разумно, перемещения противников тоже выглядят разумно;
• создайте графический объект, обладающий четко выраженной ориентацией,
но поворачивайте его способом, который бы приближенно соответствовал
физической модели. В реальной жизни скорость, с которой объект может
повернуться без заноса или опрокидывания, зависит от целого ряда факто-
Поворот к заданной точке 199

ров - скорости, трения, массы и положения центра тяжести, рельефа и т. д.


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

Преследование движущейся цели


Следующий фрагмент постоянно наводит клип на заданную точку (в данном
случае - в текущей позиции указателя мыши):
// Создание клипа ball
this.createEmptyMovieClip<"ball", 0);
ball.lineStyle(50. 0x0. 100);
ball.moveTo(0. 0);
ball.lineToCO. 1):
// Анимация ball для преследования указателя мыши
ball .onEnterFrame = function О {
this._x -= (ball._x - _xmouse) / 4;
this._y -= (ball._y - _emouse) / 4;
}:
Программа создает универсального «преследователя» с эффектом инерции (раз-
ность координат делится на 4, чтобы избежать мгновенного перемещения шара
в текущую позицию указателя мыши). Шар перемещается к последней позиции
мыши по прямой линии (или серии отрезков, если цель передвигается). Анимация
основана на упоминавшемся ранее свойстве радиальной симметрии шара (пос-
леднее означает, что шар не имеет четко выраженного направления).
Мы рассмотрели минимальный код для создания реалистичного эффекта дви-
жения, который на первый взгляд решает проблемы изменения направления
и ориентации (хотя на самом деле не делает ни того, ни другого).
Этот простой трюк молено расширить и изменять ориентацию движущегося объек-
та не моделированием поворота, а простым переключением между несколькими
готовыми изображениями или анимационными последовательностями. Напри-
мер, если персонаж двил<ется в трехмерном мире, следует заготовить разные
варианты анимации для каждого возможного направления (см. трюк 28).

Разворот к точке
Представьте, что корабль должен развернуться к цели перед выстрелом (пред-
полагается, что орулше всегда стреляет в текущем направлении). Следующий
код рисует отрезок прямой и разворачивает его в направлении текущей позиции
указателя мыши:
// Создание анимационного клипа tracker
var tracker:MovieClip = this.createEmptyMovieClipC'tracker". 0):
// Рисование линии в клипе tracker
tracker.lineStyle(0. 0x0. 100):
tracker.moveTo(0. 0):
tracker.lineTodOO. 0):
tracker, x = Stage.width / 2:
200 Глава 5. Трехмерная графика и физика

tracker._y = Stage.height / 2:
// Определение множителя для преобразования радианов в градусы
// var RAD_DE6:Number = 180/Math.PI:
tracker.onMouseMove = functionО {
// Поворот клипа в направлении указателя мыши
var angle:Number = Math.atan2(_ymouse - this._y. _xmouse - t h i s . _ x ) :
t h i s . _ r o t a t i o n = angle * RAD_DEG;
updateAfterEventO:
}:
Метод Math.atan2(), использованный в этом фрагменте, возвращает угол, на ко-
торый нужно повернуть линию, чтобы она была обращена к точке, заданной
координатами X и Y (обратите внимание: в первом параметре передается рассто-
яние У, а не X). Геометрическая интерпретация представлена на рис. 5.17.

target

s t a r t position
Рис. 5.17

Все тригонометрические функции Flash возвращают углы в радианах, поэтому


результат нужно преобразовать в градусы - единицы, используемые свойством
MovieClip._rotation.
Приведенный ранее код мгновенно разворачивает клип к текущей позиции ука-
зателя мыши. Чтобы замедлить поворот, достаточно ограничить скорость в об-
работчике события onMouseMove (в следующем примере скорость ограничива-
ется приращениями ±5°):
tracker.onMouseMove = functionO {
// Поворот клипа в направлении указателя мыши
var targetAngle:Number = Math.atan2(_ymouse - this._y. _xmouse - t h i s . _ x ) ;
var errorAngle:Number = targetAngle * RAD_DEG - t h i s . _ r o t a t i o n ;
i f (Math.abs(errorAngle) > 5) {
i f ( ((errorAngle > 0) && (errorAngle < 180))
|| (errorAngle < -180) ) {
t h i s . _ r o t a t i o n += 5:
} else {
t h i s . r o t a t i o n -= 5;
Поворот к заданной точке 201

Многоуровневая команда if в этом фрагменте проверяет переменную errorAngle,


потому что значения свойства _rotation лежат в интервале от -180° до +180°, а не
от 0 до 360°. Если увеличивать свойство _rotation на 1 для каждого кадра, то
в процессе полного оборота оно будет изменяться следующим образом:
1. 2. 3 179. 180. -179. -178 -2. -1. О
Таким образом, команда if заставляет клип tracker поворачиваться к нужному
направлению по кратчайшей дуге. Иначе говоря, если клип направлен на ^ ч а -
сов, и его нужно развернуть на 9 часов, то поворот будет выполняться на 90°
против часовой стрелки, а не на 270° по часовой.

Инерция
Допустим, мы хотим имитировать эффект инерции, чтобы клип двигался к точ-
ке назначения по дуге. Для этого следует добавить перемещение в том направле-
нии, куда клип направлен в каждый момент времени. Опробуйте следующее
решение:
function drawBlip(clip) {
// Рисование линии в клипе
clip.lineStyleCO. 0x0. 100);
clip.moveTo(0. 0):
clip.lineTodO. 0):
clip._x = Math.randomO * Stage.width:
clip._y = Math.randomO * Stage.height:
}
function real MoveО {
// Вычисление расстояния между текущей позицией клипа
// и целевой позицией (указателем мыши).
this.xDist = _xmouse-this._x;
this.yDist = _ymouse-this._y;
// Вычисление угла между текущей и целевой позициями клипа.
// а также разности между желаемым направлением
// и текущим углом (errorAngle).
var targetAngle:Number = Math.atan2(this.yDist. this.xDist):
var errorAngle:Number = targetAngle * RAD_DEG - this._rotation:
// Вычисление угла .поворота по значению errorAngle.
if (Math.abs(errorAngle) > 10) {
if ( ((errorAngle > 0) && (errorAngle < 180))
j | (errorAngle < -180) ) {
this._rotation += 10:
} else {
this.rotation -= 10:

// Перемещение клипа с учетом текущего угла.


this._x += Math.cos(this._rotation / RAD_DEG) * 20:
this._y += Math.sin(this._rotation / RAD_DEG) * 20:
}
202 Глава 5. Трехмерная графика и физика

// Определение множителя для преобразования радианов в градусы


// var RAD_DEG:Number - 180/Math.PI:
// Создание клипов tracker
for (var i:Number = 0; i < 100; i++) {
var tracker:MovieClip = this.createEmptyMovieClip("tracker" + i . i ) :
drawBlip(tracker);
tracker.onEnterFrame = realMove;
}
При перемещении указателя мыши движение выглядит почти естественным, как
движение стаи живых существ.
Если создать только один клип tracker, получится что-то вроде самонаводящейся
ракеты - особенно если добавить постепенно растворяющуюся реактивную струю
в направлении, обратном направлению перемещения.

Итоги
Существует немало приемов имитации реального движения. Разворот к целевой
точке и имитация инерции в направлении движения закладывают основу для
создания анимаций с реалистичным движением.
ГЛАВА 6

Текст
Трюки № 42-51
Средства работы с текстом в Flash не ограничиваются выводом статических
сообщений, единственный смысл которых - оставаться на своем месте и быть
прочитанными пользователем. Flash позволяет интерпретировать текст как на-
бор векторных фигур или серию анимационных клипов; оба варианта обладают
тем преимуществом, что они позволяют анимировать текст. Достаточно взгля-
нуть на титры некоторых фильмов, чтобы понять, насколько выразительным
может быть анимированный текст и до какой степени движение может спо-
собствовать передаче смысловой нагрузки. Более того, появляющиеся и исчеза-
ющие текстовые сообщения иногда используются для создания подтекста (по
аналогии с тем, как жестикуляция создает подтекст для произносимых слов).
Далее перечислены некоторые сайты Flash, демонстрирующие возможности ра-
боты с текстом:
• Typorganism (http://www.typorganism.com) - сайт демонстрирует так называе-
мое кинетическое оформление, то есть эффекты анимации текста, вносящие
дополнительный смысл посредством движения.
• Overage4Design (http://www.overage4design.com) - современный дизайн, в ко-
тором текст интерпретируется как графический объект, а не как нечто предназ-
наченное для простого чтения.
• Mono-craft (http://www.yugop.com) Юго Ыакамуры (Yugo Nakamura) - один
из первых сайтов с новаторскими и интерактивными возможностями работы
с текстом. Mono-craft версии 2.0 считался одним из законодателей моды «зо-
лотого века» Flash 4 и 5, когда первая волна Flash-дизайнеров на базе совре-
менной методики ActionScript создавала концепции, которые в наше время
считаются стандартными.
• Saul Bass on the Web (http://www.saulbass.net) - сайт поддерживается хорошо
известным Flash-дизайнером Бренданом Доусом (Brendan Dawes). Он отдает
дань уважения Солу Бассу (1920-1966) - одному из первых людей, исполь-
зовавших текст как динамическую графику в фильме. Басе также применял
текст для графического оформления плакатов к фильмам, как это делали его
предшественники-модернисты из Советской России в 1920-х годах.
204 Глава 6. Текст

Flash превосходит стандартный HTML в области работы с текстом не только


возможностью анимации, но и более широкими средствами настройки. В част-
ности, при работе с векторным текстом Flash поддерживаются следующие воз-
можности:
• отображение текста под любым углом и любого размера;
• рисование дополнительных знаков и использование сглаживания для всех
шрифтов;
• использование любых шрифтов, в том числе и не установленных на компью-
тере пользователя (для этого в SWF-файл включается контурное описание
шрифта);
• возможность разбиения знаков и их модификации внутри текста (команда
Modify • Break Apart) для быстрого создания логотипов и других изображений
на текстовой основе. Вы даже можете использовать морфинг для преобразо-
вания одних символов в другие;
• поддержка традиционного форматирования CSS и текста HTML (см. трюк 46)
даже в том случае, если содержание отображается вне браузера (например,
в автономном Flash Player или при экспортирований данных Flash в испол-
няемый файл).

Шрифты
Flash поддерживает две категории шрифтов: системные и встраиваемые. При
использовании одного из трех стандартных шрифтов («_jsans», «_serif» или
«.typewriter») Flash Player на стадии выполнения подбирает наиболее похожий
шрифт в системе пользователя. Шрифт «_sans» (эквивалент sans-serif в HTML/
CSS) обычно соответствует Arial в системе Windows или Helvetica на Мае. Вме-
сто шрифтов «serif» и «^typewriter» (эквиваленты serif и mono в HTML/CSS)
Flash обычно использует Times или Courier или другие подходящие шрифты.
Контурное описание шрифта может быть сохранено в SWF-файле для выполне-
ния различных текстовых эффектов (см. трюк 48) - скажем, поворота текста.
Встраивать стандартные шрифты в SWF не обязательно, но системные шрифты
не содержат векторной информации, поэтому Flash не может интерпретировать
текст, выведенный с применением системного шрифта, как графический объект.
Из-за этого текст, оформленный системным шрифтом, обычно исчезает со сце-
ны при повороте или масштабировании клипа. При встраивании стандартных
шрифтов («_sans», «_serif» или «_typewriter») Flash использует ближайший
шрифт, обнаруженный в системе на стадии компиляции. На стадии выполнения
такой текст успешно поворачивается, масштабируется и анимируется, посколь-
ку Flash использует встроенное описание шрифта, а не системный шрифт, нахо-
дящийся на компьютере пользователя.
Трюки, представленные в этой главе, помогут сделать текст более разборчивым,
реализовать текстовые поля с автоматическим заполнением, импортировать текст
со сложным форматированием, использовать CSS, а также применять такие спе-
цифические возможности, как всплывающие подсказки. В других главах ветре-
Сохранение разборчивости текста 205

чаются и другие трюки, применяемые при работе с текстом, - например, созда-


ние переходов с использованием текста и масок (см. трюк 2).

ТРЮК Сохранение разборчивости текста


№42 Удобочитаемость текста зависит от шрифта, размеров кегля и текущих
размеров экрана. Оперативное измерение параметров шрифта позволит
нормально читать текст сайта на экранах разных размеров.
На сайтах Flash обычно используются мелкая графика и текст. Что же, выглядит
эффектно - если не считать того, что текст, нормально читающийся на одном
компьютере, может оказаться неразборчивым на другом. Например, текст разме-
ром 8 пунктов может стать нечитаемым на Macintosh iBook. С другой стороны,
текст, который нормально смотрится на мониторе с разрешением 1024 х 768,
становится нечитаемым разрешении 1600 х 1200 (пикселы становятся меньше
при более высоких разрешениях). А если сайт проектировался для рабочего сто-
ла 1600 х 1200, то на мониторе с разрешением 800 х 600 текст будет выглядеть
непропорционально большим. В принципе, можно создать несколько версий сайта
для разных разрешений, но существует более разумный путь - определить раз-
мер экрана пользователя и оперативно изменить текстовые метрики Flash в со-
ответствии с размерами сцены.

Определение размеров экрана


Процедура определения разрешения экрана пользователя сводится к простому
запросу свойств System.capabilities. Следующий фрагмент выводит разрешение
экрана:
trace(System.capabiIities.screenResolutionX):
trace(System.capabilities.screenResolutionY);
На моем компьютере этот фрагмент выводит числа 1600 и 1200 - как и следова-
ло ожидать, на рабочем столе выставлено разрешение экрана 1600 х 1200. Так
что же можно сделать с этими числами? Например, изменить размер выводимо-
го текста. Но сначала нужно создать сам текст.
Следующий код (файл varyText.fla на сайте книги) динамически создает тексто-
вое поле с небольшим сообщением.
1 var txtFmt: Text Format = new TextFormatO ;
2 var myStr:String = "Hello and welcome to Flash Hacks. " +
3 "by Sham Bhangal and a host of co-contributors":
4 // Выбор шрифта и кегля
5 txtFmt.font = "_sans":
6 txtFmt.size = 12;
7 var metrics:Object = txtFmt.getTextExtentCmyStr. 200):
8 // Добавление текстового поля
9 this.createTextField("my_txt", 1, 100. 100.
10 metrics.textFieldWidth. metrics.textFieldHeight):
11 my_txt.wordwrap - true;
206 Глава 6. Текст

12 my_txt.border = true;
13 my_txt.text r myStr:
14 my_txt.setTextFormat(txtFmt):
Строки 1 и 2 создают экземпляр TextFormat с именем txtFmt, используемый для
отображения текста myStr. В строке 4 выбирается шрифт «_sans» - один из трех
стандартных шрифтов, поддерживаемых Flash.
Затем в строке 7 метод TextFormat.getTextExtent() создает элемент Object с именем
metrics. Метод возвращает объект с двумя свойствами, textFieldWidth и textFieldHeight,
определяющими ширину и высоту текстового поля, необходимого для отображе-
ния сообщения myStr с разрывом текста после 200 пикселов.
Вторая часть приведенного кода динамически строит текстовое поле my_txt с глу-
биной 1 и позицией (100, 100); ширина и высота поля определяются значениями
упоминавшихся ранее двух свойств metrics.
Последние четыре строки просто задают свойства текстового поля после его
создания. В частности, они заносят в него наш текст myStr и применяют к полю
объект TextFormat с именем txtFmt, определяющий шрифт и его кегль.
Особенно важна строка 6:
txtFmt.size = 12:
Если присвоить txtFmt.size любое другое значение (и применить его вызовом
setTextFormatO), текст будет отображаться другого кегля, а высота текстового
поля автоматически подгоняется под высоту текста, как показано на рис. 6.1,
для значений txtFmt.size, равных 8, 12 и 16 соответственно.

Hello and welcome to Flash Hacks,


by Sham Bhangal and a host of co-
contributors

Hello and welcome to Flash


Hacks, by Sham Bhangal
and a host of co-contributors
Рис. 6 . 1 . Автоматическое масштабирование текстового
поля для трех вариантов кегля

Вероятно, вы уже уловили, к чему я клоню: если задавать свойство size в зависи-
мости от разрешения экрана пользователя, проблему удобочитаемости текста
можно считать решенной. Попробуйте заменить строку 6 следующим фрагмен-
том:
i f (System.capabi1iti es.screenResol uti onX 800) {
txtFmt.size = 12:
} else {
txtFmt.size = 10:
Автоматическое завершение текста 207

Обратите внимание: проверять размеры обеих сторон не обязательно. Как правило,


для получения информации о разрешении достаточно проверить только одну сто-
рону, поскольку экраны мониторов обычно имеют форматное соотношение 4 : 3.
У некоторых дизайнеров может возникнуть неприятная мысль: «Все это, конеч-
но, хорошо, но не отразится ли изменение размера шрифта на моем тщательно
спроектированном макете сайта?» Отразится, но обычно изменения ограничи-
ваются очень небольшими значениями (±2 пункта, как в рассмотренном приме-
ре), не приводящими к радикальному изменению структуры сайта. В крайнем
случае можно использовать текстовые поля фиксированного размера и снабдить
их полосами прокрутки для больших текстовых сообщений или уменьшить рас-
стояние между строками при увеличении размера текста (мелкий текст обычно
разделяется более широкими межстрочными интервалами, чем крупный).

Итоги
Необходимость поддержки разных размеров экранов (для мобильных телефо-
нов, карманных компьютеров и других нестандартных устройств) становится
все более насущной, поэтому требования к удобочитаемости текста выходят на
первый план. Тривиальное решение проблемы - создать разные версии для всех
основных категорий устройств, но таких категорий немало (причем даже уст-
ройства одной категории могут различаться). Лучше реализовать возможность
динамического управления текстовыми метриками.
Также существует возможность динамического изменения размеров сцены Flash
и/или находящихся на ней текстовых экземпляров в соответствии с разрешени-
ем экрана (и размером окна браузера). Зная соотношение между размером сцены
Flash и общими размерами экрана, вы получаете дополнительные возможности
для динамического масштабирования содержания Flash. Реализация динамичес-
кого изменения текстовых метрик и размеров сцены (см. трюк 92) позволит вам
в значительной степени контролировать адаптацию SWF к разным условиям
времени выполнения.
Другое полезное применение кода, приведенного в настоящем трюке, - созда-
ние всплывающих подсказок. Код для оперативного создания легко перемещае-
мого и масштабируемого текста легко адаптируется для создания текста справ-
ки (см. трюк 47), который всегда масштабируется и позиционируется возле
указателя мыши, но внутри сцены.
Иногда при изменении размеров текста бывает желательно сменить шрифт. На-
пример, чтобы текст хорошо читался при малых размерах, следует использовать
пиксельные шрифты (см. трюк 67).

ТРЮК Автоматическое завершение текста


№43 Автоматическое завершение ускоряет ввод данных на экранных формах.

Большинство из нас предпочитает вводить ровно столько текста, сколько абсолют-


но необходимо. А для некоторых категорий пользователей (детей, пользователей
208 ; Глава 6. Текст

с ограниченной дееспособностью, владельцев мобильных устройств с неудобны-


ми клавиатурами и т. д.) экономия нажатия клавиш является делом первооче-
редной важности. Один из способов экономии времени основан на автоматичес-
ком завершении часто используемых слов до того, как пользователь завершит
их ввод (данная функция называется автоматическим завершением).
На страницах http://www.zingman.com/commonWords.html и http://alt-usage-english.org/
excerpts/xcommon.html приводятся списки 300 слов, чаще всего используемых
в письменном английском языке. Другие аналогичные списки можно найти в спе-
циализированной литературе.
При первом знакомстве с этими ресурсами у меня сразу возникла мысль: «Хмм...
Неплохое начало для реализации автоматического заполнения». На рис. 6.2 по-
казан результат удаления всех слов, состоящих из двух и менее букв (для кото-
рых автоматическое заполнение не дает сколько-нибудь существенной эконо-
мии времени), и сортировки полученного списка по алфавиту.

called с*ие can chance children city ccae oeoi could cstuitry d&y d»Y» SiS oiCferenc doea dcr.'t dour, during

Рис. 6.2. Самые распространенные слова в письменном английском языке,


содержащие не менее трех букв

Если вы предпочитаете извлечь слова из другого списка, приведу код, который


я использовал:
function textLoader(data) {
// Разбиение текстового файла по пробелам
dictionary = data.splitC " ) :
// Сортировка списка
doctionary.sortO;
// Вывод отсортированного списка, разделенного пробелами.
trace(dictionary.join(""));
}
var myText:LoadVars = new LoadVarsO:
var dictionary:Array - new ArrayO:
myText.1oad("commonWords.txt"):
myText.onData = textLoader;
Предполагается, что слова хранятся в файле commonWords.txt и разделяются
пробелами. Измените имя файла и разделитель (например, символ новой стро-
ки) в соответствии с тем списком, который имеется у вас.
Автоматическое завершение текста 209

Мой усеченный список слов занимает всего лишь 1,5 Кбайт, причем его можно
усечь до 990 байт (большая выгода!) копированием выходных данных предыду-
щего сценария в листинг ActionScript. Как вы вскоре убедитесь, полная версия
выглядит не так компактно:
var myText:String = "about above across ... years you young your";
var dictionary:Array = new ArrayO;
dictionary = myText.splitC " ) ;
dictionary. sortO;
delete (myText);
При публикации SWF Flash сжимает текст определения словаря.
На сайте http://www.the-stickman.com я обнаружил весьма изобретательный трюк
для реализации автоматического завершения.
В нем используются два текстовых поля, одно над другим. Верхнее поле пред-
назначено для ввода данных, а нижнее, динамическое поле содержит рекоменда-
ции для автоматического завершения. Допустим, у вас уже имеется слой с име-
нем actions, с первым кадром которого связан предыдущий фрагмент кода.
Добавьте два новых слоя с именами entered text и completed text (см. рис. 6.3).

« 3 D
illllQ
;
entered text * • 5
Ij? complete text:: . . •• i
Рис. 6.З. Создание слоев для реализации автоматического завершения текста

На слое entered text создайте многострочное текстовое поле без бордюра и при-
свойте ему имя myText_txt (см. рис. 6.4).

ты s.ens
А !V| ! M ;|vl И|;

iiifcl;^
:

ж rayText_txt * | Normal

309 0 х:
67. 3 ш |Ми1Шпе v| ;
| <> D Var:

И: 170.8 у;
.|
1183
Рис. 6.4. Настройка параметров текстового поля для слоя entered text

Теперь скопируйте текстовое поле, заблокируйте слой entered text и вставьте


текстовое поле на слой completed text (клавиши Ctrl+Shift+V в системе Windows
или <HS+Shift+V на Мае). На панели свойств преобразуйте текстовое поле в ди-
намическое, назначьте ему бордюр и выберите цвет текста, отличающийся от
цвета текста исходного поля (этим цветом будет выделяться автоматически
210 Глава 6. Текст

завершаемая часть). Задайте новому экземпляру имя complete_txt на панели


свойств, как показано на рис. 6.5.

;:
:•• i Dynamic Text v ' .A _sans vl 14 V
A b £ ;|
completejxt
jj 309.0 Ш67.0 |!;1А|,::|Ми1Шпе v ; A0 <Ь П Van
:
Hti 1*3.3 Щ 118.3

Рис. 6.5. Изменение свойств текстового поля на панели свойств

Программа
Введите в сценарии, связанном со слоем actions, следующий фрагмент, содержа-
щий как программный код, так и предварительно инициализированный словарь:
function autoCompleteO {
// Функция подтверждает текущий предложенный вариант
// автоматического завершения при нажатой клавише CONTROL,
if(Key.isDown(Key.CONTROL)){
myText_txt.text = complete_txt.text + " ";
Selecti on.setSelecti on(myText_txt.text. 1 ength,
myText_txt.text.length):

function fieldChangeO {
// Функция для поиска и отоображения варианта
// автоматического завершения строки,
match = "":
// Получение последнего незавершенного слова в текстовом поле
startOfWord = this.text.lastlndexOf(" ") + 1:
lastWord = this. text. substring(startOfWord, this.text .'length);
// Поиск в словаре кандидатов для последнего незавершенного слова,
if(lastWord.length > 1){
for (var i = 0; i < dictionary.length; i++) {
if (lastWord == (dictionary[i].substr(0. lastWord.length))){
// Если совпадение обнаружено, сохранить в переменной match.
match = dicti onary[i];
search = i;
break;

} else {
search = 0;
Автоматическое завершение текста 211

// Отображение текущего совпадения в автоматически завершаемом


// текстовом поле.
complete_txt.text = this.text.substrCO. startOfWord) + match;

// Инициализация

var myText:String = "about above across after again against air all almost
along also always and animals another answer any are around asked away
back because been before began being below best better between big both
boy boys but bye called came can change children city come cool could
country day days did different does don't down during each earth email end
enough even ever every example eyes far father feet few find f i r s t five
following food for form found four from get give going good goodbye got
great had hand hard has have head hear heard hello help her here high him
himself his home house how however html important into i t ' s its just keep
kind knew know land large last learn left let l i f e light like line l i t t l e .•
live long look looked made make man many may means men might miles more
most mother much must name near need never new next night no not now
number off often old once one only other others our out over own page
paper part parts people picture place play point put read right room said
same saw say school sea second see sentence set several she should show
side since small some something sometimes soon sound s t i l l story study
such sun sure take t e l l than that the their them then there these they
thing things think this those thought three through time times today
together told too took top toward try turned two under until use used
using usually very want was water way ways web website well went were what
when where which while white who whole why will with without word words
work work world would write year years you young your";

var dictionary:Array = new ArrayO;


var search:Number = 0;
var lastWord:String = "":
var startOfWord:String = "";
var control:Object = new ObjectO;
// Построение словаря
dictionary = myText.splitC " ) ;
dictionary. sprtO:
// Настройка событий и слушателей
myText_txt.onChanged = fieldChange;
control.onKeyDown = autoComplete;
Key.addLi stener(control);
Основное место в этом сценарии занимает функция fieldChange(), выполняемая
каждый раз, когда пользователь изменяет содержимое текстового поля.
Сначала функция очищает содержимое переменной match, содержащей текущий
вариант автоматического завершения. Затем она получает все символы послед-
него слова, введенного пользователем; для этого мы находим последнее вхожде-
ние пробела и берем текст от следующего знака до конца текста.
Например, в предложении «The cat sat» последний пробел находится перед
группой «sat» (а его индекс равен 7, если начать отсчет с 0). Увеличение индекса
на 1 дает позицию первого символа слова «sat». Используя эту информацию
212 Глава 6. Текст

(startOfWord), мы извлекаем подстроку «sat» из предложения. Последняя буква


«sat» соответствует концу нашего предложения на данный момент. Для удоб-
ства далее приводится соответствующий фрагмент листинга:
function fieldChangeO {
match = "";
startOfWord = this.text.lastlndexOfC" ") + 1;
lastWord = this.text.substring(startOfWord. this.text.length);
Автоматическое завершение имеет смысл лишь в том случае, если текущее слр-
во содержит не менее двух букв, поэтому команда if в следующем фрагменте
отменяет проверку, если в текущем слове был введен только один символ. Если
же пользователь ввел минимум два символа, цикл for сравнивает слово с каж-
дым элементом словаря до тех пор, пока не найдет совпадение.
Переменная search оптимизирует будущие операции поиска. Известно, что сло-
варь отсортирован по алфавиту, поэтому любые будущие возможные совпаде-
ния этого слова будут находиться после текущей найденной позиции словаря.
Следовательно, запоминая позицию текущего слова, мы сможем в следующий
раз возобновить поиск с той же позиции:
if(lastWord.length > 1){
-for (var i = 0: i < dictionary.length; i++) {
i f (lastWord == (dictionary[i].substr(0. lastWord.length))){
// Совпадение обнаружено
match - dictionary[i]:
search = i ;
break;

Наконец, если попытка поиска еще не предпринималась, потому что текущее


слово было слишком коротким, сохраненная позиция search сбрасывается -
когда слово будет иметь достаточную длину, поиск следует начать от начала
словаря:
} else {
search = 0:
}
Программа написана так, чтобы пользователь мог подтвердить предложенный
вариант завершения слова нажатием клавиши Ctrl (другие способы рассматрива-
ются далее). Когда пользователь нажимает клавишу Ctrl, в результате прослу-
шивания событий вызывается функция autoComplete(), которая передает теку-
щий вариант автоматического завершения в поле ввода, фактически, завершая
слово за пользователя:
function autoCompleteO {
i f(Key.i sDown(Key.CONTROL)){
myText_txt.text - complete_txt.text + " ";
Sel ecti on. setSel ecti on(myText_txt. text. 1 ength.
myText_txt.text.1ength);
Автоматическое завершение текста 213

Последняя команда в приведенном фрагменте перемещает курсор в конец текущей


строки. Для перемещения в конец содержимого текстового поля используется
фокус с выделением нулевой длины.
На рис. 6.6 представлен механизм автоматического завершения в действии. Если
ввести фразу «Не sa», вам будет предложен вариант завершения «Не said». На-
жмите клавишу Ctrl, чтобы занести предложенный текст в текущее поле ввода.
При желании добавьте статическую справку, в которой бы сообщалось, что кла-
виша Ctrl инициирует автоматическое завершение.

Не s| Не за|н Не said

Рис. 6.6. Автоматическое завершение в действии

Итоги
В этом разделе приведен базовый код, необходимый для реализации автомати-
ческого завершения. Скорее всего, вы захотите его изменить - например, чтобы
автоматическое завершение подтверждалось другой клавишей (скажем, пробелом).
Но в этом случае придется приложить дополнительные усилия. Хотя нажатие
пробела можно обнаружить простым поиском « » в конце текущего содержимо-
го поля, нужно убедиться в том, что последней нажатой клавишей была не кла-
виша Backspace. Другой потенциальный недостаток заключается в том, что при
нажатии пробела для перехода к другому слову механизм автоматического за-
вершения может добавить нежелательный текст. Например, если ввести слово
«table» и нажать пробел, это слово может неожиданно замениться словом «tablecloth».
Впрочем, это маловероятно, потому что часто встречающиеся слова из списка
обычно имеют небольшую длину.
Другое обстоятельство, способное вызвать раздражение у некоторых пользова-
телей, - добавление пробела в конец каждого автоматически завершаемого сло-
ва. Впрочем, это все мелочи - даже если изменить подробности реализации,
основной принцип остается прежним.
Базовый словарь из часто встречающихся слов также может стать отправной
точкой при построении более полезного списка. Когда речь заходит о «включе-
нии словаря», может показаться, что это приведет к заметному увеличению объема
SWF-файла, однако 300 самых распространенных слов занимают менее 1 Кбайт.
Расширение списка до 3000 слов (что приближается к количеству слов, исполь-
зуемых в нормальной речи, если не считать имена собственные и служебные
частицы) потребует не более 10-15 Кбайт! Получается не так уж много, и это
обстоятельство позволит нам создать словарный запас для синтезатора речи
(см. трюк 52), чтобы он мог читать простой текст. Синтезатор выводит неопоз-
нанные слова, которые вы можете добавлять в словарь (см. трюк 44) по своему
усмотрению.
214 Глава 6. Текст

Далее перечислены некоторые из возможных усовершенствований.


• Сделайте так, чтобы автоматическое завершение выполнялось по нажатию
клавиши Return/Enter.
• Предотвратите возможный переход к скрытому полю, задав свойство tablndex
для поля myText_txt, но не для complete_txt.
• Реализуйте дополнительную логику, чтобы автоматическое завершение ра-
ботало даже в том случае, если пользователь щелкнет в середине заполненно-
го текстового поля.
• Решите проблемы с переносом и прокруткой, возникающие при работе с длин-
ным текстом.
• Ускорьте поиск слов, чтобы программа могла использовать более длинные
словари без ухудшения быстродействия. Например, словарь можно разбить
на массивы, хранящиеся в хеш-таблице, ключом которой являются первые
два символа.
Идею трюка подсказал Stickman

Динамическое построение списка


вводимых слов
Накопление списка слов для поиска, индексирования и автоматического
завершения и его сохранение в локальном файле.
Ранее было показано, как организовать автоматическое завершение текста (см.
трюк 43) по заранее построенному списку слов, то есть по ограниченному словарю.
Такой подход хорошо работает для часто встречающихся слов, но на практике
понятие «часто встречающийся» изменяется в зависимости от ситуации. Напри-
мер, 300 или 3000 самых распространенных слов в разговоре специалистов по
компьютерам будут отличаться от того лее количества слов в обычном разговоре.
Автоматическое завершение текстовых полей чаще всего применяется при за-
полнении экранных форм. Как правило, такие формы заполняются нестандарт-
ными словами, специфическими для конкретного пользователя (скажем, его имя,
название улицы и города и т. д.).
В этом трюке показано, как реализовать динамическое построение списка слов.

Добавление новых слов в список


В нашем примере поиск новых слов для включения в список будет производиться
только после того, как пользователь завершит ввод текущих данных. На форме это
происходит в тот момент, когда пользователь отправляет данные кнопкой Submit.
В обработчике onReiease кнопки Submit мы ищем текст, введенный в текстовом
поле (или полях), и включаем в словарь те слова, которые не были включены
в него ранее.
Динамическое построение списка вводимых слов 215

Программа
Следующий код решает задачу поиска новых слов и их включения в список
(предполагается, что код из трюка 43 также присутствует, а обработчик события
onRelease вызывает функцию entered()).
1 function entered О {
2 var newWords:Array = new ArrayO;
3 newWords = myText_txt.text.split(" " ) ;
4 for (var i = 0; i<newWords.length; i++) {
5 if (myText.indexOf(newWords[i].toString()) == -1) {
6 // Новое слово отсутствует в словаре.
7 // Добавить его и отсортировать словарь заново.
8 myText += " "+newWords[i];
9 dictionary.push(newWords[i]):
10 dictionary.sort О:
11 }
12 }
В строках 2 и 3 функции создается новый массив newWords, содержащий все
слова из текстового поля myText_txt. Если форма содержит несколько текстовых
полей, просто объедините их в одну строку конструкцией следующего вида (вме-
сто строки 3 предыдущего листинга):
newWords = (myTextFieldl_txt.text + " " +
myTextField2_txt.text).split(" ");
В теле цикла for (строки 4-11) программа последовательно ищет в словаре каж-
дое слово в текстовом поле (конечно, можно ограничиться словами, состоящими
из трех и более букв). Если новое слово не найдено, оно включается в словарь,
после чего словарь заново сортируется.
Хотя в этом коде содержимое строки myText используется для быстрого поиска
(см. трюк 79), новые слова сохраняются в массиве dictionary (см. трюк 43). В этом
можно наглядно убедиться: запустите ролик в отладочном режиме (Control •
Debug Movie) и просмотрите содержимое массива root.dictionary при вводе слова
«aardvark». Если щелкнуть на кнопке Submit, вы увидите, что элемент dictionary[0]
теперь содержит слово «aardvark». Нажимайте клавишу Backspace до тех пор,
пока слово «aardvark» не будет полностью стерто, и начните вводить его заново.
После ввода символов «аа» Flash автоматически завершает слово.

Сохранение словаря для последующего


использования
Конечно, хранить слова в переменных Flash удобно, но закрытие формы приве-
дет к потере всех накопленных слов. Словарь следует хранить не во временной
переменной, а на жестком диске пользователя. Простейшее решение - сохра-
нить переменную myText с полным словарем (как со стандартными, так и с но-
выми словами).
216 Глава 6. Текст

В следующем листинге приведен код поиска новых слов и их сохранения в ло-


кальном файле (изменения по отношению к предыдущим версиям выделены
жирным шрифтом):
function entered О {
var newWords:Array = new ArrayO;
var needUpdate:Boolean = false;
newWords = myText_txt.text.split(" " ) :
for (var i = 0; i<newWords.length: i++) {
i f (myText.indexOf(newWords[i].toString()) == -1) {
// Новое слово отсутствует в словаре.
// Добавить его и отсортировать словарь заново.
myText += " "+newWords[ij;
dictionary.push(newWords[i]);
dictionary.sort О:
needUpdate • true;

}
if (needUpdate) {
saveDictionaryO;
>
function saveDictionaryO {
var shared:SharedObject = SharedObject.getLocal("dictionary")
shared.data.dictionary = myText;
shared. flushO;
}
function loadDictionaryO {
var shared:SharedObject = SharedObject.getLocal("dictionary")
if (shared.data.dictionary != undefined) {
myText = shared.data.dictionary;
}
function enterEventO {
enteredO;
// Прочая обработка кнопки Submit...
}
function autoCompleteO {
if (Key.isDown(Key.CONTROL)) {
myText_txt.text = complete_txt.text+" ";
Sel ect i on.setSelecti on(myText_txt.text.1ength,
myText_txt.text.1ength):
}
function fieldChangeO {
match = "";
startOfWord = this.text.lastlndexOfC ")+l;
lastWord = this.text.substring(startOfWord. this.text.length):
i f (lastWord.length>l) {
for (var i = 0: idictionary.length: i++) {
i f (lastWord == (dictionary[i].substr(0. lastWord.length)))
// Совпадение обнаружено
match = dictionary[i]:
Динамическое построение списка вводимых слов 217

search = i ;
break;

}
} else {
search = 0:
}
complete_txt.text - this.text.subs-tr(0. startOfWord)+match;
}
// Инициализация
// Полный список слов не приводится
var myText:String = "about above... you young your";
var dictionary:Array = new ArrayO;
var search:Number = 0:
var lastWord:String = "";
var startOfWord:String = "":
var control:Object = new ObjectO:
// Загрузка хранимого словаря
loadDictionaryO;
// Построение словаря
dictionary - myText.spiit(" ");
dictionary. sortO;
// Настройка событий и слушателей
myText_txt.onChanged = fieldChange:
control.onKeyDown = autoComplete;
Key.addLi stener(control):
enter_btn.onRelease = enterEvent;
В третьей строке обновленной функции enteredO определяется логическая пере-
менная needUpdate; при обнаружении новых слов, которые должны быть добав-
лены в словарь, ей присваивается значение true. Если в словарь были добавлены
новые слова, в последней строке enteredO вызывается функция saveDictionary().
Она сохраняет текст текущего полного словаря в локальном хранилище LSO
(Local Shared Object). LSO всего лишь является удобным средством для хране-
ния данных между сеансами, по аналогии с браузерными cookie. Данные будут
загружены в тот момент, когда это потребуется.
При попытке сохранения LSO, размер которого превышает максимально допус-
тимое значение в системе пользователя, Flash Player запрашивает у пользовате-
ля разрешение на сохранение дополнительных данных, отображая вкладку Local
Storage диалогового окна Settings. По умолчанию объем локального хранилища
данных составляет 100 Кбайт на домен.
Если вы собираетесь организовать локальное хранение данных, сообщите об этом
пользователю. Если диалоговое окно появится неожиданно для пользователя,
это может сильно встревожить его - особенно если заполняемая форма пред-
назначена для оформления заказа на какой-нибудь товар!
Сохраненный словарь загружается функцией loadDictionaryO. Функция сначала
ищет в LSO ранее сохраненный словарь и, если он существует, использует но-
вый текст для замены стандартного словаря myText.
Чтобы убедиться в том, что новые слова сохраняются между сеансами, запусти-
те ролик в режиме тестирования, введите в текстовом поле слово «aardvark»,
218 '_ Глава 6. Текст

закройте SWF-файл и запустите его заново. На этот раз слово «aardvark» авто-
матически завершается после второй буквы.

Итоги
В последнем листинге поиск в словаре производится в двух случаях:
• когда пользователь вводит слова в текстовом поле, происходит подбор вари-
анта для автоматического завершения (алфавитный поиск в массиве dictionary);
• когда мы хотим узнать, присутствуют ли в словаре вновь введенные слова,
поиск выполняется по строке myText.
Таким образом, мы имеем две версии списка слов: одна обеспечивает структур-
ный алфавитный поиск, а другая позволяет узнать, присутствует ли введенное
слово в текущем словаре. Обе версии оптимизированы по скорости.
Возможно, вы также обратили внимание на одно допущение: наша программа
предполагает, что все слова встречаются с одинаковой частотой, а вернее - что
частота их появления соответствует алфавитному порядку. Это не всегда так.
Например, слово «said» встречается чаще, чем «sad», но при алфавитном упоря-
дочении словаря «sad» будет предлагаться раньше, чем «said». Одно из возмож-
ных решений - упорядочить список по частоте использования (либо на основа-
нии данных, полученных в результате статистического анализа, либо простым
подсчетом использования отдельных слов в текущем контексте). Но такое реше-
ние замедлит поиск, если список не будет упорядочиваться (по крайней мере
частично) по алфавиту. При небольших списках слов поиск всегда выполняется
относительно быстро. Но если списки имеют большой размер, выбор решения
зависит от того, насколько алфавитная сортировка снижает скорость.
Область применения методики сохранения часто используемых слов не ограни-
чивается автоматическим завершением текста. Она также может использоваться
для накопления статистики - скажем, отслеживания самых популярных отве-
тов в опросах или предложения возможных условий поиска в тех случаях, когда
поиск по заданному критерию не дает результатов. Конечно, эти нетривиальные
варианты применяются в основном при сохранении данных на рабочем сервере.
Трюк обеспечивает локальное хранение данных, а это означает, что набор часто
используемых слов зависит от пользователя. При помощи Flash Remoting или
других технологий можно загружать данные на сервер и накапливать статисти-
ку по нескольким пользователям.

Перенос сложного форматирования


ТРЮК

№45 в Flash
Воспроизведение в Flash сложных текстовых/графических макетов —
таких, как математические формулы. Microsoft Word используется как
буфер для промежуточного хранения данных.
Flash получает все большее распространение и все чаще используется в целях,
отличных от «чистого» дизайна веб-сайтов. На обучающих сайтах часто возни-
Перенос сложного форматирования в Flash 219

кает задача вывода сложного форматирования текста - например, математичес-


ких формул.
Так, сайт MathWorld (http://mathworld.wolfram.com) довольно быстро сталкива-
ется с ограничениями базовых средств HTML - уравнения, приводимые на этом
сайте, реализуются с использованием растровой графики в таблицах HTML.
Должно быть, на создание таких страниц уходит целая вечность! При создании
макетов с нестандартным форматированием гораздо проще использовать Flash,
нежели HTML. Flash не только позволяет размещать текст с точностью до пик-
села, но и сохраняет возможность его редактирования.
Однако возможности Flash по форматированию текста не ограничиваются про-
стым оформлением - Flash позволяет воспроизводить сложные атрибуты форма-
та, выходящие за рамки традиционных возможностей Web. Как вы вскоре уви-
дите, в Flash даже можно полностью скопировать структуру HTML-страницы!

Создание математических формул


Математические формулы обычно создаются в Microsoft Word с использовани-
ем Equation Editor. Этот специализированный редактор не устанавливается в со-
ставе Microsoft Office по умолчанию. Чтобы установить его в Windows XP (ис-
пользуя Office XP), откройте панель управления Windows и щелкните на кнопке
Установка и удаление программ (Add or Remove Programs). Найдите в списке
Microsoft Office XP и щелкните на кнопке Изменить (Change). В открывшемся
диалоговом окне установки Microsoft Office установите переключатель Добавить
или удалить компоненты (Add or Remove Features) и щелкните на кнопке Далее
(Next). Найдите строку Редактор формул (Equation Editor) в категории Средства
Office (Office Tools), как показано на рис. 6.7.
В Mac OS X Equation Editor устанавливается в составе компонента Microsoft
Office Value Pack, находящегося на компакт-диске Microsoft Office для Mac OS
X; тем не менее, представленный трюк лучше работает в Windows, чем на Мае.
Чтобы использовать редактор формул после его установки, выполните команду
Insert • Object и выберите строку Microsoft Equation. Затем создайте уравнение
при помощи панели инструментов Equation Editor, появившейся на экране. Ос-
новные меню Microsoft Word тоже изменяются, чтобы вам было удобнее приме-
нять форматирование, специфическое для уравнений (в частности, вводить ниж-
ние и верхние индексы и буквы греческого алфавита).
Equation Editor можно заменить редактором MathType (http://www.mathtype.com),
сторонним редактором формул для Word (Word может выдать диалоговое окно
с информацией о MathType при первом запуске Equation Editor). Объекты
MathType имеют более сложную структуру, чем стандартные выходные данные
Equation Editor, поэтому у Flash возникают трудности с их импортированием.
Так что не соглашайтесь на замену, если вы собираетесь использовать математи-
ческие формулы в Flash.
Используя Equation Editor, отформатируйте формулу в Word. Чтобы скопиро-
вать ее в Flash, выделите текст формулы (рис. 6.8) и нажмите клавиши Ctrl+C
(Windows) или <Н>+С (Мае), чтобы скопировать его в буфер обмена.
220 Глава 6. Текст

1
Micros 4

Microsoft Office XP Professional with FrontPage


Choose instaiiafon opoons for air Office applications and toois

Features to install:
ш Office Shared Features


Office Tools
• ' * - - •

H T M L S o u r c e E d i t i n g

i •щ^|
L a n g u a g e S e t t i n g s T o o l

M i c r o s o f t D r a w C o n v e r t e r

M i c r o s o f t G r a p h

: ^р| -г M i c r o s o f t O f f i c e S n d e r S u p p o r t

M i c r o s o f t O f f i c e D o c u m e n t I m a g i n g

X - M i c r o s o f t O f f i c e S h o r t c u t B a r

Description
Inserts mathematical symbols and equations into
documents.
Space Required on С: 1696 KB

Hep „Cancel,:

Рис. 6.7

Копировать нужно текст внутри объекта формулы, а не сам объект формулы.


Впрочем, скопировать объект во время редактирования все равно невозможно,
поэтому, если текст выделяется, как показано на рис. 6.8, - значит, все нормаль-
но. Если скопировать объект, Flash сможет импортировать его только в виде
растрового изображения. Чтобы скопировать текст формулы после выхода из
режима редактирования (то есть если меню Equation Editor отсутствует на экра-
не), дважды щелкните на объекте формулы, затем выделите текст и нажмите
Ctrl+C (Windows) или Ж+С (Мае). После копирования текста в буфер активизи-
руйте окно Flash, щелкните на сцене и вставьте данные из буфера клавишами
Ctrl+V (Windows) или 3€+V (Mac). Формула должна выглядеть как редактируе-
мый текст, объединенный в группу (рис. 6.9).

E q u a t i o n

-»<=>i ; , ' . V 3 ; : Е П С ; 6oo€ : А ш б АП«)


Гц |р | Г"! Г -=-» *-=- f | U ; оса |S|| :

Рис. 6.8. Математическая формула, созданная в Microsoft Office Equation Editor


Перенос сложного форматирования в Flash 221

Рис. 6.9. Уравнение, вставленное в Flash, имеет вид группы


редактируемых текстовых объектов

В Mac OS X формула, скопированная из документа Word и вставленная в Flash,


может содержать неверные символы. Механизм переноса работает надежнее, если
скопировать уравнение прямо из Equation Editor (без вставки объекта уравне-
ния в документ Word) и вставить его непосредственно в Flash.
Если уравнение будет использоваться часто, преобразуйте группу в символ (кла-
виша F8).
Описанная методика отлично подходит для небольших формул, но для постро-
ения более серьезных формул придется основательно потрудиться, особенно если
вы создаете набор Flash-слайдов с изложением волновой теории!

Импортирование форматированного текста


из других источников
Более крупные текстовые блоки с формулами удобнее импортировать в форма-
те HTML или PDF.
Если импортируемая формула является стандартной, просто проведите поиск
в Веб и найдите ее версию, отформатированную в виде HTML-текста (рис. 6.10).
Выделите формулу, скопируйте и вставьте ее из веб-страницы в Word, затем
повторно выделите ее в Word, скопируйте и вставьте в Flash. Word гораздо луч-
ше справляется с импортированием большинства видов данных посредством
копирования/вставки, чем Flash (и, если уж на то пошло, лучше большинства
других приложений).

the Лг-Ьаявошс Fotraer series approximafton сщ be wMttea as!

x(t) ~a0 -raj cos (&U т GJ т a2cos (2®t + Щ


-r ... 4- av cos (Nu)jt + бу

Рис. 6.10. Отформатированная математическая формула на веб-странице


222 Глава 6. Текст

На рис. 6.11 показан текст со сложным форматированием, скопированный из


таблицы HTML в Word.

)pc(t): = cos (mj -f By) + a2 cos (2G>J +

Рис. 6 . 1 1 . Сложный текст, скопированный из HTML-страницы в Word,


может выглядеть как таблица

В Word сложный текст может выглядеть как таблица, но если скопировать его
и вставить в Flash, все получается нормально, как показано на рис. 6.12.

x(t) = а0 + а} cos (wj + 9)) + а2 cos (2a>J + &2)


+ ... + a,v cos (№4/
Рис. 6.12. Таблица, скопированная из Word в Flash MX 2004

На рис. 6.13 показано, как выглядит группа, созданная Flash в результате опера-
ции вставки. Только подумайте, сколько времени потребовалось бы для ручного
создания такой формулы в Flash!

Рис. 6.13. Сложная формула, представленная в виде группы текстовых элементов Flash

Неважно, откуда копируется отформатированный текст, - если его можно вста-


вить в Word, а затем заново скопировать и вставить в Flash, все пройдет нор-
мально. Более того, описанный трюк подходит не только для формул - если
у вас имеются любые данные в формате HTML, которые нужно использовать
в Flash (например, если вы хотите перенести в Flash статическое меню HTML),
просто скопируйте его в Word с HTML-страницы и вставьте в Flash. В системе
Windows такая операция работает идеально (хотя на Macintosh иногда возника-
ют проблемы).

ПРИМЕЧАНИЕ
Копирование/вставка — удобный способ создания форм Flash на базе суще-
ствующих форм HTML/JavaScript.

На рис. 6.14 выделяется основной шаблон сайта O'Reilly с боковым меню. Выде-
ленный HTML-код копируется в буфер.
Перенос сложного форматирования в Flash 223

Рис. 6.14. Выделение заголовка и бокового меню на сайте O'Reilly

Вставьте данные в формате HTML в Word, как показано на рис. 6.15, скопируй-
те их из Word в буфер обмена, затем вставьте в Flash

: f"V r--v< (Г"? • ;


i;:*I •;- ! W ; Ш :( ^эд ' Cj v

^ final Showing P

Рис. 6.15. Данные HTML вставляются в Word, затем заново выделяются


и копируются обратно в буфер

На рис. 6.16 изображен шаблон сайта O'Reilly с боковым меню, выполняемый


в виде SWF-ролика после небольшой корректировки. Все элементы являются
статическими, но эта заготовка может использоваться для воссоздания некото-
рых компонентов сайта на базе Flash.
224 Глава 6. Текст

Рис. 6.16. Основной шаблон сайта O'Reilly в виде SWF-ролика

Если потребуется импортировать целые страницы технических документов


(например, для создания обучающего ролика на техническую тему в стиле
Macromedia Breeze), проще всего преобразовать документ Word в формат PDF
(или получить документ в формате PDF из другого источника), а затем импор-
тировать PDF в Flash командой File • Import.

Итоги
Хотя для публикации технической информации в Веб можно использовать про-
стые электронные документы PDF или отформатированные данные HTML, тех-
нология Flash обладает рядом преимуществ (например, она позволяет приме-
нять анимацию при выводе диаграмм). Многие физические концепции трудно
объяснить на статических моделях, и тогда SWF-ролики Flash с анимацией, по-
ясняющей описанный материал, окажут огромную помощь.
Если вы еще не уверены в необходимости использования математических фор-
мул в Flash, ознакомьтесь с некоторыми анимированными системами, реализо-
ванными на Flash (например, с системой работы с формулами Роберта Пеннера
по адресу http://www.robertpenner.com). Автор объясняет основные принципы
работы с системой при помощи Flash, и это выглядит в высшей степени уместно!
Возможности форматирования текста в Flash весьма ограничены (хотя поддержка
CSS в Flash MX 2004 отчасти решает эту проблему). Microsoft Word обладает
гораздо лучшими средствами работы с текстом, поэтому текст удобнее отформа-
тировать в Word и перенести в Flash через буфер обмена.
Если элементы Flash потребуется вставить в существующую структуру HTML,
попробуйте импортировать весь макет (вместе с текстом и растровой графикой)
Использование HTML и CSS в Flash 225

п
по цепочке H T M L • Word • Flash. Таким способом даже многие интерфейсные эле-
менты JavaScript (например, поля) импортируются в виде растровой графики!

ПРИМЕЧАНИЕ
Flash MX 2004 стал первой версией продукта с проверкой орфографии. Если вы
используете более раннюю версию, проверьте правописание текста в Word и ско-
пируйте его в Flash.

Методика, описанная в этом разделе, хорошо работает в системе Windows, но


у пользователей Macintosh могут возникнуть проблемы.

ТРЮК Использование HTML и CSS в Flash


№46 Flash MX 2004 обладает расширенными возможностями форматирова-
ния HTML, а также поддерживает CSS. Это позволяет создавать страни-
цы, которые по внешнему виду напоминают Flash, но загружаются как
обычные HTML-страницы.
В Flash существуют разные способы форматирования текста - например, ис-
пользование экземпляров класса TextFormat для применения форматирования
к экземплярам TextField (см. трюк 42). Для тех, кто привык использовать теги
HTML, Flash MX и более поздних версий поддерживает базовые средства форма-
тирования HTML. В Flash MX 2004 появилась поддержка стилевых таблиц CSS,
упрощающих применение и изменение текстовых стилей в презентациях Flash.
Впрочем, сходство возможностей форматирования текста еще не означает, что
Flash ведет себя точно так же, как HTML в браузере. Одна из основных проблем
с сайтами Flash состоит в том, что процесс их загрузки не всегда проходит так
же, как загрузка простых HTML-страниц. При загрузке HTML-страниц боль-
шинство ресурсов отображается сразу же после того, как они становятся доступ-
ными; не требуется ни предварительная загрузка, ни потоковая передача дан-
ных, ни другие средства управления пересылкой данных.
Flash-сайты превосходят свои аналоги HTML по анимации и интерактивности,
но некоторые странности загрузки Flash-сайтов обескураживают многих пользо-
вателей:
• По прошествии одной-двух секунд пользователь не может выяснить, содер-
жит ли страница нужный материал, просто просмотрев начало загруженной
страницы.
• При загрузке содержания Flash обычно не учитывается «удельный вес» от-
дельных элементов. Например, многие веб-страницы HTML практически мгно-
венно отображают текст и пустые таблицы, затем появляется графика, и только
потом - прочие данные (например, видео). В Flash дело обстоит иначе: если
для первого кадра временной диаграммы нужно загрузить 150 Кбайт, а на
втором кадре размещены 3 Кбайт простого текста, этот текст появится лишь
после того, как будут загружены первые 150 Кбайт.
Хотя хороший Flash-дизайнер способен решить обе проблемы, поддержка фор-
матирования HTML в Flash MX 2004 позволяет приблизить процесс загрузки
к традиционному.
22В Глава 6. Текст

Форматирование текста с применением HTML


В текстовых полях текст обычно воспроизводится буквально. Следовательно,
для того чтобы текст выводился без интерпретации метаданных, достаточно вос-
пользоваться свойством TextField.text. В следующем примере теги HTML не ин-
терпретируются и выводятся как обычный текст:
myText.text = "Enter any <b>HTML formatted</b> text here";
trace(myText.text);
// Результат:
Enter any <b>HTML formatted</b> text here
Чтобы содержимое текстового поля интерпретировалось как HTML-код, за-
дайте свойству html значение true и присвойте код HTML свойству htmlText,
как показано далее (обратите внимание на жирный шрифт в выходных дан-
ных):
myText.html = true:
myText.html Text = "Enter any <b>HTML formatted</b> text here":
trace(myText.text):
// Результат:
Enter any HTML formatted text here
Строка, назначаемая свойству myText.htmlText, может содержать следующие теги
H T M L : <a> (с атрибутами href и target), <Ь>, <br>, <font> (с атрибутами face,
color и size), <i>, <li>, <p>, <span> и <u>.
Также поддерживается атрибут class, позволяющий создавать определения клас-
сов CSS; кроме того, как будет показано далее, вы можете создавать определе-
ния стилей CSS.
Между реализациями тегов в Flash и HTML существуют некоторые различия.
В частности, если заключить блок текста между тегами <а> и </а> (тег ги-
перссылки) в Flash, стиль текста не изменяется автоматически в соответствии
с внешним видом ссылки (подчеркнутый синий текст). Форматирование текста
придется задать явно с использованием других тегов. Например, подчеркивание
текста ссылки обеспечивается тегом <и>:
myText.html = true;
myText.html Text = "This is a <u><a href = 'somelink'>link</a></u>";
На рис. 6.17 показано, как будет выглядеть полученный текст; слово «link» дей-
ствует как гиперссылка.

T h i s is a link

Рис. 6.17. Создание ссылки HTML в Flash с применением тегов


подчеркивания и гиперссылки

Впрочем, для форматирования данных в стиле HTML существует более удоб-


ный способ - поддержка CSS в Flash MX 2004.
Использование HTML и CSS в Flash 227

Форматирование с использованием CSS


Каскадные таблицы стилей (CSS, Cascade Style Sheets) позволяют задавать ат-
рибуты форматирования при помощи таблиц, хранящихся во внутреннем или
внешнем представлении (файлы .ess). Изменение таблицы приводит к измене-
нию текстовых стилей во всей презентации. Flash MX 2004 поддерживает атри-
бут HTML class для определения таблиц стилей, что позволяет использовать
форматирование CSS в тексте. Например, можно определить текстовый стиль,
обеспечивающий выделение гиперссылок синим цветом (см. трюк 93). Также
следует учесть, что при определении CSS во внешних текстовых файлах необхо-
димо позаботиться о том, чтобы таблица была полностью загружена перед ис-
пользованием - при загрузке стилевых таблиц для HTML-страниц браузер берет
эту заботу на себя. Следующий фрагмент кода корректно загружает внешнюю сти-
левую таблицу myExternalCSS.css и использует ее для форматирования HTML-кода
в текстовом поле Flash:
// Определение нового объекта Stylesheet
var myStyle = new TextField.StyleSheetO;
// После того как загрузка таблицы будет завершена.
// использовать ее для форматирования текста.
myStyle.onLoad = function О {
myText.stylesheet = t h i s ;
myText.html = true;
myText.htmlText = myHTML;
}:
myStyle.1oad("myExternalCSS.ess");
myHTML = "<p class = 'title'>Creating an e f f i c i e n t walk cycle</p>"
myHTML+= "<br><p><span class = 'emphasis'>Scribble</span> moves very " +
"quickly in the final work, far too quickly for the viewer to see " +
"the lack of frames. He also spends a l o t of time in the a i r . thus " +
"minimizing the slide walk effect.</p>"
myHTML+= "<p>You can see an example of him moving <a href = 'someURL'>here</
a>.<br><br>"
myHTML+= "<p>Of course, when two designers get together, easy options " +
"always go out of the window...(etc)</p>."
Файл myExternalCSS.css представляет собой простой текстовый файл с опреде-
лениями классов и стилей CSS:
body {
font-family: Verdana. Arial. Helvetica, sans-serif;
font-size: 12px;
font-weight: normal;
text-decoration: none;
color:#909090;
}
.emphasis {
font-family: Verdana. Arial. Helvetica, sans-serif;
font-size: 12px;
font-weight: normal:
228 . Глава 6. Текст
text-decoration: none;-
color:#404080;
}
.title {
font-family: Verdana. Arial. Helvetica, sans-serif:
font-size: 16px;
font-weight: bold:
text-decoration: none;
COlor:#8080A0;
}
a:link {
font-family: Verdana. Arial. Helvetica, sans-serif:
font-size: lOpx:
font-weight: none;
text-decoration: underline;
color:#8080A0:
}
a:visited {
font-family: Verdana. Arial. Helvetica, sans-serif;
font-Size: lOpx;
font-weight: bold;
text-decoration: underline.:
COlor:#333355:

a:active {
font-family: Verdana. Arial. Helvetica, sans-serif;
font-size: lOpx;
font-weight: bold:
. text-decoration: underline;
col or:#444444:

a:hover {
font-family: Verdana. Arial. Helvetica, sans-serif;
font-size: lOpx;
font-weight: bold:
text-decoration: underline;
COlor:#C08080;
}
Стоит обратить внимание на ряд обстоятельств:
• Flash не поддерживает теги заголовков HTML (<h1>, <h2> и т. д.), однако
это ограничение можно обойти посредством определения собственных клас-
сов CSS - таких, как класс .title в нашем примере.
• Flash не различает единицы определения размеров шрифта рх (пикселы)
и pt (пункты). Следовательно, неважно, какая из этих единиц будет исполь-
зоваться в таблице стилей.
• Поддержка CSS в Flash позволяет определять ссылки HTML. Текст, пред-
ставляющий ссылку, находится в одном из состояний link, visited, active или
hover, атрибуты которых определяются в таблице.
Использование HTML и CSS в Flash 229

• Значения свойства color задаются числовыми литералами - например, #444-


444. Использование имен цветовых констант, поддерживаемых браузерами,
не допускается.
• По аналогии с внешним определением CSS, код HTML также можно разме-
стить в отдельном текстовом файле и загрузить его функцией LoadVars.load().
Тем не менее при загрузке внешнего кода HTML необходимо проследить за
тем, чтобы текстовые файлы загружались в правильном порядке: сначала
загружается файл CSS, затем файл с кодом HTML, а затем в текстовое поле
заносятся текстовые данные. В противном случае определения CSS окажут-
ся недоступными или код HTML может оказаться недоступным при его раз-
мещении в текстовом поле.

ПРИМЕЧАНИЕ
Если HTML-код имеет относительно небольшой объем, определите его внутри
SWF. Однако графику в HTML-коде обычно лучше загружать на стадии выполне-
ния при помощи тега <img>, о котором речь пойдет далее.

На рис. 6.18 приведен результат выполнения предыдущего кода с файлом CSS.


Предполагается, что на сцене создано динамическое текстовое поле с именем myText.

Creating an efficient w a l k cycle


Scribble moves very quickly in the final work» fartooquickly for the viewer to see the iack o
ftam&s. He also spends aforof time in the atr, thus minimizing the slide walk effect.
You сел see an exampte or him moving here.

Рис. 6.18. Форматирование текста в Flash с использованием таблицы стилей

Внедренная графика
Один из самых замечательных аспектов поддержки HTML в Flash MX 2004 -
возможность применения атрибута src тега <img> для внедрения графики J P E G
в текстовое поле. Например, в следующем фрагменте изображение задается в од-
ном из тегов <р> (изменения выделены жирным шрифтом):
myHTML = "<р class = 'titie'>Creating an e f f i c i e n t walk cycle</p>"
myHTML+= "<br><p><img src = 'walk.jpg' align = ' r i g h t 1 > " +
"<span class = 'emphasis'>Scribble</span> moves very " +
"quickly in the f i n a l work, far too quickly for the viewer to see " +
"the lack of frames. He also spends a l o t of time in the a i r . thus " +
"minimizing the slide walk effect.</p>"
myHTML+= "<p>You can see an example of him moving <a href = 'someURL'>here</
a>.<br><br><br><br>"
myHTML+= "<p>Of course, when two designers get together, easy options " +
"always go out of the window...(etc)</p>."
Результат, полученный при выполнении этого кода, показан на рис. 6.19.
Изображение загружается во время обработки HTML-кода на стадии выполне-
ния. Сначала на странице появляется текст. После того как изображение будет
230 Глава 6. Текст

полностью загружено, оно тоже появляется на странице, и текст автоматически


переформатируется, освобождая место для графики... как при отображении HTML
в браузере!

Creating an efficient walk cycle


Scribble moves very
quickly in the final
work, farroc?quickly
for the viewer to see
He also spends a tec
of time in the sir,
thus mirumrzing the
slide: waik effect.
You ~<\in ?-w?? --$"
exsmpie of hitri
moving jjerg.

; when two designers gz he?., easy options always, go out Dt the wind aw,,, (etc)
Рис. 6.19. Загрузка внедренного изображения на стадии выполнения

Учтите, что теги <р> и <img> в Flash работают несколько нестандартно.


• Блоки < р х / р > не разделяются пропусками, поэтому нам приходится ис-
пользовать теги <br>, как в предыдущем листинге.
• Теги <img> весьма своенравны. Например, они не работают, если это единствен-
ный тег в текстовом поле. Проблема решается заключением <img> между дру-
гими тегами (обычно хватает абзаца, содержащего единственный пробел, или па-
ры тегов <br>). Выбор окружающих тегов зависит от размера текстового поля.
• Flash не поддерживает загрузку прогрессивной графики JPEG при помощи
тега <img>. Если указать файл JPEG в прогрессивном формате, изображение
не появится.
• Тег <img> поддерживается только для текстовых полей, у которых свойства
TextField.multiline и TextField.wordwrap равны true.
• Чтобы внедрить SWF-файл, задайте путь к нему в атрибуте src тега <img>.
Чтобы внедрить анимационный клип, задайте атрибуту src идентификатор
компоновки символа клипа.
• Необязательный атрибут <id> тега <img> задает имя, используемое для управ-
ления внедренным содержанием из ActionScript.

Итоги
Flash MX 2004 предоставляет широкие возможности управления текстом за счет
поддержки функциональных подмножеств стандартных спецификаций HTML
и CSS. Чтобы объем Flash Player оставался небольшим, фирма Macromedia отка-
залась от полной реализации спецификаций; кроме того, поддержка CSS в Flash
отличается от поддержки CSS в браузере. Подмножество поддерживаемых тегов
и определений CSS прошло тщательный отбор. Некоторые теги (например, теги
заголовков) не поддерживаются, но вместо них можно легко определить соб-
ственные классы или стили CSS.
Всплывающие подсказки 231

Хотя некоторые дизайнеры были недовольны тем, что Flash не поддерживает


таблицы HTML и расширенное блочное форматирование CSS, поддержка HTML/
CSS позволяет легко загружать и размещать большие блоки текста и графики на
стадии выполнения - в предыдущих версиях сделать это было непросто.
Что еще важнее, поддержка HTML/CSS в Flash MX 2004 позволяет более четко
отделить текстовое и графическое содержание от пользовательского интерфейса
Flash-сайтов (и даже хранить его отдельно от файла SWF). Данная особенность
упрощает обновление материала.

Всплывающие подсказки
Вспомогательный текст обычно используется специализированными про-
граммами для пользователей с дефектами зрения. Впрочем, его также
можно использовать для выдачи справочной информации тем, кто видит
нормально.
При проектировании Flash MX была учтена и такая серьезная проблема веб-
дизайна, как проблема доступности контента Flash наравне со всем прочим веб-
контентом. В частности, появилась панель Accessibility для ввода текстовых строк,
используемых специальными программами для слабовидящих. В Flash MX 2004
компоненты v2 были дополнены новыми возможностями, включая улучшенную
поддержку управления фокусом.
Конечно, даже пользователи с нормальным зрением иногда нуждаются в помо-
щи, поэтому вспомогательный текст может пригодиться и им, хотя и в несколь-
ко иной форме. В этом трюке вспомогательный текст используется для реализа-
ции всплывающих подсказок.

Добавление специальных свойств


Чтобы добавить специальные свойства к анимационному клипу, кнопке или не-
статическому текстовому полю (то есть к любому графическому объекту), выде-
лите элемент на сцене и введите необходимую информацию на панели Accessibility.
На рис. 6.20 вспомогательный текст добавляется к кнопкам из трюка 96.

* Accessibility
j 0 Make Object Accessble '
# В Г ] Make child objects a xessible •'.'. \

• С
- Name:! Button A

Description::; ' ' •••••••' ^ i

Щ
. Shortcut: : A ''11
Tab index:: -:
ш"!шштА

Рис. 6.20. Ввод специальных свойств на панели Accessibility


232 Глава 6. Текст

Если экспортировать клип для Flash Player версии 6г65 и выше, вы увидите, что
у выделенного объекта появилось свойство accProps (рис. 6.21).

; JevdO.buttonA

3 accProps
I true
гмитев
shortcut

Рис. 6 . 2 1 . Свойство accProps кнопки buttonA

Содержимое полей Name, Description и Shortcut на панели Accessibility отобража-


ется в виде подсвойств name, description и shortcut свойства _accProps.
Конечно, свойство _accProps для элемента можно определить из ActionScript.
Данная возможность может использоваться при динамическом связывании кон-
тента с временной диаграммой или включении вспомогательного текста в от-
дельный файл, обрабатываемый на стадии выполнения. Следующая команда со-
здает описание для кнопки buttonA:
buttonA._accProps.description = "some text":
Зная все это, мы можем легко приспособить вспомогательный текст для реше-
ния практически любых задач, в том числе:
• организации звукового воспроизведения вспомогательного текста (см. трюк 52)
на устройствах с поддержкой звука, но без специализированных программ
для слабовидящих, а также в тех случаях, если вывод звуковой информации
используется для экономии места на экране;
• отображения всплывающих подсказок.
В этом трюке мы займемся решением второй задачи. Когда пользователь задер-
живает указатель мыши над кнопкой, содержимое свойств _accProps будет ис-
пользоваться для создания справочного текста (рис. 6.22).

Button В
Control+B

Рис. 6.22. Всплывающая подсказка.

Взяв за основу код создания сочетаний клавиш (см. трюк 96), мы включим в не-
го три новые функции:
• определение событий, управляющих выводом справочного текста. Для этой
цели будут использоваться события onRollOver и onRollOut;
• размещение подсказок на сцене;
Всплывающие подсказки 233

• удаление подсказок после того, как они станут ненужными.


Но сначала нужно создать справочный текст - либо динамическим созданием
текстового поля, либо созданием нового символа, динамически связанного со
сценой. В данном трюке используется второй способ - на рис. 6.23 показан
символ клипа helpText, содержащий многострочное динамическое текстовое поле
с именем экземпляра helpText.

Рис. 6.23. Символ helpText

Назначьте текстовому полю бордюр и выберите шрифт _sans с размером 14 пунк-


тов.
Код создания простого текстового поля на основании свойств _accProps приво-
дится в следующем разделе.
Функция addHelp() настраивает событие onRollOver на вызов функции createHelpText()
через 1,2 с. Если пользователь отодвигает указатель мыши от символа, интер-
вальный таймер сбрасывается вместе с текущим текстом подсказки (для этой
цели используются события onRollOut/onDragOut).
Функция createHelpText() присоединяет новый экземпляр символа клипа helpText
и заполняет его информацией _accProps. В этом коде обратите внимание на сле-
дующие обстоятельства:
• функция должна знать размер поля helpText, при котором оно будет вмещать
текст справки. Для этого она создает объект TextFormat, повторяющий атри-
буты форматирования текста, и вызывает метод TextFormat.getTextExtent() для
определения размеров текста. К сожалению, метод TextFormat.getTextExtent()
обычно возвращает заниженный результат. Чтобы преодолеть этот недоста-
ток, мы задаем значение helpFormat.size чуть большим фактического размера
шрифта, используемого в текстовом поле;
• свойства background и backgroundColor приходится задавать средствами Action
Script, потому что на панели свойств отсутствуют элементы для их ручного
задания.
234 Глава 6. Текст

Программа
Следующий код получает вспомогательный текст и использует его для построе-
ния всплывающей подсказки. Предполагается, что на сцене размещены три кнопки
с именами buttonA, buttonB и buttonC. Если щелкнуть на кнопке или нажать опре-
деленную комбинацию Клавиш, выполняются соответствующие обработчики
событий. За кнопками закреплены следующие комбинации клавиш:
• ButtonA - A;
• ButtonB - Control+B;
• ButtonC - Control+D.
Обратите внимание: в поле Shortcut слово «Control» должно вводиться полностью,
хотя в книге эта клавиша обычно обозначается сокращением «Ctrl». Кроме того,
для каждой кнопки должны быть определены свойства, содержащие вспомогатель-
ную информацию. Откройте панель Accessibility (Window • Other Panels • Acces-
sibility) и введите для каждой кнопки имя и комбинацию клавиш, как показано
на рис. 6.24. В нашем примере заполняются поля Name и Shortcut, но вы можете
самостоятельно изменить программу, чтобы в подсказке отображалось содержи-
мое поля Description.
• - • . • • • • • •

тлссе* sibrfrty
0 Make 01sjectAccesable
;::Owske:d-|fd objects;.3ccesSbie и;' ';•,•}
г\

Name: | Button A
Description: i

С ; Shortcut: j A

Tab: infer:

Рис. 6.24. Ввод свойств кнопок на панели Accessibility

Следующий фрагмент использует заданные свойства для создания справочного


текста и реализации ускоренного вызова комбинациями клавиш. Подробные
комментарии помогут разобраться в происходящем:
function addHelp(target) {
target.onRollOver = functionO {
// Отображение подсказки задерживается на 1.2 секунды.
helplnterval = setlnterval(createHelpText. 1200. target);
}:
target.onRollOut = target.onDragOut=function 0 {
// Когда указатель мыши выходит за пределы клипа.
// подсказка скрывается.
clear-Interval (helplnterval);
Всплывающие подсказки 235

removeHelpTextO ;

function createHelpText(target) {
// Создание клипа с текстом подсказки.
var helpClip:MovieClip = attachMovieC'helpText". "helpText".
t h i s.getNextHi ghestDepth());
clearlnterval(helplnterval):
// Задание атрибутов текста подсказки.
var helpText:TextField = helpClip.helpText;
helpText.background = true;
helpText.backgrounded or = OxFFFFCC;
// Форматирование текста подсказки.
var helpFormat:TextFormat = new TextFormatO;
helpFormat.leftMargin = 2;
helpFormat.rightMargin = 2;
helpFormat.indent = 0:
helpFormat.size = 15;
helpFormat.font = "_sans";
//
// Если у целевого клипа задано вспомогательное свойство name.
// оно отображается в подсказке.
if (target._accProps.name != undefined) {
helpText.text = target._accProps.name;
}
if (target._accProps.shortcut !•= undefined) {
// Если у целевого клипа задано вспомогательное свойство
// shortcut, оно включается в подсказку.
helpText.text += "\n"+target._accProps.shortcut;
}
// Задание размеров подсказки.
var fieldSize;Object = helpFormat.getTextExtent(helpText.text)
helpText._height = fieldSize.textFieldHeight;
helpText._width = fieldSize.textFieldWidth;
helpClip._x = _xmouse-helpClip._width/2:
helpClip._y = _ymouse-helpClip._height-10;
} • •
function removeHelpTextO {
helpText.removeMovi eCli p ( ) :
}
function aHandlerO {
// Обработчик события кнопки А
traceC'You clicked A");
}
function bHandlerO {
// Обработчик события кнопки В
traceC'You clicked В");
}
function cHandlerO {
// Обработчик события кнопки С
traceC'You clicked С"):
236 Глава 6. Текст
function down() {
// Функция обнаруживает комбинацию клавиш
// и выполняет соответствующий сценарий,
var all Keys;
// Проверить, нажаты ли все клавиши в комбинации,
for (var j - 0: j<keys.length; j++) {
all Keys = true;
for (var i = 0; i<keys[j].combo.length; i++) {
allKeys = al1 Keys && Key.isDown(keys[j].combo[i]);
}
if (allKeys) {
// Если все клавиши комбинации нажаты, передать фокус
// кнопке и выполнить ее обработчик события. Дальнейшие
// события блокируются до момента отпускания нажатых клавиш.
Selecti on.setFocus(keys[j]):
this.onKeyDown = undefined:
this.onKeyUp = up:
keys[j].btn.onRelease();
break;

}
function upO {
// Функция выполняется при отпускании комбинации клавиш.
this.onKeyUp = undefined:
this.onKeyDown = down:

var keys:Array = new ArrayO:


var keyListener:Object = new ObjectO:
keys[0] = {btn:buttonA. combo:[65]};
keys[l] = {btn:buttonB. combo:С Key.CONTROL. 66]}:
keys[2] = {btn:buttonC. combo:[Key.CONTROL. 68]}:
buttonA.onRelease = aHandler:
buttonB.onRelease = bHandler;
buttonC.onRelease = cHandler;
addHelp(buttonA);
addHelp(buttonB);
addHelp(buttonC);
keyListener.onKeyDown = down;
Key.addListener(keyListener):
На рис. 6.25 показан пример выполнения кода. Кнопке В назначено вспомога-
тельное имя «Button В», а в поле Shortcut введена комбинация клавиш Control+B;
если задержать указатель мыши над кнопкой, на экране появляется подсказка
с этой информацией. Если пользователь нажмет Control+B, выполняется обра-
ботчик события bHandler().
Учтите: программа не проверяет, находится ли подсказка полностью на сцене
и не закрыта ли указателем мыши. Код всего лишь демонстрирует базовую кон-
цепцию, которую при необходимости можно легко дополнить новыми воз-
можностями.
Текстовые эффекты 237

Button 8
Control+B

Рис. 6.25. Текст подсказки для кнопки В

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

ТРЮК Текстовые эффекты


№48 Текстовые эффекты анимируют текст или представляют его в необычном
виде. Создать обобщенный генератор текстовых эффектов оказывается
на удивление легко.
Многие читатели знакомы с текстовыми эффектами по программам для созда-
ния презентаций (таким, как Microsoft PowerPoint), в которых текст перемеща-
ется или анимируется по несложным правилам. Спектр возможных анимацион-
ных текстовых эффектов в Flash куда более разнообразен. Текстовыми эффектами
часто злоупотребляют, но они позволяют эффективно и наглядно донести до
читателя основную мысль или добавить анимацию к кнопкам и баннерам.
Существует немало генераторов текстовых эффектов Flash, написанных сторонними
разработчиками. Для примера можно упомянуть SWiSH (http://www.swishzone.com),
Flax (http://www.flaxfx.com), Magic Flare (http://magicflare.com) и Anim-FX (http://
www.flashtexteffects.com). Хорошие дизайнеры относительно редко применяют
текстовые эффекты, поэтому расходы на покупку генератора ради создания не-
скольких эффектов могут оказаться неоправданными. С учетом этого обстоя-
тельства я написал следующую программу, позволяющую быстро и легко созда-
вать текстовые эффекты.
Программа основана на следующих принципах:
• каждая буква в тексте анимируется отдельно от других;
• анимация букв происходит с небольшой задержкой. Например, если мы хо-
тим анимировать буквы слова «c-a-t», сначала должна появляться буква «с»,
затем буква «а» и в последнюю очередь - буква «t». Любые другие варианты
затрудняют чтение, и применять их не рекомендуется (если, конечно, они не
являются частью задуманного эффекта). Одновременное появление всех букв
при большом объеме текста замедлит эффект;
• в конце эффекта текст имеет «нормальную» позицию и ориентацию. Хотя
в некоторых случаях это может оказаться нежелательным (например, если
238 Глава 6. Текст

вы хотите, чтобы текст сначала проступил, некоторое время оставался на эк-


ране, а потом растворился), такое предположение удобно для разработки ис-
ходного обобщенного решения.

Создание текста
Хотя пустые текстовые поля можно создавать динамически методом MovieClip.create
TextField(), прежде чем анимировать текстовое поле, его необходимо создать в пу-
стом анимационном клипе (поскольку класс TextField не поддерживает события
onEnterFrame для покадрового обновления). Кроме того, необходимо просле-
дить за тем, чтобы шрифт, используемый текстовым полем, был правильно вне-
дрен в итоговый SWF-ролик. Самый простой и безопасный способ - создать
текстовое поле внутри клипа и вручную внедрить шрифт на стадии разработки.
Далее остается лишь воспользоваться ActionScript для размещения символа,
созданного вручную, на сцене во время выполнения.
Создайте на сцене динамическое текстовое поле при помощи инструмента Text.
Введите в нем текст «mm», чтобы быть уверенными в том, что поле вместит
один произвольный символ выбранного шрифта. Выберите на панели свойств
тип текста Dynamic Text (рис. 6.26), выберите простой шрифт без засечек (напри-
мер, Arial или Helvetica) размером 24 пункта. Наконец, задайте текстовому полю
имя экземпляра field.

Dynamc
i Text j^J Jill Arial
"field' ШШФ \ %:•' f Ш;1
imrn
\ Single Line ° .U EH
v; <0

Рис. 6.26. Задание свойств текстового поля

ПРИМЕЧАНИЕ
Выбор простого шрифта без засечек предотвращает использование сложных
шрифтов с большим количеством векторных элементов. Тем самым гарантиру-
ется быстрая анимация итогового эффекта и незначительный объем лишних
данных, обусловленных внедрением шрифта. Не используйте системные шрифты
(такие, как _sans), потому что текстовые эффекты работают только при внедре-
нии шрифта.

Внедрение шрифта
Чтобы внедрить шрифт в SWF, не снимайте выделения с текстового поля и щелк-
ните на кнопке Character в правой части панели свойств (если кнопка Character
не отображается, значит, вы забыли выбрать тип текста Dynamic Text). В открыв-
шемся диалоговом окне Character Options (рис. 6.27) установите переключатель
Select Ranges и выделите первые 4 строки списка, щелкая на них с нажатой
клавишей Shift.
Текстовые эффекты 239

Embed font outlines for:

Basic Latin (95 glyphs)


Japanese Капа {318 glyphs)
Japanese Kanji -Level l{3174glv|i
Japanese (АИ) (7517glyphs)
Basic HangiJ (3454 glyphs)
:
Hangul (All) (11772 glyphs) t~:~
Traditional .Chinese -Level 1C5609JV

Indude these characters:

! !

Рис. 6.27. Диалоговое окно Character Options

Инкапсуляция поля в клипе


Не снимая выделения с текстового поля, нажмите клавишу F8, чтобы преобразо-
вать его в символ анимационного клипа (а точнее, инкапсулировать текстовое
поле в клипе). Задайте символу клипа имя letter. Дважды щелкните на нем, что-
бы войти в режим редактирования, и переместите текстовое поле (при помощи
инструмента Selection) так, чтобы его левый нижний угол был совмещен с точ-
кой регистрации клипа (рис. 6.28). Выйдите из режима редактирования, щелк-
нув на строке Scene 1 в области навигации панели Timeline, и удалите экземпляр
letter со сцены.

Рис. 6.28. Совмещение левого нижнего угла текстового поля


с точкой регистрации клипа

Остается задать клипу идентификатор символа компоновки, чтобы его можно


было динамически размещать на сцене средствами ActionScript. Выделите
символ letter в библиотеке, щелкните на нем правой кнопкой мыши (Windows)
или щелкните с нажатой клавишей Н ! > (Мае) и выберите в контекстном меню
команду Linkage. Установите флажки Export for ActionScript и Export in First
Frame. Убедитесь в том, что в поле Identifier выбран символ letter, и щелкните на
кнопке ОК.
240 Глава 6. Текст

Динамическое размещение текста


Чтобы разместить текст на сцене с соразмерным распределением пробелов, свя-
жите следующий сценарий с кадром 1 временной диаграммы:
// Код ActionScript 2.0
function placeTextCtarget:MovieClip. x:Number. y:Number.
banner:String. tFormat:TextFormat):Void {
// Для каждого знака...
for (var i = 0; i<banner.length: i++) {
// Создать клип и поместить текущий символ в текстовое поле.
var char:MovieClip = target.attachMovie("letter". "char"+i.
target.getNextHi ghestDepth());
char.field.text = banner.substr(i, 1):
char._x = x:
char._y = y:
// Прибавить ширину текущего знака к позиции х следующего знака,
х += tFormat.getTextExtent(char.field.text).width;

}
var format:TextFormat = new TextFormatO;
format.font = "Arial":
format.size = 24;
placeText(this, 100. 100. "This is a text effect", format);
Функция placeText() создает надпись, текст которой задается аргументом banner,
в позиции (х, у) временной диаграммы timeline. Межсимвольные интервалы
определяются объектом tFormat класса TextFormat. Если вместо Arial использует-
ся другой шрифт или размер шрифта отличен от 24, внесите соответствующие
изменения в две строки, выделенные жирным шрифтом. Чтобы использовать
шрифт другого размера, измените размеры текстового поля - выделите его ин-
струментом Text и перетащите ограничивающий прямоугольник до нужных
размеров.
При использовании значений, заданных в последней строке листинга, текст
выводится с правильными межсимвольными интервалами, как показано на
рис. 6.29.

T h i s is a t e x t e f f e c t
Рис. 6.29. Выходные данные генератора с пропорциональными интервалами

Если экземпляр TextFormat не используется, а знаки текста выводятся на фикси-


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

ТЫ s j s a text effect
• Рис. 6.30. Текст, выведенный без пропорциональных интервалов

Пропорциональные интервалы обеспечиваются следующей строкой:


х += tFormat.getTextExtent(char.field.text).width;
Эффект пишущей машинки 241

Если заменить выражение в правой части константой, (например, х+=12;), вы


получите текст с непропорциональными интервалами, наподобие изображенно-
го на рис. 6.30.
Хотя надпись внешне выглядит как обычная строка Flash, в действительности
она состоит из серии клипов, каждый из которых содержит всего один символ.
Методику создания анимированных эффектов на этой основе проще всего пояс-
нить на конкретных примерах. Далее мы рассмотрим несколько примеров таких
эффектов, в том числе эффект пишущей машинки (см. трюк 49).

Итоги
В настоящее время существует целый ряд генераторов текстовых эффектов, раз-
работанных независимыми фирмами, но базовый код текстового эффекта все-
гда остается одним и тем же. Стоит разобраться в основополагающих принци-
пах, и вы сможете легко создавать собственные эффекты. Возможности написания
текстовых переходов ограничены только вашим воображением.
Хотя некоторые знаменитые текстовые эффекты (см. трюк 31) можно реализо-
вать разными способами, универсальная основа, приведенная в этом трюке, по-
может вам генерировать собственные текстовые эффекты (см. трюк 50). Если
вам нужен исходный творческий импульс, посмотрите на начальные титры в та-
ких фильмах, как «Звездные войны», «Семь» или любой фильм Хичкока.

ТРЮК Эффект пишущей машинки


№49 Создание классического текстового эффекта пишущей машинки без при-
менения ручной анимации.
Эксперименты с заготовкой для создания текстовых эффектов обычно начина-
ются с классического эффекта пишущей машинки. Этот эффект прекрасно под-
ходит для оформления начальных титров в триллерах, криминальных драмах
и фильмах о писателях (таких, как «Адаптация»).
Мы реализуем эффект пишущей машинки вместе со звуковым сопровождением.
Программа предполагает, что Flash-ролик содержит звуковые данные с иденти-
фикатором компоновки typeClick (импортируйте звуковой файл в Flash и задай-
те идентификатор компоновки в диалоговом окне Linkage Properties, вызывае-
мом из раскрывающегося меню Options панели Library). Естественно, в файле
typewriter.fla, находящемся на сайте книги, используется звук нажатия клавиш
механической пишущей машинки.

Программа
Приведенный далее код написан на базе заготовки для построения текстовых
эффектов (см. трюк 48). Изменения выделены жирным шрифтом. Предполага-
ется, что динамическое текстовое поле letter находится в клипе с именем экзем-
пляра field, а в библиотеке существует звуковой клип typeClick.
242 Глава 6. Текст

function typewriter(target:MovieClip, del ay:Number):Void {


target.interval = functionO { .
target._visible = true:
keyHit.start(0, 1);
clearlnterval(target.interval ID);
}:
target.interval ID = setlnterval(target, "interval", delay):
target._visible = false;
}
function placeText(target:MovieClip. x:Number, у:Number, banner:String.
tFormat:TextFormat):Void {
// Для каждого знака...
for (var i = 0; i<banner.length; i++) {
// Создать клип и поместить текущий символ в текстовое поле.
var char:MovieClip = target.attachMovie("letter". "char"+i. •
target.getNextHi ghestDepth());
char.field.text = banner.substr(i. 1);
char._x = x;
char._y = y;
// Прибавить ширину текущего знака к позиции х следующего знака.
х += tFormat.getTextExtent(char.field.text).width:
//
// Вызов эффекта.
var timer = i*200+Math.round(Math.random()*200);
typewriter(char, timer);

}
var keyHit = new Sound(this);
keyHit. attachSoundf typeCl i ck");
var format:TextFormat = new TextFormatO;
format.font = "Aria!":
format.size = 24;
placeTexttthis. 100, 100. "This is a text effect.", format);
В конце функции placeTextQ задается задержка timer от 200 до 300 мс на каждый
знак. Указанный интервал должен пройти перед выводом текста (и воспроизве-
дением соответствующего звука) функцией typewriter(). Тем самым имитируется
задержка между нажатиями клавиш в процессе ввода текста.
Любой текстовый эффект строится по тому же принципу:
• определяется задержка на вывод одного знака и изменяются одного или не-
сколько свойств каждой буквы;
• в конце задержки измененному свойству присваивается окончательное зна-
чение, завершающее эффект;
• происходит переход к следующей букве.
Для создания эффекта пишущей машинки свойству visible задается значение
false, в результате чего все буквы изначально невидимы. При истечении задерж-
ки код typewriter) делает текст снова видимым. На рис. 6.31 показан эффект
пишущей машинки в действии. Программа с небольшой задержкой открывает
каждую букву в последовательности.
Текстовые эффекты, контролируемые по времени 243

This is a

This is a text ef

This is a text effect.

Рис. 6 . 3 1 . Эффект пишущей машинки в действии

Итоги
Эффект пишущей машинки наглядно показывает, что многие эффекты строятся
по одному образцу. Кроме того, в программе продемонстрированы важные ас-
пекты любых текстовых эффектов - задержка, выбор шрифта и звуковое сопро-
вождение. Без звука и задержки между выводом букв эффект будет выглядеть
отнюдь не так убедительно. Кстати говоря, моноширинный шрифт сделает ил-
люзию еще более полной.
Реализация многих текстовых эффектов требует тщательного подбора времен-
ных интервалов, звуков и шрифтов. Например, скрип мела по доске в сочетании
с подходящим шрифтом может использоваться для создания «рукописного»
эффекта (каждая буква может представлять собой анимированный клип, рисую-
щий букву несколькими штрихами).

Текстовые эффекты, контролируемые


ТРЮК

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

Эффект поднимающихся букв


В этом эффекте текст постепенно «поднимается» из горизонтального положения.
Как и в других текстовых эффектах, задача решается постепенным изменением
свойств клипа. В данном случае изменяется свойство _yscale (масштаб по верти-
кальной оси). Изначально свойство равно 0, то есть текст остается невидимым
(не имеет высоты). Вместо немедленного изменения свойства, как это делалось
при реализации эффекта пишущей машинки (см. трюк 49), переход осуществляет-
ся постепенно с применением обработчика onEnterFrame(). Когда свойство _yscale
достигает окончательного значения (100%), обработчик onEnterFrame удаляет себя.
244 Глава 6. Текст

Программа
Следующий листинг показывает, как реализовать плавный эффект «выраста-
ния» букв посредством постепенного изменения их свойств в обработчике
onEnterFrame. Функция placeText() тоже была модифицирована по сравнению
с предыдущим трюком (см. трюк 49): в новом варианте ей передается имя
выполняемой функции и величина задержки, что упрощает ее повторное ис-
пользование для- других эффектов. Предполагается, что динамическое текстовое
поле letter находится в клипе с именем экземпляра field. Итоговая версия нахо-
дится в файле standup.fla на сайте книги. Важные фрагменты выделены жирным
шрифтом,
function standUpCtarget :Movi eCl ip. del ay: Number)-.Void {
target.interval = functionO {
clearInterval(target.interval ID);
this.onEnterFrame = functionO {
target._yscale += 10;
if (target._yscale > 95) {
delete this.onEnterFrame;

}
target.interval ID = setlnterval(target, "interval", delay);
target._yscale = 0;
}
function placeText(target:MovieClip, x:Number, y:Number.
banner:String. tFormat:TextFormat.
effectFunction:Function, del ay:Number):Void {
II Для каждого знака...
for (var i = 0: i<banner.length; i++) {
// Создать клип и поместить текущий символ в текстовое поле,
var chanMovi eCl ip = target.attachMovieC'letter", "char"+i.
target.getNextHighestDepthО);
char.field.text = banner.substr(i. 1);
char._x = x;
char._y = y;
// Прибавить ширину текущего знака к позиции х следующего знака.
х += tFormat.getTextExtent(char.field.text).width;
//
// Вызов функции эффекта, передаваемой в виде параметра.
effectFunction(char, i*delay);

узг format:TextFormat = new TextFormatO;


format.font = "Aria!":
format.size = 24;
placeTextUhis. 100. 100. "This is a text effect", format. standUp. 100);
На рис. 6.32 показан эффект поднимающихся букв в действии. Эффект изменя-
ет высоту каждого символа от 0 до 100 % от исходного размера.
Текстовые эффекты, контролируемые по времени 245

This is

T h i s is a text e f f _

T h i s is a text effect
Рис. 6.32. Эффект поднимающихся букв в действии

Эффект падения
Изменяя другие свойства (и/или сразу несколько свойств одновременно), мож-
но создавать переходы, визуально отличающиеся друг от друга, но работающие
на сходном коде. Чтобы создать эффект падения, мы постепенно изменяем свой-
ство _у - создается впечатление, что буквы падают на свое место в последова-
тельности. Также в начале падения каждой буквы свойство visible задается рав-
ным true, чтобы буква была видна на экране.
Чтобы падение выглядело более естественно, выделенная жирным шрифтом стро-
ка создает иллюзию инерции. Функция placeTextQ в листинге не приводится -
она не изменилась по сравнению с предыдущим примером. Как и прежде, пред-
полагается, что динамическое текстовое поле letter находится в клипе с именем
экземпляра field. Итоговая версия находится в файле drop.fla на сайте книги.
// Код ActionScript 2.0
function dropCtarget :MovieCl i p . del ay: Number)-.Void {
target.interval = functionO {
target._vi sible = true:
clearInterval(target.interval ID);
target.onEnterFrame = functionO {
target._y -= (target._y-target.startY)/3:
i f (Math.abs(target._y-target.startY)<l) {
target._y = target.startY:
delete target.onEnterFrame:

}
target.interval ID = setlnterval(target, "interval", delay):
target.startY = target._y:
target._y = 0;
target._visible = false:
}
var format:TextFormat = new TextFormatO;
format.font = "Arial":
format.size = 24;
placeText(this. 100. 100. "This is a text effect", format, drop. 100);
На рис. 6.33 показан эффект падения в действии. Буквы поочередно появляются
с небольшой задержкой, а затем «падают» на положенное место.
24G Глава 6. Текст

X
e
T h i s is a t

T h i s is a t e x t

T h i s is a t e x t e f f e c t

Рис. 6.33. Эффект падения в действии

Проявление с масштабированием
Вероятно, наибольшую известность из всех текстовых эффектов получил эф-
фект постепенного проявления с масштабированием. Он прославились благода-
ря сайту theVoid (http://www.thevoid.co.uk).
Этот эффект основан на постепенном изменении свойств _xscale, _yscale и _alpha,
но программная реализация остается практически такой же, как прежде. При из-
менении всех свойств имитируется эффект инерции (соответствующий фрагмент
листинга выделен жирным шрифтом). Функция placeTextO в листинге не приводит-
ся - она не изменилась по сравнению с предыдущим примером. Как и прежде,
предполагается, что динамическое текстовое поле letter находится в клипе с име-
нем экземпляра field. Итоговая версия находится в файле fadein.fla на сайте книги.
function fadeZoom(target:MovieClip. del ay:Number):Void {
target .interval = functionO {
target._visible = true;
clearlnterval(target.interval ID);
target.onEnterFrame = functionO {
target._xscale -= (target._xscale-100)/3;
target._yscale -= (target._yscale-100)/3;
target._alpha -= (target._alpha-100)/3:
i f (Math.abs(target._xscale-100)<l) {
target._xscale = 100;
target._yscale = 100;
target.alpha = 100:
delete target.onEnterFrame:

}
target.interval ID = setlnterval(target, "interval", delay);
target._xscale = 2000:
target._yscale = 2000;
target.„alpha = 0;
Текстовые эффекты, контролируемые по времени 247

var format:TextFormat = new TextFormatO;


format.font = "Arial";
format.size = 24;
placeText(this. 100. 200. "This is a text effect", format. fadeZoom. 100);
На рис. 6.34 показан эффект проявления с масштабированием в действии. Хотя
эффект выглядит более сложным, чем в предыдущих примерах, базовый прин-
цип не изменился - мы изменяем сразу несколько свойств со временем.

Thisj

This is a text

T h i s is a t e x t e f f e c t

Рис. 6.34. Эффект проявления с масштабированием в действии

Чтобы эффект был симметричным, переместите текстовое поле в клипе letter


(при помощи инструмента Selection) так, чтобы точка регистрации клипа нахо-
дилась в середине левой стороны текстового поля, как показано на рис. 6.35.

m m

Рис. 6.35. Перемещение точки регистрации делает эффект проявления симметричным

Итоги
После того как мы написали универсальную заготовку для построения тексто-
вых эффектов, в дальнейшем разнообразные текстовые эффекты строятся по
принципу изменения свойств во времени. Либо придумайте свой эффект и реа-
лизуйте его, либо выберите свойство (или комбинацию свойств), попробуйте
изменить его и посмотрите, что из этого выйдет.
В интерактивном генераторе текстовых эффектов пользователю нужно предоста-
вить возможность ввода текста и изменения параметров - таких, как амплитуда
248 Глава 6. Текст

или скорость эффекта. Попробуйте создать пару библиотек: умеренные эффек-


ты для деловых презентаций, а эксцентричные - для модных веб-сайтов.

Текстовые эффекты с применением


ТРЮК

№81 морфинга
Некоторые текстовые эффекты реализуются только с применением мор-
финга. Для создания эффектов такого рода применяется редко исполь-
зуемый, но очень полезный инструмент Envelope.
Ранее уже рассматривались способы создания сценарных текстовых эффектов
(см. трюк 50). Тем не менее, текстовые эффекты ActionScript ограничиваются
созданием анимации за счет изменения свойств клипа со временем. Данная раз-
новидность анимации позволяет изменять позицию, прозрачность, цвет, ориен-
тацию и масштаб текста, но ActionScript не способен создавать сложные анима-
ции с изменением геометрической формы текста. Чтобы решить эту задачу,
необходимо преобразовать текст в низкоуровневые векторные фигуры и рабо-
тать с ними, как с графическими примитивами.
Перспектива выполнения низкоуровневых операций с множеством фигур вы-
глядит устрашающе, но в этой ситуации нам пригодится очень полезный инст-
румент Envelope. Большинство дизайнеров забывает о нем, однако этот инстру-
мент позволяет быстро применять эффекты к набору букв способом, который не
удастся легко реализовать на сценарном уровне.

Разбиение текста
Прежде чем приступать к редактированию текста в виде векторных фигур, его
необходимо преобразовать в векторную форму - в Flash этот процесс называет-
ся разбиением (breaking apart). Создайте текст при помощи инструмента Text, a
затем, не снимая выделения с текста, дважды выполните команду Modify • Break
Apart. Первая команда Break Apart разбивает текстовое поле на несколько тексто-
вых полей (по одному на каждую букву), а вторая разбивает буквы на вектор-
ные контуры.

ПРИМЕЧАНИЕ
После того как текстовое поле будет преобразовано в серию векторных конту-
ров, отредактировать текст напрямую уже не удастся. Проверьте правописание
перед тем, как осуществлять разбиение!

Инструмент Envelope
Выделите все буквы в тексте инструментом Selection, активизируйте инстру-
мент Free Transform. В области параметров этого инструмента (в нижней части
панели Tools) выберите значок Envelope. Примерный вид текста показан на
Текстовые эффекты с применением морфинга 249

рис. 6.36; обратите внимание на ограничивающий прямоугольник, в который


заключена надпись.

Рис. 6.36. Разбитый текст выделен при помощи инструмента Envelope

Возможно, вы не сразу разберетесь в том, как работать с ограничивающим пря-


моугольником, потому что по его периметру расположено множество непонят-
ных маркеров. В действительности маркеры делятся на два типа: квадратные
представляют контрольные точки, а круглые - концы управляющих векторов,
определяющих угол входа огибающей в контрольную точку. Получается, что
каждому квадратному маркеру соответствуют два круглых. Чтобы лучше раз-
глядеть контрольные точки, попробуйте временно затемнить фон (рис. 6.37). Цвет
фона задается командой Modify • Document (выделение с огибающей при этом
не снимается).

Рис. 6.37. Затемнение фона помогает различить два типа маркеров на огибающей

Перемещение контрольных точек изменяет общую форму огибающей, при этом


внутренний текст деформируется в соответствии с новой формой, как показано
на рис. 6.38. ,

Рис. 6.38. Перемещение контрольной точки

Изменение направления или длины управляющих векторов, связанных с кон-


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

точек, форма текста автоматически подгоняется под форму огибающей, как по-
казано на рис. 6.39.

Рис. 6.39. Перемещение управляющего вектора

Модификация огибающей придает тексту желаемую форму. Хотя текст состоит


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

Рис. 6.40. Изменение формы и/или ориентации текста


применением инструмента Envelope

Пара замечаний о работе с инструментом Envelope:


• если щелкнуть в любой месте, кроме контрольной точки или управляющего
вектора, выделение огибающей снимается;
• при снятии выделения форма огибающей не запоминается. Например, если
снять выделение с огибающей, показанной на рис. 6.40, то повторное выделе-
ние не вернет ее к прежней криволинейной форме. Вместо этого огибающая
будет выглядеть как прямоугольник, ограничивающий изогнутый текст. Иногда
это сильно раздражает, потому что даже отмена операции (Ctrl+Z или §€+Z)
не восстанавливает исходную форму огибающей.
Несмотря на эти недочеты, инструмент Envelope позволяет очень быстро реали-
зовать морфинг текста (см. трюк 34), как показывает серия изображений на
рис. 6.41. Определяя в ключевых кадрах измененные формы текста, мы почти
мгновенно создаем естественную «пульсирующую» анимацию.
Текстовые эффекты с применением морфинга 251

:!
10 1; 23 •-••:•
'.:

;
]J S • IS 13 2S

Г ЪШШ Ш$

Рис. 6 . 4 1 . Создание морфинга с использованием инструмента Envelope

Итоги
Некоторые анимации не удается легко создать.средствами ActionScript - в та-
ких случаях лучше всего прибегнуть к редактированию текста в векторной фор-
ме. Если править форму каждой буквы по отдельности, задача окажется весьма
трудоемкой. Мощный (хотя и не прощающий ошибок пользователя) инстру-
мент Envelope позволяет работать с несколькими буквами, как с единым целым.
В этом трюке показано, как организовать постепенное изменение формы текста.
Если вам потребуется создать более сложный морфинг, попробуйте отредакти-
ровать текст во внешнем векторном редакторе (таком, как Freehand или Illustrator
или даже в одной из последних версий Photoshop) и импортировать графику
в Flash командой File • Import.
Г Л А В А

Работа со звуком
Трюки № 52-60
На собственном опыте знаю, что многие веб-дизайнеры разделяют распростра-
ненное заблуждение по поводу звука. Это заблуждение можно сформулировать
примерно так:«Я не профессиональный художник, но это не мешает мне рисо-
вать картинки и строить симпатичные веб-сайты. Я не музыкант, и это мешает
мне создавать звуки и музыку для моих сайтов».
Такой подход годится для дизайнера HTML-сайта, которому практически не
приходится работать со звуком, но когда вы имеете дело с анимацией в Веб,
отсутствие звукового сопровождения оборачивается крупным недостатком. Звук
является одним из важнейших аспектов анимации и интерактивности. Попро-
буйте поработать на Flash-сайте с отключенным звуком или поиграть в Quake
на 20% громкости. Получается совсем не то!
Помимо создания собственных звуковых файлов есть и другой путь - приобре-
сти компакт-диск с готовыми звуковыми материалами. Однако содержимое та-
ких дисков обычно делится на две категории: «используется повсеместно и всем
надоело» или «настолько дико, что никто не захочет слушать».
К сожалению, поддержке звука в области веб-дизайна еще не уделяется должно-
го внимания. Все мы знаем, как оптимизировать растровое изображение для Веб
без создания лишних неровностей контуров или нежелательной зернистости/
цветового шума, но оптимизация звука редко выходит за пределы назначения
частоты оцифровки МРЗ при экспортировании с целью уменьшения размеров
файла. Однако в технологии оптимизации звука тоже присутствуют свои «не-
ровности» и «шумовые эффекты» (шум оцифровки). Вы должны знать о них,
чтобы добиться оптимального соотношения «размер файла/качество».

ПРИМЕЧАНИЕ
Звуковые данные загружают канал связи интенсивнее, чем остальные со-
ставляющие ролика (за исключением разве что видеоданных), поэтому очень
важно, чтобы звук был как можно лучше оптимизирован в любом веб-содер-
жании;

Итак, основной темой настоящей главы станут трюки, позволяющие создавать


звуковое оформление для Flash без использования готовых компакт-дисков (обыч-
но очень дорогих) и без воспитания выдающихся музыкальных способностей.
Создание синтезатора речи 253

Также мы рассмотрим некоторые проблемы, из-за которых звук в Flash работает


не так, как описано в документации (в прошлом эти проблемы отбили у многих
дизайнеров всякое желание экспериментировать со звуком).
Заодно будут представлены некоторые трюки из области работы со звуком. Соб-
ственно, эти приемы названы «трюками» только из-за своей нестандартности -
например, методика голосового ввода и вывода на базе Flash.
Во многих функциях создания сложных звуковых эффектов задействованы пос-
ледние усовершенствования Flash (например, класс Microphone и более тонкие
возможности вроде повышения точности хронометража и общей стабильности
Flash Player). А это означает, что некоторые из представленных звуковых трю-
ков будут работать только в последних версиях Flash.

ТРЮК Создание синтезатора речи


№52 Синтез речи повышает гибкость реализации без увеличения объема пе-
редаваемых данных — отпадает необходимость в предварительной за-
писи или приеме заранее записанных звуков.
В этом трюке события Flash используются для объединения звуковых фрагмен-
товх и имитации эффекта одного непрерывного звука - в данном случае синте-
зированной речи с применением аллофонов (фонетических речевых единиц, из
которых строятся произносимые слова).

Проблема лазера
В основу многих трюков заложено нестандартное применение стандартных при-
емов и технологий. История науки полна примеров неожиданного применения
технологий - например, лазеров. Мало кто мог предположить, что лазеры будут
использоваться во всех областях, от военного дела до хирургии, от прослушива-
ния музыки и просмотра фильмов до ведения международных телефонных пе-
реговоров.
Давайте посмотрим, как использовать тривиальное на первый взгляд событие
onSoundComplete для построения синтезатора речи в Flash.

Событие Sound.onSoundComplete
Как только в Flash MX появился метод Sound.onSoundComplete(), я сразу же
подумал: «Здорово! Теперь звуки можно легко и точно синхронизировать, и я
смогу создать виртуальный микшерный пульт». И это действительно так - точ-
ность события onSoundComplete на порядок превышает частоту смены кадров,
поэтому оно гораздо точнее решения с ключевыми кадрами и onEnterFrame, при-
менявшегося в Flash 5.
События onSoundComplete, как и любые другие события, могут задерживаться
из-за большого количества параллельных вычислений, особенно анимации,

Здесь и далее под «фрагментами» имеются в виду samples. — Примеч. перев.


254 Глава 7. Работа со звуком

интенсивно расходующей ресурсы процессора. Чрезмерная нагрузка на Flash


Player приведет к задержкам при воспроизведении, так что не перестарайтесь!
Взгляните на следующий фрагмент, позаимствованный из файла groovyL.oop.fla,
размещенного на веб-сайте книги:
function nextSoundO {
myLoop.start О;
}
myLoop = new Sound(this);
myLoop.attachSound("groovy"):
myLoop.start О;
myLoop.onSoundComplete = nextSound:
Чтобы этот код работал, на панели Library должен присутствовать файл с иден-
тификатором компоновки groovy. Данное требование является стандартным при
работе со звуком на сценарном уровне, однако именно с его нарушением связано
большинство неудач при воспроизведении звука. Выполните следующие дей-
ствия:
1) после импортирования звукового файла в Flash (команда File • Import • Import
to Library) щелкните на ресурсе на панели Library правой кнопкой мыши
(Windows) или щелкните с нажатой клавишей §€ (Мае). Выберите в открыв-
шемся контекстном меню команду Linkage;
2) в диалоговом окне Linkage Properties (рис. 7.1) введите в поле Identifier иден-
тификатор компоновки groovy. Вообще говоря, идентификатор может быть
произвольной строкой, но не выбирайте его слишком длинным, сложным или
трудно запоминаемым, потому что точно такой же текст нужно будет повто-
рить в программе (заключив его в кавычки);

Export infiist frame

Рис. 7 . 1 . Окно Linkage Properties с определением идентификатора компоновки groovy

3) установите флажок Export for ActionScript. При этом флажок Export in First Frame
автоматически устанавливается и становится доступным. Оставьте его уста-
новленным.
В процессе компиляции SWF Flash проводит поиск по всем временным диаграм-
мам и проверяет порядок присоединения всех символов. На основании получен-
ных результатов упорядочивается содержимое SWF-файла. Далее при пересыл-
ке SWF через Веб символы загружаются в Flash Player в порядке использования.
Создание синтезатора речи 255

Символы, подключаемые к временным диаграммам только на сценарном уров-


не, на стадии компиляции не видны, поэтому по умолчанию Flash не включает
их в SWF, предполагая, что они нигде не используются. Установка флажков
Export for ActionScript и Export in First Frame отменяет это правило по умолчанию;
фактически, вы говорите Flash: «Эти символы будут использоваться в сценари-
ях, поэтому их нужно включить в SWF».
Однако при этом Flash Player вынужден загружать звук еще до того, как кадр 1
появится на экране. Более грамотное решение - поместить звук в анимацион-
ный клип и запретить его немедленное воспроизведение командой Sound.stop().
Затм клип помещается в кадр главной временной диаграммы, в который требу-
ется экспортировать звук (то есть кадр, предшествующий использованию зву-
ка). Впрочем, не будем отвлекаться - предварительная загрузка звука выходит
за рамки основной темы трюка.
В предыдущем листинге groovyLoop.fIa звук с идентификатором компоновки groovy
присоединен к экземпляру Sound с именем myLoop. По завершении воспроизве-
дения текущего звука при обработке события onSoundComplete вызывается фун-
кция nextSound(), которая снова включает воспроизведение. Так чего же мы до-
бились? Того же эффекта можно было добиться и проще:
myLoop = new Sound(this):
myLoop.attachSound("groovy");
myLoop.start(0. 1000);
Метод Sound.start() в цикле воспроизводит звук groovy 1000 раз. Однако глав-
ным преимуществом события onSoundComplete является его динамический ха-
рактер. Функция обратного вызова (в данном случае nextSound()) может вы-
брать другой звук и запустить его после воспроизведения текущего звука. Таким
образом создаются динамические звуковые дорожки, содержимое которых изме-
няется в интерактивном режиме или на основании результатов обработки дру-
гих событий. Мы не будем слишком подробно рассматривать этот процесс, так
как он вполне стандартен и не может считаться частью трюка. Для достижения
желаемой цели будет использовано несколько неожиданное свойство хорошо
известного процесса.

Синтез речи и Flash


Так уж получилось, что я впервые узнал о событии onSoundComplete в то вре-
мя, когда занимался специализированными программами для слабовидящих
(в частности, преобразующими веб-содержимое в голосовой поток). Программы
были действительно замечательные, но «весили» более 10 Мбайт - а ведь в те
времена, когда мы возились с приставками Commodore 64 и Atari, программа
синтеза речи занимала около 32 Кбайт. Фокус был основан на использовании
отдельных фонетических единиц, называемых аллофонами, - таких, как звук
«ои» в слове «you» или «th» в «the». Я заподозрил, что программы синтеза речи
на старых 64-килобайтных компьютерах каким-то образом комбинировали ал-
лофоны при помощи чего-то наподобие onSoundComplete. И уж во всяком слу-
чае, для решения этой задачи 10 Мбайт было слишком много. Так мне пришла
в голову мысль о создании этого трюка.
256 Глава 7. Работа со звуком

Хотя сейчас мало у кого остались 8-разрядные компьютеры, в Интернете можно


найти множество программных эмуляторов. В результате поиска по ключевым
словам «8-bit emulation» или «8-bit emulation allophone» в моей любимой поис-
ковой системе (http://vivisimo.com) обнаружилось множество сайтов, посвящен-
ных эмуляторам. Многие эмуляторы позволяют эмулировать устройства рече-
вого синтеза, существовавшие для тех систем.

С точки зрения фонетики


Импортировать аллофоны в Flash было проще простого. При помощи Adobe
Audition (звуковой редактор) я:
• удалил все пропуски, не содержащие звука, в начале и конце каждого фраг-
мента;
• удалил щелчки в начале и конце фрагментов (применяя эффекты нарастания
и затухания звука);
• нормализовал все фрагменты, чтобы они имели одинаковую громкость и мощ-
ность сигнала;
• оптимизировал фрагменты для использования в Веб.
В результате образовалась библиотека синтезированных голосовых фрагментов,
каждому из которых были присвоены имя и идентификатор компоновки, иден-
тичный одному из аллофонов (рис. 7.2). Если вы не готовы повторить этот труд,
загрузите файл speechfinal.fla с импортированными аллофонами с сайта книги.

*?ЩШШШ

Mame
Sound Export: a £

Sound
Ш
Sound
Export: aa
Sound
Export: aer
•J; ay Export: ar
Sound Export; b
Sound Export: bb
Sound Export: с
Sound Export: ch
4$ ck Sound Export: dc

Рис. 7.2. Панель Library со звуковыми файлами аллофонов


Создание синтезатора речи 257

Старые 8-разрядные синтезаторы речи не преобразовывали традиционное написа-


ние в фонетический текст. Например, чтобы синтезатор произнес слово «know-
ledge», надо было запросить у него фонетический эквивалент - например, «nnolej»
или нечто похожее. Программа писалась в демонстрационных целях, поэтому я
ограничился написанием фонетического синтезатора речи. Если хотите просла-
виться, попробуйте создать программу преобразования традиционного написа-
ния в фонетическое произношение (начните с технических статей по лингвистике,
которые можно найти в Веб).
Итак, я присоединил простой код обработки строк в приведенному ранее коду
вывода звука. Полученная программа берет строку, образованную из аллофо-
нов, и преобразует ее в простую очередь, обслуживаемую функцией косвенного
вызова onSoundCompleteQ:
makePhrase = function () {
i f (soundCount<soundMax) {
soundCount++;
speech.attachSound(aPhones[soundCount]);
speech. startO:
} else {
delete speech.onSoundComplete;

}
function say(phrase) {
var i = j=0:
aPhones = new ArrayO:
aPhones[0] = "":
for (i=0; i<phrase.length; i++) {
i f (phrase.charAt(i) != "|") {
aPhones[j] += phrase.charAt(i)
i f (phrase.charAt(i) == " ") {
aPhones[j] = "space";
}
} else {
a Phones[++j] = "";

speech.attachSound(aPhones[0]);
speech. startO;
speech.onSoundComplete = makePhrase:
soundCount = 0;
soundMax = j - 1 :
}
function soundlnitO {
speech = new Sound(this):
}
soundlnitO;
say("h|e|ll|oo| | | | | |h|ow| |ar| |y|ouu| | | | |tt|u|d|ay|");
stopO;
К сожалению, имена некоторых аллофонов слишком похожи, что затрудняет их
выделение из строки. Например, сочетание «ооо» можно записать в виде «о о о»,
«о оо», «оо о», и все варианты будут звучать по-разному. В программе аллофоны
258 Глава 7. Работа со звуком

разделяются символом |. «Чистый» программист переименовал бы аллофоны


в «ol» и «о2», чтобы эта проблема вообще не возникала, но мой внутренний
дизайнер воспротивился такому решению, потому что оно затрудняет ручное
построение фонетических строк - «у|оо» выглядит понятнее, чем «у|о2».
Предположим, программа должна произнести слово «hello». Первая строка при-
водит синтезатор в движение: она передает произносимый текст в виде строко-
вого аргумента с фонетическим произношением функции say():
say("h|e|ll|oo|");
Функция say() создает новый массив, который заменяет существующий массив
с тем же именем, поэтому стирать данные, оставшиеся от предыдущих вызовов
функции, не нужно. По переданной строке массив аллофонов заполняется сле-
дующим образом:
aPhonesCO] = "h"
aPhones[l] = "е"
aPhones[2] = "11"
aPhones[3] = "oo"
Затем мы связываем первый звук «h» с экземпляром Sound, после чего при по-
мощи события onSoundComplete последовательно присоединяем звуки «е», «11»
и «оо» по мере завершения очередного аллофона. Задача решается функцией
makePhrase(), которая подключает следующий звуковой файл к последователь-
ности аллофонов aPhones до тех пор, пока не будут озвучены все элементы мас-
сива. Просто, не правда ли? У нас получился классный эффект «компьютерного
голоса» из старого научно-фантастического фильма. Чтобы прослушать резуль-
тат, запустите ролик speech_final.fla.
Напоследок стоит упомянуть об одном «трюке внутри трюка»: обратите внима-
ние - мы используем всего один экземпляр Sound вместо того, чтобы использо-
вать по одному экземпляру на каждый звуковой файл, что привело бы к увели-
чению объема кода и появлению лишних циклов for. Это возможно благодаря
тому, что метод Sound.attachSoundQ можно вызывать столько раз, сколько по-
требуется, а работает он довольно быстро. Программист, имеющий опыт работы
со звуком в Flash, увидит два интересных побочных эффекта:
• достаточно создать только одну функцию обратного вызова для onSoundComplete
вместо того, чтобы создавать по одной функции для каждого экземпляра Sound;
• Flash поддерживает восемь звуковых каналов, но в обычной ситуации рабо-
тать с отдельными каналами невозможно. Flash распределяет каналы автома-
тически, но при сложном управлении звуком из сценария это может оказать-
ся нежелательно. Вместо этого можно создать восемь экземпляров Sound
(channelO- channel7), а затем перераспределить звуки для динамического вос-
произведения на каждом экземпляре методом Sound.attachSoundQ. В резуль-
тате вы получите восемь экземпляров Sound, напрямую соответствующих
восьми звуковым каналам.

Итоги
Синтезатор речи на базе Flash выглядит особенно впечатляюще, потому что весь
механизм синтеза реализован в SWF-ролике - никакие внешние модули им не
Говорящий аватар 259

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


синтеза речи (например, Windows-Eyes от GW Micro - http://www.gwmicro.com),
для их работы необходим класс Accessibility, использующий Windows ActiveX.
Наш синтезатор прекрасно работает в любой системе с полноценной поддерж-
кой звуковых возможностей Flash Player.
Более того, в написанной вами программе пользователь вообще может не смот-
реть на экран (представьте себе карманный компьютер, который говорит: «На-
поминаю: вы записаны на прием к зубному врачу на 10 часов»). Наконец, даром
речи можно наделить устройства с маленькими экранами, чтобы вторичная ин-
формация вроде справочного текста не загромождала полезную площадь.
Не стоит полагать, что синтез речи пригодится только пользователям с дефекта-
ми зрения, - он открывает новые горизонты в организации диалога Flash с пользо-
вателем. Сколько новых областей применения вы найдете на этом горизонте?

ТРЮК Говорящий аватар


№53 Синхронизация анимации головы с синтезатором речи.

Завершив работу над синтезатором речи (см. трюк 52), я показал его Адаму
Филипсу. Через несколько дней Адам нарисовал подходящего персонажа-робо-
та по имени Чарли (рис. 7.3).

Рис. 7.3. Робот Чарли


260 Глава 7. Работа со звуком

Адам также предоставил полный набор изображений рта для синхронизации


изображения со звуком (рис. 7.4). Многие изображения используются сразу не-
сколькими аллофонами. Например, символ JShCh используется при отображе-
нии трех аллофонов: «j», «sh» и «ch».

Рис. 7.4. Полный набор форм рта для английского языка

На следующем этапе каждому из 77 аллофонов ставится в соответствие одна


из 13 форм рта; при наличии этой информации сценарий после распознавания
аллофона сможет отобразить нужное изображение.
Сначала я разместил все 13 изображений в виде ключевых кадров на экземпляре
клипа с именем mouth (рис. 7.5).
Затем был создан массив, устанавливающий соответствие между номерами кадров
клипа mouth и именами аллофонов. Вместо того чтобы создавать отдельный эле-
мент для каждого аллофона, я создал отдельный элемент для каждой формы рта.
Почему? Да потому что форм рта гораздо меньше, чем аллофонов (13, а не 77).
При этом использовалась методика ускоренного поиска в массиве (см. трюк 79).
Говорящий аватар 261

Рис. 7.5. Временная диаграмма клипа mouth

Сначала мы создаем массив строк, по одной для каждой формы рта. Каждая
строка содержит все аллофоны, связанные с данной формой. Аллофоны допол-
няются пробелами с обеих сторон, чтобы «аег» молено было отличить от «г».
var shapes = new АггауО;
// Определение массива форм рта с соответствующими аллофонами.
shapesCO] = " space ";
shapes[l] = " b bb m p ";
shapes[2] = " a aer ay ее er err i ii ";
shapes[3] = " aa ";
shapes[4] = " г ";
shapes[5] = " о ";
shapes[6] = ' or ow oy ":
shapes[7] = ' 00 ou ouu w wh ";
shapes[8] = ' ck d dd dth g gg h hh n ng nn s t tt z zh ";
shapes[9] = ' с e ear k у уу ";
shapes[10] = " f u uh ";
shapes[ll] = 11 Ch sh j ";
shapes[12] = 1 1 11 ";
shapes[13] = th ";
Функция mouthAnim() ищет строку аллофона (например, «th») в массиве shapes.
Затем по номеру найденного элемента происходит переход к кадру клипа mouth,
содержащего наиболее подходящую форму рта. Первая форма находится в кад-
ре 10, вторая - в кадре 20 и т. д. Чтобы лучше понять, как работает алгоритм,
снимите комментарии с команды трассировки (выделенной жирным шрифтом)
при запуске FLA.
262 Глава 7. Работа со звуком

function mouthAnim(phone) {
for (var i = 0; i<shapes.length; i++) {
i f (shapes[i].indexOf(" "+phone+" ") != -1) {
// trace(phone + " found in "+ shapes[i]);
mouth.gotoAndStop((i+l)*10);
break;

Изменения программного кода по сравнению с синтезатором речи (см. трюк 52)


выделены жирным шрифтом:
makePhrase = function О {
i f (soundCount < soundMax) {
soundCount++;
speech.attachSound(aPhones[soundCount]);
mouthAnim(aPhones[soundCount]);
speech. startO;
} else {
delete speech.onSoundComplete;

}
function say(phrase) {
var i = j = 0;
aPhones = new ArrayO;
for (i = 0 ; i < phrase.length; i++) {
i f (phrase.charAt(i) != "|") {
aPhones[j] += phrase.charAt(i);
i f (phrase.charAt(i) == " ") {
aPhones[j] = "space":
}
} else {

speech.attachSound(aPhones[0]);
mouthAnum(aPhones[0]);
speech.startO;
speech.onSoundComplete = makePhrase:
soundCount = 0;
soundMax = j-1;
}
function mouthAnim(phone) {
for (var i = 0 ; i<shapes.length; i++) {
if (shapes[i].indexOf(" "+pnone+" ") !- -1) {
// trace(phone + " found in "+ shapes[i]);
mouth.gotoAndStop((i+l)*10);
break;
Синхронизация событийных звуков 263

var speech = new Sound(this):


var shapes = new ArrayO;
shapes[0] = " space ";
shapes[l] = b bb m p ";
shapes[2] = a aer ay ее er err i i i ";
shapes[3] = aa ";
shapes[4] = г ":
shapes[5] = о ";
shapes[6] = or ow oy ";
shapes[7] = 00 ou ouu w wh ";
shapes[8] = ck d dd dth g gg h hh n ng nn s t t t z zh
shapes[9] = с e ear к у yy ";
1
shapes[10] = " f u uh ";
1
shapes[ll] = " ch sh j ";
1
shapes[12] = " 1 11 ";
1
shapes[13] = " t h ";
say("h1e111 |oo |h|ow| |a r| |y|ouu| |tt|u|d|ay| I"):
stopO;
Синхронизировать движения рта с анимацией можно в приложении Poser
(см. трюк 32). Вероятно, вам придется приобрести для этого отдельное приложе-
ние - Mimic от фирмы Daz (http://www.daz3d.com). При наличии такого инстру-
ментария вы сможете создавать анимированных говорящих персонажей/авата-
ров или опорные изображения, упрощающие работу над ключевыми кадрами
анимации. Хорошим примером профессионального приложения с говорящими
аватарами служит Oddcast (http://www.oddcast.com).

ТРЮК Синхронизация событийных звуков


№54 Исправление ошибки синхронизации в Flash.

При синхронизации звука с ключевыми кадрами в Flash возникают серьезные


проблемы. Выражаясь точнее, такой синхронизации попросту не существует.
Событийные звуки, полностью загружаемые перед воспроизведением (обычно
это делается лишь с короткими звуками, хранящимися в памяти на случай по-
вторного использования), начинаются с ключевого кадра, с которым они были
связаны; но предсказать, на каком кадре они закончатся, очень трудно. Напри-
мер, если запустить звук продолжительностью 1 с на временной диаграмме с
частотой 12 fps, то вероятность завершения звука ровно через 12 кадров близка
к нулю.
Данная «особенность» создает основательные трудности, если вы хотите создать
непрерывную серию звуков, связанных с ключевыми кадрами. Если точный но-
мер кадра, в котором закончится звук, является переменной величиной, вы не
сможете определить, с какого кадра должен начинаться следующий звук. Пред-
положим, имеются два звуковых файла, song01.wav и song02.wav, которые при
последовательном воспроизведении создают единую музыкальную тему.
Для точного слияния фрагментов продолжительность звуков должна быть крат-
на частоте смены кадров. В противном случае продолжительность звука следует
264 Глава 7. Работа со звуком

изменить (см. трюк 57) в каком-либо звуковом редакторе (например, Sony Acid,
Adobe Audition или Audacity). Чтобы слияние звуков происходило без пауз и на-
ложений, необходимо как избавиться от ошибки синхронизации, так и сделать
звуки кратными частоте смены кадров.
Если разместить на временной диаграмме два звуковых файла так, чтобы один
файл останавливался непосредственно перед началом другого, можно предполо-
жить, что переход между звуками в Flash будет плавным. Однако в действитель-
ности этого не происходит из-за упомянутой ошибки.

Рис. 7.6. Смежное размещение двух звуков не гарантирует


слитности их воспроизведения

Хотя левый звук завершается до того, как начнется воспроизведение правого,


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

1; S К

io
п
У~1 »
Рис. 7.7. Размещение потокового звука на временной диаграмме
для обеспечения синхронизации

Удалите с этого слоя все кадры, следующие за кадром 5. Не снимая выделения


с ключевого кадра, сделайте этот звук потоковым (выберите строку Stream в рас-
крывающемся списке Sync на панели свойств).
Наконец, щелкните на кнопке Edit на панели свойств и уменьшите громкость
потокового звука до нуля при помощи контрольных точек Volume Envelope
(рис. 7.8).
В результате получается потоковый звук с нулевой громкостью, продолжитель-
ность которого составляет 1 кадр. Благодаря ему механизм обработки звука Flash
Player считает, что временная диаграмма содержит потоковый звук, и начинает
Преобразование монофонического звука в стереофонический 265

синхронизировать все звуки (в том числе и событийные) на временной диаграм-


ме. Тестирование показывает, что прежде не синхронизированные звуки воспро-
изводятся практически безупречно. Это позволяет создавать более предсказуе-
мые и надежные звуковые переходы.

Effect: Custom OK
Cancel

Рис. 7.8. Управление громкостью звука

Итоги
Из-за невозможности синхронизации событийных звуков многие дизайнеры счи-
тают, что в Flash со звуком вообще невозможно сделать что-то серьезное (осо-
бенно до выхода Flash MX и появления события Sound.onSoundComplete).
Создание SWF-ролика со потоковым звуком-«катализатором» и его загрузка
функцией loadMovieNum() позволяют легко создать загружаемую звуковую дорож-
ку, которая сочетает преимущества многократного использования событийных зву-
ков с преимуществами потоковых звуков. Если вам потребуются более совершен-
ные средства синхронизации, воспользуйтесь якорными точками (см. трюк 59).

Преобразование монофонического
ТРЮК

№55 звука в стереофонический


Создание стереозвука посредством разбиения монофонического звука
на два канала без увеличения объема пересылаемых данных.
Flash воспроизводит любой сигнал в двухканальном режиме. При воспроизведе-
нии монофонического звука один и тот же сигнал направляется на оба динамика.
2ВВ Глава 7. Работа со звуком

Если звук является стереофоническим, левый канал направляется на один дина-


мик, а правый канал - на другой. Громкость двух каналов изменяется при помо-
щи звуковой огибающей (вызывается кнопкой Edit на панели свойств) или из
кода ActionScript (метод Sound.setVolumeQ). Также существует возможность из-
менения баланса, то есть относительной громкости каналов (см. трюк 60), с ис-
пользованием методов Sound.setPan() и Sound.setTransformQ.
Преобразование монофонического звука в стереофонический с использованием зву-
ковой огибающей начинается с импортирования звука в Flash командой File •
Import • Import to Library. Тип импортированного звукового файла (моно или сте-
рео) определяется по количеству форм сигнала, отображаемых в библиотеке, -
одна форма для монофонического сигнала, две - для стереофонического.
На панели Library щелкните на импортированном звуковом файле правой кноп-
кой мыши (Windows) или щелкните с нажатой клавишей §€ (Мае). Выберите
в контекстном меню команду Properties. На экране появляется диалоговое окно
Sound Properties. Выберите в списке Compression строку МРЗ (рис. 7.9).

Compression::1мРЗ \^}£\Шт
'-Preprocessing; >\:Х:даУа1 $Щтщ::тт •

Bit fate: ! 16 kbps v

;••;. Quaiity: ;Best \yf .

( 2.7 k8 f 1.1% of original

Рис. 7 . 9 . Параметры экспортирования звука в диалоговом окне Sound Properties

На практике почти всегда используется алгоритм сжатия МРЗ, поскольку он


существенно превосходит своих конкурентов по соотношению «размер файла/
качество звука». Недостатком формата МРЗ можно считать то, что он требует
восстановления сжатых данных на стадии выполнения, а эта работа может ока-
заться непосильной для старых компьютеров. Если объем пересылаемых данных
не важен (например, при создании автономных приложений) и если вам приходит-
ся поддерживать старые компьютеры, попробуйте использовать формат RAW -
он не требует восстановления на стадии выполнения, а следовательно, исполь-
зует меньше вычислительных мощностей.
Экспортируемый звук может быть либо монофоническим, либо стереофониче-
ским. При сжатии МРЗ с частотой более 20 Кбит/с лучше выбрать стереофони-
ческий формат, так как алгоритм МРЗ хорошо сжимает стереосигналы. Для ча-
стот ниже 20 Кбит/с стереофонический формат не поддерживается. Низкие
частоты дискретизации хорошо подходят для озвучивания пользовательского
интерфейса и заметно уменьшают общий объем звуковых данных; и все же было
бы неплохо иметь возможность экспортирования в стереофоническом формате
и на частоте 16 Кбит/с.
Чтобы стереофонический формат был доступен на низких частотах дискрети-
зации, следует создать звуковую огибающую. Выделите ключевой кадр на вре-
менной диаграмме. На панели свойств выберите звуковой файл в раскрываю-
щемся списке Sound. Убедитесь в том, что в группе Sync выбраны параметры
Event/Repeat/1 (рис. 7.10).
Преобразование монофонического звука в стереофонический 267

А.
Sound: ipadl •-
Efect: C.uso
tm
Sync: .Event v Repeat vi 1
44k№Stereo tfiBit L3s236.0kB

Рис. 7.10. Параметры синхронизации звука

Щелкните на кнопке Edit. На экране появляется окно Edit Envelope (рис. 7.11).

Effect: i Custom

•!>!

Рис. 7 . 1 1 . Окно Edit Envelope

Два графика формы сигнала в этом окне представляют два звуковых канала,
а линия представляет уровень громкости. Если два канала имеют одинаковую
форму огибающей (по умолчанию), в динамиках будет воспроизводиться исход-
ный монофонический звук. Изменение огибающих создает различия между гром-
костью двух каналов. Подача двух уникальных сигналов на динамики создает
стереофонический эффект.
Звуковая огибающая содержит до восьми контрольных точек (маркеров, кото-
рые можно перетаскивать мышью). Чтобы создать новую контрольную точку,
щелкните на любом участке огибающей, не содержащем контрольной точки.
Чтобы удалить контрольную точку, перетащите ее мышью за пределы панели.
На многих сайтах для управления звуком используется ActionScript. Чтобы
использовать представленную методику для звуков, присоединяемых на стадии вы-
полнения методом MovieClip.attachSoundO, создайте клип с ключевыми кадрами, к ко-
торым присоединены звуки. Для каждого ключевого кадра с ассоциированным
268 Глава 7. Работа со звуком

звуком также определите операцию stop(). Кроме того, определите операцию


stop() для первого кадра (рис. 7.12).

Рис. 7.12. Клип со звуками и операции stop() на временной диаграмме

Код ActionScript для управления звуком должен выглядеть примерно так (пред-
полагается, что клипу со звуками на панели свойств было задано имя экземпля-
ра soundHolder):
mySound = new Sound(soundHolder): // Определение объекта Sound
soundHolder.gotoAndPlayC'soundl"); // Запуск звука
mySound.stopO; // Остановка звука
Применяя огибающие к звуковому файлу, можно превратить один монофони-
ческий звук в разные стереофонические звуки. Вместо того чтобы использовать
несколько звуков с пониженным качеством, можно использовать один качествен-
ный базовый эффект и преобразовать его при помощи огибающих.

Звуковые эффекты в реальном


времени
Реализация звуковых эффектов в реальном времени на стороне клиента
снижает объем пересылаемых данных. Реверберация и другие эффекты
сделают звуковое оформление вашего ролика более разнообразным.
Метод Sound.start() позволяет воспроизводить звук с заданным смещением:
Sound.start(cwe/z/ewtfe. количество):
Звук начинается с заданного смещения и воспроизводится заданное количество
раз, однако не существует простых средств для воспроизведения звука с начальным
и конечным смещением. Эта задача решается методом Sound.startEnd(startTime,
endTime) из следующего фрагмента:
Sound.prototype.startEnd = function(startTime. endTime) {
var duration = (endTime - startTime)*1000;
this.startCstartTime. 1);
this.endSound = setlntervaKendTimer, duration, this); •
}
endTimer = function (arg) {
arg.stopO;
Звуковые эффекты в реальном времени 269

clearlnterval(arg.endSound):
}:
mySound = new Sound(this);
mySound. attachSoundC"UlSound");
mySound.startEnd(0.5, 0.7);
Метод Sound.startEndQ позволяет выделять небольшие фрагменты из существу-
ющих звуков, уже включенных в библиотеку, избавляя вас от необходимости
создавать их отдельно.
Возможность выделения подобных фрагментов может использоваться при соз-
дании интерактивных пультов микширования. Кроме того, это хороший способ
имитации режима быстрой перемотки, реализованной в некоторых проигрыва-
телях компакт-дисков, - проигрыватель воспроизводит односекундный образец
для каждых 10 секунд звукового материала, позволяя быстро найти нужную
точку.
Еще один трюк, маскирующий факт использования одних и тех же базовых ма-
териалов, - добавление эффектов реального времени. В следующем фрагменте
эффект реверберации создается воспроизведением двух версий одного звука с не-
большим смещением по времени:
mySound = new Sound(this);
mySoundEcho = new Sound(this);
mySound.attachSoundC"UlSound");
mySoundEcho.attachSoundC'UISound");
mySound.start(0. 1);
mySound.start(0.1. 1);
Если последняя строка имеет вид
mySound.start(0.001. 1);
возникает эффект фазового сдвига.
Повышение громкости до уровня выше 100% создает эффект дисторсии:
mySound = new Sound(this);
mySoundEcho.attachSoundC"UlSound");
mySound.start(0. 1);
mySound.setVolume(200);
Flash позволяет задавать отрицательные уровни громкости. При этом создается
версия исходного сигнала с фазовым сдвигом на 180°, которая может использо-
ваться для создания фазовых эффектов, особенно в сочетании с эффектом ревер-
берации. Тем не менее, восприятие таких эффектов требует хорошего звукового
оборудования и грамотной расстановки динамиков (что на практике встречается
гораздо реже, чем вы думаете).
Как видите, несложные приемы позволяют с максимальной эффективностью ис-
пользовать один-два звуковых файла, входящих в SWF, за счет обработки звука
в реальном времени. Это особенно важно при написании звукового Flash-содержа-
ния для приложений с крайне жесткими ограничениями по объему пересылаемых
данных - особенно для рекламных баннеров, которые часто ограничиваются
объемом 12 Кбайт.
270 Глава 7. Работа со звуком

Быстрое создание звукового


ТРЮК

№57 сопровождения для пользовательского


интерфейса
Звуки щелчков на кнопках и другие звуковые эффекты пользовательско-
го интерфейса сможет создавать даже тот, кто не имеет музыкального
слуха, сильно занят, просто ленив... или сочетает все эти качества.
К числу важнейших ресурсов в любом Flash-ролике относятся звуки, воспроиз-
водимые при взаимодействии с элементами пользовательского интерфейса. Веб-
дизайнеры традиционной школы не особенно беспокоятся о звуковом сопро-
вождении пользовательского интерфейса, поскольку браузер имеет стандартное
озвучивание для щелчков, но на Flash-сайтах звуковой дизайн играет более важ-
ную роль. Внимательное изучение хороших Flash-сайтов показывает, что звук
является одним из важнейших факторов в общем впечатлении от сайта.
Попробуйте просмотреть заставку сайта Mondo (http://www.mondo.pl) со звуко-
выми эффектами и без них. Этот пример наглядно показывает, до какой степени
небольшое звуковое сопровождение меняет пользовательский интерфейс.
Однако большинство дизайнеров не умеют создавать звуки пользовательского
интерфейса «на пустом месте» (в отличие от других базовых ресурсов Flash).
Как правило, они используют одни и те же общедоступные звуковые эффекты,
потому что создать хороший эффект без профессионального звукового оборудо-
вания довольно трудно.
Видимо, многие дизайнеры не обладают музыкальным слухом, предпочитают
использовать готовые звуки из бесплатных источников или еще хуже - заим-
ствовать их из малоизвестных тем Windows. А впрочем, дело скорее не в лени,
а в расстановке приоритетов. В настоящем трюке представлено руководство по
ускоренному созданию звукового оформления пользовательского интерфейса для
занятых и ленивых.
Поиски веб-ресурсов с информацией о звуке лучше всего начать с сайта Sonify.org
(http://www.sonify.org), посвященного интерактивному аудио для Веб и беспро-
водных устройств. На сайте имеются актуальные ссылки для тех, кто захочет
больше узнать о звуке в Flash.
К сожалению, многие звуки, распространяемые на коммерческой основе, приме-
няются слишком часто. Количество предлагаемых звуковых файлов огромно,
но самые полезные из них встречаются в Веб на каждом шагу!
У веб-дизайнера со средней музыкальной подготовкой, не отличающего контра-
пункт от контрабаса, есть два выхода:
• искать там, где еще не искали другие;
• самостоятельно создать звуковое сопровождение пользовательского интер-
фейса, используя несложные приемы фильтрации.

Устаревшие программы
Устаревшими программами (abandonware) называются программные продукты,
коммерческий жизненный цикл которых уже завершился. На такие продукты
Создание звукового сопровождения для пользовательского интерфейса 271

еще распространяются соглашения об авторских правах, но никто не следит за


их соблюдением, потому что у продукта нет платежеспособной клиентской ба-
зы. В поисковой системе Google вы найдете множество сайтов с устаревшими
программами - выполните поиск по ключевому слову «abandonware» и загля-
ните в подраздел «games» на найденных сайтах. Речь идет о действительно старых
играх, 10- и 20-летней давности, работающих в DOS и не использующих
аппаратное ускорение. Для нас эти игры представляют интерес по следующим
причинам:
• они разрабатывались до широкого распространения формата МРЗ, поэтому
их звуковые ресурсы обычно хранятся в более простых форматах - напри-
мер, WAV. WAV-файлы очень легко импортируются в Flash (в отличие от фай-
лов МРЗ, разнообразие форматов которых часто сбивает с толку фильтр им-
портирования Flash). Попробуйте заглянуть в подкаталог Sound и поискать
в нем звуки для пользовательского интерфейса;
• хотя с момента издания первых устаревших игр игровые технологии прошли
огромный путь, звук щелчка на кнопке так и остался звуком щелчка на кноп-
ке, да и технология создания звука тоже не претерпела особых изменений.
Вероятно, вы уже поняли мою мысль - если игра отнесена к категории устарев-
ших продуктов, скорее всего, звуковое сопровождение ее пользовательского ин-
терфейса тоже не защищается на коммерческой основе, и никто не будет возра-
жать, если вы им воспользуетесь. Конечно, всегда остается вероятность того, что
звуки в старых играх были позаимствованы по лицензии из библиотек, суще-
ствующих и в наши дни, несмотря на прошедший срок. Авторское право не пере-
стает действовать только потому, что его объект утратил коммерческую привле-
кательность, и его владельцы имеют законное право защищать свои продукты.
Так что в вашем распоряжении остается еще один вариант: создание собствен-
ных звуков.

Растяжение времени
Современные настольные системы способны на серьезную обработку цифрового
звука, но не стоит удивляться, если время обработки большого звукового файла
будет измеряться в минутах, а не в секундах.
Методика растяжения (и сжатия) звуков по времени позволяет изменять про-
должительность звука при сохранении тональности тона или темпа. Этот прием
используется при звукозаписи для модификации сэмплов, чтобы они лучше
соответствовали общей композиции. В нашем трюке используется тот факт, что
музыкальное произведение, воспроизводимое за несколько минут, можно пре-
образовать в звук продолжительностью в доли секунды с сохранением то-
нальности.
Даже простые, бесплатные звуковые редакторы способны творить настоящие
чудеса. Тем не менее, для общего редактирования звука я обычно использую
Adobe Audition (формально - CoolEdit). В настоящее время этот продукт суще-
ствует только на платформе Windows. Фирма Adobe предлагает 30-дневную пол-
ноценную пробную версию. За это время вы успеете создать все звуковые эф-
фекты пользовательского интерфейса, которые вам когда-либо понадобятся. После
этого созданные звуки можно будет использовать много лет.
272 Глава 7. Работа со звуком

Бесплатный альтернативный звуковой редактор Audacity (http://audacity.sourcefor-


ge.net) содержит все функции, которые вам могут понадобиться. Audacity рас-
пространяется с открытыми исходными текстами и работает на платформах
Windows, Mac OS 9/X и Linux/Unix. Название Audacity не зря напоминает
Audition - сходство не ограничивается именами и распространяется на функ-
циональность!
Далее приводятся краткие инструкции по работе с Audacity и Audition. Конечно,
на рынке существует множество других звуковых редакторов, но эти две про-
граммы особенно хорошо приспособлены для редактирования звука, предназна-
ченного для использования в Веб.
Чтобы создать собственную коллекцию звуков пользовательского интерфейса,
загрузите любой музыкальный фрагмент с секциями, не содержащими удар-
ных. На рис. 7.13 показано, как выглядит форма сигнала с такой секцией
в Audition. i

tnf-T! r-
m
-----'-цдщ ЩЩ:
«•Us Щ
1 1

Г Щ

1 1J ЯШ! :!, , jib,,

гШМШМШ; ШШМ Ш1
0:00.000

Рис, 7 . 1 3 . Редактирование звука в окне Organizer редактора Adobe Audition

Выделите нужную секцию музыкального фрагмента (длиной примерно 10 с


или более) и удалите остальные звуковые данные, выделив их и нажав клави-
шу Delete.
Если вы работаете в Audition, выделите в окне Organizer (левая панель на рис. 7.13)
вкладку Effects и найдите эффект Real Time Effects • Time/Pitch • Stretch (если окно
Organizer отсутствует на экране, откройте его клавишами Alt+9).
Дважды щелкните на слове Stretch, чтобы открыть вкладку Constant Stretch окна
Stretch (рис. 7.14).
Задайте параметру Precision значение High Precision, а параметру Stretching Mode -
значение Time Stretch (Preserves Pitch). В группе Pitch and Time Settings установи-
Создание звукового сопровождения для пользовательского Интерфейса 273

те флажок Choose Appropriate Defaults. Справа от бегунка Stretch % задайте пара-


метру Length значение 3 с (или около того). Щелкните на кнопке ОК.

Constant Stretch j Gliding Stietch ) Presets Add J . :•;::. j ;

Stretch* Faster Tempo Ratio Length Transpose Cutting Power


Double Speed
J352898 [1 jnone j j Fast Talker
Helium
Lower Pitch
Raise Pitch
Slow Down
Speed Up
Precision :r;~ •••
;•
; СLow Precision Г Medium Precision & High Precision::;

Pit.:hand Типе settings

Г <^ Time Stretch (preserves pitch] ~~ Hz


:
Г pitch Shift (presefves temfKjf •.: . I ^
С Resampte (preserves neiiheij
riate defaults

Рис. 7.14. Окно Stretch в редакторе Audition

Если вы работаете в Audacity, найдите нужную 10-секундную секцию, удалите все


остальное и выделите полученный участок. Выполните команду Effect • Change Tem-
po. На экране появляется диалоговое окно Change Tempo (рис. 7.15). В поле Length
(seconds) этого окна введите значение около 3 с. Щелкните на кнопке ОК.

| к!

Length (seconds) (тот to В

Cancel

Рис. 7.15. Окно Stretch в редакторе Audacity

Если новая продолжительность звука меньше исходной, фактически, происхо-


дит сжатие звуковых данных по времени. При этом происходит следующее:
• звук становится неузнаваемым, а в процессе сжатия теряется достаточно ин-
формации, чтобы возврат к оригиналу стал невозможным;
274 Глава 7. Работа со звуком

• благодаря сохранению тональности результат звучит не хуже оригинала.


Наверное, вы уже догадались, почему я предложил выбрать фрагмент без
звучания ударных - при сжатии не сохраняется темп;
• полученный звук «отдаленно напоминает» оригинал, но отличается от него
по звучанию.
Теперь вы можете выделить весь результат (или его часть) и восстановить его.
После завершения процесса у вас появляется фрагмент, который звучит так,
словно он был создан профессиональным музыкантом (в общем-то, так оно
и есть - только этим музыкантом были не вы!). Если повторить тот же трюк
с другим фрагментом исходного произведения, вы получите другой звук, доста-
точно близкий к первому. Таким способом можно создать набор звуков для оформ-
ления пользовательского интерфейса, следующих общей музыкальной теме.
На первый взгляд кажется, будто прием растяжения/сжатия (а также связан-
ный с ним эффект изменения тональности при сохранении продолжительности
звука) является чем-то узкоспециализированным, однако разработке звука Flash
он приносит огромную пользу. После знакомства с ним становится непонятно,
как же вы раньше работали со звуком в Flash.
Например, если продолжительность созданных вами звуков превышает один кадр
Flash (1/12 с по умолчанию) и вы хотите, чтобы другой звук начался сразу же
после окончания предыдущего звука (см. трюк 54), растяните или сожмите его
до ближайшей величины, кратной частоте смены кадров Flash. Небольшое изме-
нение продолжительности остается незаметным для слушателя.
А вот еще несколько ситуаций, в которых применяется растяжение/сжатие:
• Объединение звуков из разных источников. Вполне естественно предполо-
жить, что все звуки пользовательского интерфейса должны иметь одинако-
вую продолжительность, а растяжение лучше простого отсечения, создающе-
го явное впечатление незавершенности звука.
• Создание голосов для «мультяшных» персонажей. В результате преобразова-
ния происходит либо изменение тональности с сохранением продолжитель-
ности, либо наоборот. В обоих случаях полученный звук звучит более раз-
борчиво и профессионально, чем при простом ускорении.
• Изменение комментария в соответствии с продолжительностью анимации.
Допустим, имеется 12-секундная анимация и комментарий к ней, который
продолжается 15 с. Первое побуждение - изменить продолжительность ани-
мации, поскольку кажется, будто изменить продолжительность комментария
будет гораздо сложнее. Но стоит овладеть методикой растяжения/сжатия
звуков, и все становится очень просто.
• Длинная анимация синхронизирована со звуковой дорожкой. Включение но-
вых кадров в анимацию приводит к нарушению синхронизации изображения
со звуком. Просто выделите часть звуковой дорожки и слегка растяните ее.
Аниматоры будут долго гадать, почему звуковая дорожка так хорошо синхро-
низируется с анимацией, хотя они удалили 5 кадров из начала ролика и еще
30 кадров из середины.
• Новый звук формируется из нескольких существующих звуков, но результат
слияния звучит странно, потому что исходные звуки находятся в разной то-
Оптимизация звука 275

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


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

Итоги
Вероятно, из всего контента Flash звуки используются наименее эффективно.
Коммерческие звуковые библиотеки качественно звучат, но дорого стоят. Нет
полной уверенности в том, что они идеально впишутся в дизайн вашего сайта,
зато велика вероятность их использования на множестве других сайтов. Конеч-
но, вам не хотелось бы идти на подобный риск с графикой, так стоит ли делать
то же самое со звуком?
Выберите фрагмент музыкального произведения, соответствующий общему на-
строению вашего сайта, а затем посредством растяжения/сжатия его фрагмен-
тов создайте уникальные звуки, которые дополнят графику сайта подходящим
звуковым сопровождением.
Если вам не хочется заниматься этим, попробуйте воспользоваться звуковыми
ресурсами устаревших программ. Хотя эти звуки не являются абсолютно обще-
доступными и свободными от авторских прав, такой путь все же гораздо лучше
«выдирания» звуков пользовательского интерфейса из операционной системы!

ТРЮК Оптимизация звука


№58 Оптимизация звука в формате МРЗ для Flash.

На сайтах Flash звук не только является неотъемлемой частью контента, но и за-


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

Устранение шума дискретизации


В процессе оцифровки в данные вносится ошибка, называемая ошибкой дискре-
тизации, в результате чего возникает шум дискретизации. Под термином «дис-
кретизация» понимается процесс преобразования аналогового сигнала в цифровой
сигнал, принимающий ряд фиксированных значений (называемых уровнями
дискретизации). На практике чаще встречается термин «оцифровка», а сигнал,
значения которого делятся на уровни дискретизации, называется цифровым сигна-
лом. Именно шум дискретизации создает неприятную пронзительную составля-
ющую в низкокачественных звуковых сигналах и придает неживое, механическое
звучание голосу в телефоне.
276 Глава 7. Работа со звуком

Оцифровка аналогового сигнала дает приближенное представление, состоящее из


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

Рис. 7.16. Аналоговая форма сигнала (кривая) и ее цифровое


приближение (темная ломаная линия)

Существует два пути снижения шума дискретизации. Стандартный путь осно-


ван на снижении размера шага дискретизации за счет увеличения количества
уровней. Именно по этой причине 16-разрядный звук (65 536 уровней дискрети-
зации) звучит гораздо лучше 8-разрядного (256 уровней). Однако размер звуко-
вого файла также увеличивается вдвое.
Второй, нестандартный путь основан на использовании всех доступных уровней
дискретизации, обеспечивающем максимально возможную точность оцифрован-
ного сигнала. Кроме того, в отличие от аналогового шума, который может увели-
чиваться с возрастанием громкости или мощности сигнала, величина шума дис-
кретизации остается постоянной при любой громкости сигнала, поскольку она
зависит от расстояния между уровнями дискретизации, а не от амплитуды сиг-
нала. Таким образом, повышение уровня сигнала приводит к заметному сниже-
нию соотношения «сигнал/шум».
Возьмем две формы сигнала (рис. 7.17). Внизу изображен сигнал, записанный
при низкой громкости. Расстояние между уровнями дискретизации относитель-
но велико по сравнению с сигналом, что приводит к снижению разрешения и вы-
сокому соотношению «сигнал/шум». На верхнем графике сигнал записан с вы-
сокой громкостью, а в его оцифровке задействовано больше уровней; такой сигнал
обладает гораздо лучшими соотношением «сигнал/шум» и точностью оцифровки.
Оптимизация звука 277

Чтобы обеспечить максимальный выигрыш, следует увеличить громкость сигна-


ла до такого уровня, чтобы он находился ненамного ниже максимального уров-
ня дискретизации (около 90-95%), представленного пунктирной линией в верх-
ней части рис. 7.17.

Максимальный уровень
дискретизации

Рис. 7.17. Улучшение соотношения «сигнал/шум» посредством записи


на 90-95% от максимального уровня дискретизации

Громкость сигнала увеличивается либо увеличением амплитуды с применением


максимизирующего фильтра, либо нормализацией. Мы рассмотрим процесс нор-
мализации на примере Adobe Audition.
Максимизация сигнала выполняется при помощи особой разновидности фильт-
ров сжатия, которые динамически повышают уровень мощности на всех часто-
тах к уровню насыщения без его достижения. Данная методика начала активно
применяться в 1990-х годах. Любой владелец фонотеки знает, что для записей
более раннего периода был характерен относительно низкий уровень басов и мень-
шая общая выразительность, тогда как более новая музыка (особенно танце-
вальная) стала более яркой, но не утратила четкости звучания отдельных инст-
рументов. Этот современный стиль стал возможным благодаря применению
максимизации.
Формат МРЗ хорошо работает с максимизированным звуком, и импортирование
максимизированных аудиоданных в Flash обеспечивает наилучшее соотноше-
ние «качество/размер файла». Опыт показывает, что экспортирование максими-
зированного звука позволяет создавать ресурсы МРЗ значительно меньшего объе-
ма, чем без применения максимизации, с тем же качеством. Впрочем, у этого
решения есть и оборотная сторона: программное обеспечение максимизации до-
рого стоит и применяется только в профессиональных студиях.
Нормализация звука не обеспечивает той же эффективности, что максимизация,
но зато она реализуется широко распространенным фильтром, входящим в боль-
шинство программ звукового монтажа.
Далее приводится описание процедуры нормализации звука в двух основных
редакторах.
278 Глава 7. Работа со звуком

Adobe Audition
1. Откройте звуковой файл в Adobe Audition.
2. В окне Organizer (Alt+9) перейдите на вкладку Effects.
3. Найдите эффект Off-line Effects • Amplitude • Normalize и дважды щелкни-
те на нем (рис. 7.18). На экране появляется диалоговое окно Normalize
(рис. 7.19).

ffl-Real-T
r,e Effects
В-Off-UP eEffects
| В-Asrpittude
1 ! i. •Amplify
Binaural Auto-Partner
£nve!ope

Рис. 7.18. Эффект нормализации в Adobe Audition

^ЩЩз! 'ЯР1Р1'

W Normalize to Jo " d B

1 O K 1

- ;• • i
W Normalize L/R Equally
C a n c e l !

Г DC Ъя* Adjust [ "


• • • .

Рис. 7.19. Окно Normalize в Adobe Audition

4. В окне Normalize установите флажки Normalize To, Decibels Format и Normalize


L/R Equally. В текстовом поле рядом с флажком Normalize to введите значение
О (используется по умолчанию).

Audacity
Выберите эффект Normalize. Проследите за тем, чтобы оба флажка были уста-
новлены, и щелкните на кнопке ОК.
Более опытные читатели также могут добавить усиление басов или сжатие - обе
возможности скрывают шум дискретизации. В Audacity соответствующие коман-
ды выбираются из раскрывающегося меню Effects.
На рис. 7.20 и 7.21 показаны формы сигнала до и после нормализации. Звуковые
данные масштабируются для заполнения всего спектра сигнала. Тем самым обес-
печиваются использование большего количества уровней дискретизации и умень-
шение влияния шума дискретизации.
Оптимизация звука 279

Рис. 7.20. Исходный сигнал

Рис. 7 . 2 1 . Нормализованный сигнал

Борьба с шумом наложения


Качество звука, экспортируемого из Flash, снижается из-за применения сжатия.
Обычно результат получается примерно таким же, как при снижении разреше-
ния (downsampling), то есть уменьшении количества дискрет в звуковом файле.
Сжатие и снижение разрешения в звуковых данных создают ошибки наложения,
которые могут привести к появлению заметного шума наложения.
Наложением (aliasing) называется эффект слышимости гармоник частоты
дискретизации. Обычно этот эффект проявляется в виде постоянного гудения
в экспортированном звуке при построении SWF. В крайних случаях гудение
превращается в пронзительный скрежет, а звук становится совершенно беспо-
лезным.
Эффект наложения также проявляется в работе с растровой графикой, а для его
сокращения применяется методика сглаживания (antialiasing). В данном случае час-
тота дискретизации заменяется размером пиксела, а ошибка наложения проявля-
ется в виде «зазубрин», отсутствовавших на исходном изображении (см. трюк 22).
280 Глава 7. Работа со звуком

Термины «aliasing» и «antialiasing» знакомы многим дизайнерам, но мало кому


известно, что эти термины пришли из теории обработки сигналов.
Важнейшее правило оцифровки, известное как теорема Найквиста, гласит, что
для достижения абсолютной точности воспроизведения звука частота дискре-
тизации должна быть как минимум вдвое больше максимальной звуковой час-
тоты сигнала. Именно по этой причине в аудиоформате Redbook, используе-
мом в звуковых компакт-дисках, выбрана частота дискретизации 44,1 кГц. Самая
высокая частота, воспринимаемая человеческим ухом, равна 22 кГц (и то толь-
ко в детстве - у меня и у большинства читателей этот порог составляет около
12-16 кГц). Удвоение 22 кГц дает величину 44 кГц, а 0,1 кГц обеспечивает то
самое «больше» в фразе «вдвое больше максимальной звуковой частоты сигна-
ла».
Таким образом, слушатель не сможет отличить запись на компакт-диске от жи-
вого звука, воспроизводимого той же аудиосистемой.
Снижение разрешения в Flash приводит к нарушению условия теоремы Найк-
виста, а наложение частот портит звук. Большинство дизайнеров пытается бо-
роться с шумом наложения за счет увеличения частоты дискретизации, но это
повышает размер файла. Нетривиальное решение проблемы с шумом наложе-
ния основано на удалении высоких частот, мешающих выполнению правила
«двойной максимальной частоты». Так определяется пороговая частота для лю-
бого аудиоматериала, который должен использоваться с заданными параметра-
ми экспортирования МРЗ. Если удалить (отфильтровать) все частоты исходно-
го материала, превышающие пороговое значение, мы исключим возможность
появления шума наложения.
Но не все так просто: Flash не указывает частоту дискретизации МРЗ, а оп-
ределяет ее в единицах величины потока данных (килобитах в секунду), как
показано на рис. 7.22.
Впрочем, мы можем без особого труда определить пороговые частоты, соответ-
ствующие значениям потока данных Flash на рис. 7.22. Эти частоты перечисле-
ны в табл. 7.1. Правда, «без особого труда» - выражение относительное. Я исполь-
зовал осциллограф для поиска максимальной частоты, которая поддерживалась
каждым значением потока данных без существенного затухания. На первый взгляд
кажется сложно, но на практике это делается довольно легко. Вероятно, то же
самое можно проделать при помощи теоретических вычислений, но на мою по-
мощь не рассчитывайте!
Допустим, для редактирования звука используется Adobe Audition, и мы хотим
экспортировать звук на уровне 20 Кбит/с. Далее перечислены действия, выпол-
нение которых гарантирует отсутствие шума наложения в экспортированном
звуке.
1. Загрузите звук в Adobe Audition.
2. В окне Organizer (Alt+9) откройте вкладку Effects и дважды щелкните на эф-
фекте Off-line Effects • Filters • FFT Filter (рис. 7.23).
Оптимизация звука 281

j Cancel j

[ Impart.. I
ТеД

Рис. 7.22. Значение потока данных (в килобитах в секунду)


в диалоговом окне Sound Properties

Таблица 7 . 1 . Пороговые частоты, соответствующие значениям потока данных


при экспортировании из Flash.
Значение потока данных, Кбит/с Пороговая частота, КГц

8 3,0
16 5,5
20 6,0
24 6,0
32 8,0
48 10,0
56 10,0
64 12,0
80 16,0
96 16,0
282 Глава 7. Работа со звуком

Щ •• Reai-Time Effects
Й-Off-line Effects
I Й- Amplitude
I Щ- Generate
! ЁЗ niters

•Sdenfifk Filters

Рис. 7.23. Выбор фильтра в Adobe Audition

3. В открывшемся диалоговом окне FFT Filter установите флажки и переключа-


тели так, как показано на рис. 7.24. Проследите за тем, чтобы флажок Lock to
Constant Filter был обязательно установлен. Введите в поле Мах значение 0 дБ,
а в поле Min - значение -15 дБ.

Г Log S ca!e Г S plirie Curves: _Jbt


;-' FFT atld Windowing -' -; :;: —
\ Presets i ;FFTSfee Windowing Function
С Major Triad
Cassette Tape Frequency Respon: 8192 ~~p] [eiackman
De-Esser
Inharmonic Resonance .-• Time-Variable Settings •• • -; •
Inharmonic Resonance Slide
t ill The 60 H: Ground Loop ; F Lock to Constant filler .
! ш ы Ы '••••". \ , • • ••
Kill The Subharrnonics
Mastering • Gentle & Narrow
Mastering • Gentle &Wide
;
Precision Factor: |*''

Рис. 7.24. Окно FFT Filter в Adobe Audition

4. Создайте кривую в верхней части окна FFT Filter, как показано на рис. 7.24, со
«ступенькой» на частоте, указанной в табл. 7.1 (для 20 Кбит/с пороговая ча-
стота равна 6,0 кГц). При этом вы определяете фильтр нижних частот, отсе-
кающий частоты выше пороговой точки 6,0 кГц (в Audition частоты измеря-
ются в герцах, поэтому точка отсечения устанавливается на частоте 6000 Гц).
5. Щелкните на кнопке ОК, чтобы применить фильтр.
Служебная информация для синхронизации 283

6. Сохраните файл в формате МРЗ.


7. Импортируйте звуковой файл в Flash командой File • Import • Import to Library.
По сравнению с оригиналом звук становится глубже, поскольку высокочастотные
составляющие были удалены. Если теперь экспортировать звук в итоговый SWF-
ролик, пропадет фоновое гудение, возникающее из-за шума наложения.

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

Служебная информация
ТРЮК

№69 для синхронизации


Наличие контрольных точек синхронизации позволяет реагировать на спе-
циальные события при воспроизведении звуков.
Flash используется для воспроизведения звуков, но с получением низкоуровне-
вой информации о звуках дело обстоит сложнее. В частности, вы можете задать
общую громкость звукового объекта методом Sound.setVolumeO, но вам не удастся
определить мгновенные значения громкости звукового файла, воспроизводимо-
го в данный момент. Чтобы решить эту проблему, необходимую информацию
приходится сохранять в Flash отдельно.
В данном примере используется Audacity (http://audacity.sourceforge.net) - бес-
платный звуковой редактор для Windows, Mac OS 9/X и Unix/Linux, распро-
страняемый с открытыми исходными текстами. Хотя по широте возможностей
настройки он уступает коммерческим продуктам вроде Adobe Audition, его стан-
дартные настройки почти всегда соответствуют потребностям типичного веб-
дизайнера, поэтому работать с Audacity удобно и просто. Мы выделим из музы-
кального произведения моменты ударов и будем использовать полученные данные
во время воспроизведения. В результате возникает иллюзия, будто Flash «чита-
ет» низкоуровневую информацию прямо из звукового файла.
Для начала нам понадобится звуковой файл с ударными инструментами. Если
у вас под рукой не найдется такого файла, вы всегда можете использовать файл
groovyl_oop.wav с сайта книги.
284 Глава 7. Работа со звуком

У файла groovyl_oop.wav имеется одна полезная особенность - его можно непре-


рывно воспроизводить в циклическом режиме. К сожалению, для создания та-
ких звуков «с нуля» нужны музыкальные способности и профессиональное обо-
рудование, хотя, в принципе, также можно нарезать фрагменты готовых файлов
(средствами Audacity и Audition) до тех пор, пока не будет получен аналогичный
результат. Впрочем, я бы не рекомендовал так поступать, потому что при столь
очевидных заимствованиях могут возникнуть проблемы с авторским правом.
Откройте файл groovyl_oop.wav в Audacity командой File • Open. Выделите весь
сигнал (Edit • Select All).
Выполните команду Analyze • Beat Finder. Мы воспользуемся этой функцией для
нахождения всех ударных звуков в нашем файле. Поиск производится по не-
формальному критерию, но на самом деле ничего сложного в нем нет. Посмот-
рите на форму сигнала и найдите пороговое значение, которое бы захватывало
только звуковые пики без фонового сопровождения. Для файла groovyLoop.wav
такой порог составляет примерно 75%.

Рис. 7.25. Назначение порога при поиске пиков в Audacity

После того как сигнал будет обработан, под графиком в окне появляются марке-
ры, помеченные буквой «В» и следующие более или менее периодично (рис. 7.26).

'Kits' 4410C •'--' ". ' -


Рис. 7.26. Результаты поиска ударных звуков в Audacity
Служебная информация для синхронизации 285

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

Рис. 7.27. Неправильный поиск ударов

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


низкого порога и постепенно увеличивайте его. По крайней мере, вы будете увере-
ны в том, что правильное значение лежит в конкретном направлении от текущего.
Не закрывая окна Audacity, запустите Flash и импортируйте звук командой File •
Import • Import to Library. Присвойте ему идентификатор компоновки groovyLoop
(см. трюк 52).
Свяжите следующий фрагмент кода с кадром 1 FLA:
beatHandler = function О {
beatMarker++;
clealnterval(beatlD):
beatID = setlnterval(beatHandler. beatCode[beatMarker]);
pulseO;
};
repeatSound = functionO {
this, start (0. 1):
clealnterval(beatlD);
beatMarker = 0;
beatID = setlnterval(beatHandler. beatCode[beatMarker]);
}:
function pulseО {
// Сделать что-нибудь полезное...
}
beatCode = new ArrayO:
beatMarker = 0:
beatCode = [];
for (var i = beatCode.length - 1: i > 0; i--) {
beatCode[i] = beatCodeCi] - beatCode[i-l]:
trace(beatCode[i]):
}
groovy = new Sound(this):
groovy.attachSoundC"groovyLoop");
groovy.start(0. 1):
groovy.onSoundComplete = repeatSound;
clearlnterval (beatID):
beatID = setlnterval(beatHandler. beatCode[0]);
В массив beatCode заносятся значения, соответствующие позициям маркеров.
В Audacity активизируйте инструмент Selection (первая кнопка на панели) и пос-
ледовательно щелкайте на форме сигнала в позиции каждого маркера, начиная
с первого. Прочитайте время в позиции маркера (оно отображается в формате
минуты:секунды:миллисекунды в нижней части окна приложения), преобразуй-
те его в миллисекунды и введите полученное значение в массив beatCode.
28В Глава 7. Работа со звуком

Повторите эту процедуру для всех маркеров. Полученный массив beatCode бу-
дет выглядеть примерно так: ,
beatCode = [120. 556. 996. 1366. 1835. 2302, 2669. 3124.
3559. 3938. 4414. 4827. 5232, 5661. 6091. 6512];
Массив содержит позиции всех ударов в миллисекундах. В такой форме его со-
держимое может использоваться с функцией setlntervalQ; именно это и делает при-
веденная ранее программа - она выполняет функцию beatHandlerQ в точках, опре-
деленных массивом beatCode. Чтобы реально использовать события setlntervalQ,
включите в функцию pulse() код для выполнения каких-нибудь полезных опера-
ций - например, управления танцующей фигурой или изменения параметров
узора. Функция даже может использоваться для синхронного запуска другого
звука.
В таких музыкальных проигрывателях, как WinAmp и iTunes, предусмотрена
возможность создания визуальных эффектов для сопровождения текущей до-
рожки. Как правило, эффекты представляют собой узоры, вращающиеся и пуль-
сирующие в такт музыке. Работа эффектов основана на идентификации удар-
ных звуков - точно так же, как мы сделали в Audacity. Выполнить описанным
способом хронометраж ударных для длинной песни будет довольно сложно, од-
нако он позволяет сохранять информацию о позициях ударов в коротких сэмплах,
традиционно используемых в веб-дизайне Flash в качестве фонового сопровож-
дения. Кроме того, на основании позиций ударов можно отображать столбчатую
диаграмму, пульсирующую в ритме музыки. На многих сайтах такие диаграммы
обозначают включение/выключение музыкального сопровождения, но диаграм-
ма остается неподвижной - а с этим кодом она придет в движение!
Массив beatCode можно заполнять данными любых контрольных точек, синхро-
низируемых с любыми событиями звуковой дорожки, будь то крещендо, удар по
тарелкам и т. д. Другими словами, массив beatCode в сочетании с приведенным
кодом имитирует то, что в Director называется якорными точками. В вашем
распоряжении появляется механизм для инициирования событий в определен-
ные моменты при воспроизведении звука.

ТРЮК Пользовательский класс звуковых


№60 преобразований
Создание пользовательского класса для выполнения эффектов нараста-
ния/затухания звука и перекрестного растворения.
На практике часто применяются эффекты нарастания/затухания звука и пере-
крестного растворения (затухания одного звука с одновременным нарастанием
другого). Стандартный характер задачи предполагает, что она хорошо подходит
для реализации в виде пользовательского класса. Класс обеспечит выполнение
всей черновой работы, а нужный эффект будет реализовываться простым вызо-
вом одного из методов.
Класс Sound, как и встроенный класс Color, содержит метод setTransform(). Ранее
мы уже создали пользовательский класс цветовых преобразований (см. трюк 10),
Пользовательский класс звуковых преобразований 287

а теперь на базе тех же принципов будет построен аналогичный пользовательс-


кий класс для работы со звуком. Класс SoundTrans реализуется как субкласс
встроенного класса Sound и содержит два метода:
• SoundTrans.fadeln(интервал, количество) - метод запускает звук и наращива-
ет его громкость от 0 до 100 % в течение заданного интервала. Звук воспроиз-
водится циклически заданное количество раз;
• SoundTrans. 1адеОи\(интервал) - затухание громкости до нуля в течение за-
данного интервала.
Далее приводится код пользовательского класса SoundTrans, который должен
храниться во внешнем файле с именем SoundTrans.as:
// Следующий код ActionScript 2.0 должен храниться
// во внешнем файле SoundTrans.as.
class SoundTrans extends Sound {
// FADEJDUT - затухание звука.
// FADE_IN - нарастание звука.
// RATE - частота эффектов в миллисекундах.
private static var FADEJ3UT:Object = {11:0. 1г:0. г г : 0 . r l : 0 } :
private static var FADEJN:Object = {11:100. l r : 0 . rr:100. r l : 0 } :
private s t a t i c var RATE:Number = 6 0 ;
private var interval:Number;
private var startTime:Number;

// (Пере)запуск звука и нарастание громкости за duration миллисекунд.


// Далее звук циклически воспроизводится loop раз.
public function fadeln(duration:Number, loop:Number):Void {
// Вызов функций, унаследованных от суперкласса Sound.
stopO:
startCO. loop);
setTransform(FADE_0UT);
// Вызов метода, определенного в субклассе.
applyTransform(FADE_IN. duration):
}
// Затухание звука за duration миллисекунд
// с остановкой в конце воспроизведения,
public function fadeOutCduration:Number):Void {
applyTransform(FADE_OUT, duration);
}
// Инициирование эффекта и создание интервального таймера
// для его завершения.
private function applyTransform(transObject:Object.
duration:Number):Void {
// Получение текущего объекта звукового преобразования
var getTrans:Object = getTransformO;
var diffTrans:Object = new ObjectO;
i f (duration < RATE) {
duration = RATE:
}
startTime = getTimerO;
for (var i in transObject) {
d i f f T r a n s [ i ] = (transObject[i]-getTrans[i])/(duration/RATE);
288 Глава 7. Работа со звуком

// Первый параметр - текущий объект t h i s .


// Второй параметр - вызываемая функция ( t r a n s i t i o n O ) .
// Третий параметр - продолжительность интервала в миллисекундах.
// Четвертый, пятый и шестой параметры передаются t r a n s i t i o n O .
interval = setlnterval(this. "transition". RATE. transObject.
diffTrans. duration);
}
private function transition(transObject:Object. diffTrans:Object.
duration:Number):Void {
var getTrans:Object = getTransformO;
for (var i i n diffTrans) {
getTrans[i] += d i f f T r a n s [ i ] ;
}
setTransform(getTrans);
i f (getTimerO - startTime > duration) {
// Деинициализация
setTransform(transObject);
clearlnterval(interval):
}
updateAfterEventO;

Обратите внимание: наш класс не добавляет новые методы непосредственно в класс


Sound, как это делалось при наследовании на базе прототипов в ActionScript 1.0.
Вместо этого класс SoundTrans расширяет встроенный класс Sound (то есть объяв-
ляется производным от него). Преимущество такого способа состоит в том, что
новая функциональность класса SoundTrans отделяется от существующего клас-
са Sound, но в то же время новый класс идеально интегрируется с Sound.
Рассмотрим пример использования класса SoundTrans.
Прежде всего необходимо создать экземпляр класса SoundTrans. Программа
создает объект SoundTrans, используя файл groovyl_oop.wav (предполагается, что
этот файл находится в библиотеке и ему присвоен идентификатор компоновки
groovyLoop):
var groovy:SoundTrans = new SoundTrans(this):
groovy.attachSound("groovyLoop"):
Теперь мы можем использовать методы класса SoundTrans (или методы супер-
класса Sound) с экземпляром SoundTrans. Следующая команда запускает звук на
воспроизведение с нарастанием громкости от 0 до 100% в течение трех секунд.
Звук воспроизводится дважды:
groovyTrans.fadeIn(3000. 2):
Команда на затухание звука в течение шести секунд:
groovyTrans.fadeOut(6000);
Попробуйте усовершенствовать класс SoundTrans и реализовать в нем дополни-
тельные возможности:
• сделайте так, чтобы значение RATE могло определяться пользователем;
• включите в класс метод, который получает массив точек нарастания/затуха-
ния звука и реализует сценарный аналог звуковой огибающей.
ГЛАВА 8

Элементы пользовательского
интерфейса
Трюки № 61-64
Изначально Flash создавался как инструмент для создания анимации в услови-
ях каналов связи с низкой пропускной способностью, но с тех пор фирма
Macromedia добавила много возможностей для построения графического пользо-
вательского интерфейса (GUI).
В последние годы Macromedia усиленно продвигает Flash как платформу для
разработки RIA (Rich Internet Application). С этой целью в сценарный язык
Flash, ActionScript, были внесены изменения, упрощающие написание кода вза-
имодействия с пользователем, неформально называемого «клеем GUI» - того,
что объединяет элементы интерфейса и управляет их совместной работой.
Пользовательский интерфейс и средства передвижения могут быть реализованы
посредством использования временной диаграммы Flash как нелинейной серии
секций анимации/контента. В итоговом Flash-сайте пользователь перемещается
между секциями, каждая из которых представляет некоторое состояние програм-
мы (например, разные страницы в многостраничной форме); для перемещений
используется простой интерфейс, основанный на щелчках мышью. Пользова-
тельский интерфейс также легко создается дизайнером с минимальным объе-
мом сценарного кода. В Flash MX Professional 2004 появились новые средства
Slides и Forms (объединенные общим термином Screens), упрощающие визуальную
разработку за счет изоляции разработчика от парадигмы временной диаграммы.
Вместо этого парадигма разработки приближается к стилю PowerPoint или Visual
Basic.
Flash MX и Flash MX 2004 содержат многочисленные компоненты (см. трюк 73)
для построения пользовательских интерфейсов - поля со списками, переключа-
тели и т. д. Эти компоненты упрощают разработку и последующую модифи-
кацию (на базе скинов) пользовательского интерфейса. Конечно, вы также мо-
жете создавать собственные элементы вроде кнопок (см. трюк 14) и бегунков
(см. трюк 61).
ActionScript также включает встроенные методы, упрощающие интерактивное
управление мультимедийными потоками (звуком и видео) при использовании
классов Sound, Microphone и Camera.
290 Глава 8. Элементы пользовательского интерфейса

В любом случае главная задача Flash - увлечь пользователя. Даже при исполь-
зовании технологии Flash в коммерческих или образовательных целях содержа-
ние должно быть увлекательным, иначе вы рискуете потерять старых зрителей
и не сможете привлечь новых.
В одних случаях интерфейс должен быть лаконичным и четким, в других случа-
ях требуется создать нечто необычное, что понравится пользователю и будет
соответствовать его ожиданиям. В конечном счете дизайнер сайта или разработ-
чик сам выбирает стиль с учетом предполагаемой аудитории и своих художе-
ственных наклонностей, а иногда и изменяет его на основании обратной связи
с пользователями.
Тем не менее, книга посвящена не проектированию интерфейсов, а нестандарт-
ным применениям Flash. По этой причине трюки настоящей главы посвящены
нетривиальному применению элементов пользовательского интерфейса в Flash.
Некоторые из них позволяют преодолеть очевидные недостатки средств органи-
зации пользовательского интерфейса Flash. Но как показывает первый трюк,
интерфейсные элементы предназначены не только для конечного пользовате-
ля - иногда они могут упростить процесс разработки программы.
Если уж речь зашла о пользовательских интерфейсах стадии разработки, Flash
MX 2004 и Flash MX Professional 2004 поддерживают концепцию расширяемос-
ти, то есть возможности не только настройки среды разработки Flash, но и до-,
бавления/модификации ее отдельных компонентов.
Среда разработки Flash настраивается средствами JSAPI (JavaScript API) с ис-
пользованием диалекта JavaScript, специфического для среды Flash JSFL (со-
кращение означает «Flash JavaScript» - да, меня тоже раздражают обратные
акронимы).
Как известно большинству веб-дизайнеров, JavaScript предоставляет прямой
доступ к пользовательскому интерфейсу браузера и всем открытым документам
HTML при помощи модели DOM (Document Object Model). Однако, в отличие,
от браузерной модели DOM, модель JSFL DOM предоставляет доступ к пользо-
вательскому интерфейсу среды разработки и всем открытым документам FLA.
Используя JSFL и связанную с ним модель, вы можете:
• обратиться к любой части открытого в настоящий момент документа Flash
(FLA) и отредактировать его на программном уровне. Данная возможность
позволяет создавать расширенные команды, вызываемые из меню Commands,
для автоматизации рабочего процесса или создания новых инструментов;
• модифицировать пользовательский интерфейс среды разработки Flash - напри-
мер, создать новые инструменты на панели элементов. Один из таких инстру-
ментов (PolyStar) отображается, если щелкнуть на инструменте Rectangle
и удерживать кнопку мыши;
• экспортировать SWF из командной строки Windows, как описано по адресу
http://moock.org/blog/archives/000058.html.
Кроме того, вы можете создавать пользовательские панели и запросчики (reques-
ters) для организации взаимодействия между сценариями JSFL и пользовате-
лем, что позволит не только запускать сценарии для модификации интерфейса
среды разработки Flash, но и настраивать разные аспекты работы самих сцена-
Интерактивное тестирование 291

риев JSFL! Для этой цели используется специальный язык на базе XML, XML to
UI, который дает возможность создавать пользовательские модификации интер-
фейса, работающие в среде разработки Flash и обеспечивающие взаимодействие
между пользователем и вашим кодом JSFL. Также предусмотрена возможность
взаимодействия между стандартным ActionScript и JSFL, поэтому воспроизве-
дение SWF может использоваться как часть пользовательского интерфейса.
Функция MM Execute () позволяет выполняемому SWF (обычно внедренному в ин-
терфейс XML to UI) запускать сценарии JSFL; так создаются большие нестан-
дартные интерфейсы с множеством автоматизированных задач и инструментов
на одной пользовательской панели.
Более того, фирма Macromedia использовала средства расширяемости в Flash
MX 2004 для реализации ряда новых возможностей, в том числе Timeline Effects,
Behaviors и записи макросов через панель History- Интересно, когда сторонние фирмы
начнут использовать JSAPI, XML to UI и MMExecuteQ для настройки среды раз-
работки Flash и распространять свои модификации среди других разработчиков
(учтите, что применение JSAPI, XML to UI и MMExecute() ограничивается ста-
дией разработки; эти возможности не предназначены для использования на ста-
дии выполнения в Flash Player)?

ТРЮК Интерактивное тестирование


№61 Область применения элементов пользовательского интерфейса не огра-
ничивается стадией выполнения. Использование их во время разработки
ускоряет тестирование различных ситуаций.
При каждом посещении конференции Flash я узнаю что-то новое. Обычно это
просто полезная информация вроде особенностей использования компонентов
Flash MX 2004 или сервера FlashCom. Но время от времени попадаются трюки и
фокусы, которые на первый взгляд кажутся тривиальными, но в действительно-
сти оказывают заметное влияние на мой рабочий процесс. Перед вами один из
таких трюков.
Во время нашей беседы с Эмитом Питару и Джеймсом Патерсоном Джеймс
сказал что-то вроде следующего: «Ну, я делаю анимацию, тут приходит Эмит и го-
ворит: "Давай-ка поставим сюда шкалу" - мы немного повозились и опробовали
разные варианты. Когда нас все устроило, текущее состояние было закреплено».
Примерно в то же время я посетил презентацию авторов сайта Banja (http://
www.banja.com). Banja - полноценная, сложная приключенческая игра, поэтому
я полагал, что авторы написали код с определениями данных для каждой лока-
ции, но я ошибался. Они использовали более сложную версию «шкалы Эмита».
С каждой локацией в игре были связаны данные, которые вводились при помо-
щи многочисленных внеэкранных полей и бегунков. Добавление новой локации
не требовало обновления части кода (или конфигурационного файла) - все на-
стройки осуществлялись на визуальном уровне и хранились в одном файле.
Модификации ограничивались прорисовкой локации и заполнением внеэкран-
ных элементов - никакие изменения в программном коде были не нужны.
Давайте разберемся, как работает этот механизм.
292 Глава 8. Элементы пользовательского интерфейса

Прежде всего создается «шкала» - так Эмит называет любой регулируемый


элемент пользовательского интерфейса вроде бегунка или поворотной рукоят-
ки. Элемент вовсе не обязан входить в число встроенных компонентов пользо-
вательского интерфейса Flash - более того, мы обычно избегали их, чтобы не
увеличивать размер файла.
В следующем примере в роли «шкалы» выступит простой бегунок с числовыми
данными. Для начала создайте одиночную волосяную линию длиной 200 еди-
ниц и преобразуйте ее в символ клипа; поместите точку регистрации на середи-
не линии (рис. 8.1). По этой линии будет перемещаться наш бегунок. Присвойте
символу имя slider.

Рис. 8 . 1 . Линия, в середине которой находится точка регистрации

Создайте в символе клипа slider новый слой с именем puck. Создайте на слое
puck небольшой квадрат размером 10 х 10, преобразуйте его в символ puck
и разместите точку регистрации в центре квадрата. Затем поместите его в пози-
цию (- 5, -5) и задайте клипу имя экземпляра puckjnc (рис. 8.2).

| Movie Clip

X: -5.С
PI Jf'}

Рис. 8.2. Клип puck_mc, размещенный на линии

Наконец, создайте над слоем по умолчанию новый слой с именем actions и при-
соедините следующий код к кадру 1 слоя actions:
puckjnc.onPress = function() {
this.startDragUrue. -100. 0. 100. 0);
this.onMouseMove = _onMouseMove:
}:
jonMouseMove = functionО {
parent[_name + "_txt"].text = this._x;
updateAfterEventO:
}:
_parent[_name + "_txt"].onChanged = functionO {
puckjnc._x = Number(this.text);
}:
puckjnc.onRelease = puckjnc.onReleaseOutside = functionO {
this.stopDragO;
}:
_parent[_name + "_txt"].onChanged():
Приведенный фрагмент обеспечивает перетаскивание puckjnc вдоль линии.
Кроме того, клип puckjnc связывается с текстовым полем, находящимся на од-
Интерактивное тестирование 293

ной временной диаграмме с клипом slider. Имя текстового поля совпадает с име-
нем клипа slider и снабжается суффиксом _txt (sliderjxt).

Использование бегунка
При построении рекурсивных деревьев (см. трюк 6) я подбирал начальные зна-
чения основных параметров при помощи бегунков. В коде присутствовали два
параметра, значения которых мне было трудно подобрать на интуитивном уров-
не: angle (угол роста веток) и branch (густота ветвления).
Сначала я просто закомментировал фрагмент программы, в котором определя-
лись эти переменные:
// angle = 10;
// branch = 2:
Затем я быстро создал символ slider, разместил несколько экземпляров slider
и связанных внеэкранных текстовых полей (рис. 8.3).

initialize

—•

. .. тщ•
...... ••

-'; i
т

Рис. 8.3. Бегунки для подбора параметров генератора деревьев

Первый бегунок помечается статической надписью «angle», ему назначается имя


экземпляра valueOI. Текстовому полю справа от него (с числом 80) присвоено
имя valueO1_txt. При запуске SWF манипулятор бегунка перемещается в позицию,
соответствующую значению 80 по шкале от -100 до 100. Щелкая и перетаскивая
манипулятор, мы изменяем значение в поле valueO1.txt. Если разрешить ввод
в текстовом поле, то значение можно будет ввести напрямую, а бегунок автома-
тически перейдет в новую позицию. Чтобы текстовое поле управляло значением
переменной angle, закомментированной в предыдущем коде, выделите поле
valueO1_txt на сцене и введите строку angle в поле Var панели свойств.
Поле Var, эквивалентное свойству TextField.variable, сохранено для совместимос-
ти со стилем прямого присваивания текстовому полю, применявшемуся в Flash 5.
В Flash Player 6 и выше для чтения/записи содержимого текстовых полей реко-
мендуется использовать свойство TextField.text. Без использования свойства text
некоторые компоненты (например, полосы прокрутки) могут неправильно реа-
гировать на изменения текстового поля. Однако мы не применяли компоненты
при построении бегунка, а программа всего лишь демонстрирует трюк, поэтому
для простоты в ней используется поле Var.
294 Глава 8. Элементы пользовательского интерфейса

Далее приводится версия с использованием свойства text. Подготовительная фа-


за слегка изменяется: для управления переменной angle текстовому полю долж-
но быть назначено имя экземпляра angle_txt, а бегунку - имя экземпляра
angle_mc. В то же время заполнять поле Var на панели свойств уже не обяза-
тельно.
// Имя текстового поля совпадает с именем бегунка
// и дополняется суффиксом "_txt"
this.targetTextField = _parent[_name.split("_")[O] + "_txt"];

// Имя переменной совпадает с именем текстового поля до "_".


this.targetTextField.targetVariable = _name.split("_")[O]
puckjnc.onPress = functionO {
this.startDrag(true. -100. 0. 100. 0);
this.onMouseMove = _onMouseMove:
}:
_onMouseMove = functionO {
this.parent.targetTextField.text = this._x;
this .parent.targetTextField.onChangedO;
updateAfterEventO:
}:
this. targetTextFi el d.onChanged = functionO {
puckjnc.x = Number(this.text):
this._parent[this.targetVariable] = Number(this.text);
}:
puckjnc.onRelease = puck_mc.onReleaseOutside = functionO {
this.stopDragO;
}:
this.targetTextFi eld.onChanged();
Какую бы методику вы не выбрали (с полем Var или со свойством text), появ-
ляется возможность быстрого изменения входных данных - перемещение бе-
гунка приведет к изменению переменной angle и построению разных деревьев
(рис. 8.4).
Кто-нибудь из читателей скажет: «Но ведь то же самое можно сделать в отлад-
чике!» Верно, но визуальное решение позволяет сразу выделить критические
переменные, а результат настройки можно зафиксировать без изменения напи-
санного кода.
Когда результат вас полностью устроит, запомните значения всех переменных,
остановите SWF и введите значения прямо в текстовые поля (например,
valueO1_txt или angle_txt) в документе FLA. Выбранные значения будут присво-
ены переменным при публикации SWF. После того как дизайн придет к окон-
чательному виду, просто удалите бегунки со сцены, а текстовые поля оставьте
невидимыми.
Интерактивное тестирование 295

•сэ
•со
•пз
•CD

Рис. 8.4. Два дерева, сгенерированные с разными входными параметрами

Итоги
Чем больше думаешь об этой методике, тем лучше раскрываются ее достоин-
ства. В любой ситуации, когда у вас нет полной уверенности относительно вход-
ных значений, просто свяжите их с элементами пользовательского интерфейса
и поэкспериментируйте. Данная методика помогает подобрать начальные значе-
ния переменных даже в том случае, если вся логика уже запрограммирована.
Вам не придется возвращаться к программе и вносить изменения, потому что
настраиваемые переменные были отделены от кодовой базы. Если подобрать
начальные значения не удается, возможно, этот факт поможет вам осознать не-
достатки исходной логики и необходимость ее изменения.
Разработчики сайта Banja использовали стандартный набор элементов для визу-
альной настройки локаций - чрезвычайно полезная возможность для команды,
в которую входят как программисты, так и дизайнеры. Программист пишет код
Action Script и создает внеэкранные элементы. Дизайнер готовит графику и на-
страивает переходы при помощи элементов пользовательского интерфейса. Та-
ким образом, эта методика пригодится даже «чистому» программисту, поскольку
она позволяет другим изменять входные данные, не прикасаясь к написанному
296 Глава 8. Элементы пользовательского интерфейса

коду. Более того, элементы можно оставить в итоговом пользовательском интер-


фейсе, чтобы пользователь мог сам вносить изменения в работу программы или
анимацию! Если вы не хотите оставлять текстовые поля в ролике, закодируйте
их итоговые значения в ActionScript и удалите поля вместе с бегунками.

ТРЮК Правая ксредняя кнопки мыши


№62 Документированные обработчики событий Flash реагируют только на ос-
новную кнопку мыши. Для проверки состояния дополнительных кнопок мож-
но воспользоваться недокументированными возможностями ActionScript.
Хотя МЫЕШ оснащается двумя и более кнопками, Flash обнаруживает события
только для основной кнопки мыши (обычно это левая кнопка, хотя основную
кнопку можно сменить на панели управления Windows).

Класс 800
В Flash не предусмотрены документированные средства для работы с правой
и средней кнопками мыши. К счастью, недокументированная функция ASnative()
позволяет вызывать дополнительные внутренние методы ActionScript (см. трюк 83)
с использованием числовых индексов, приблизительно соответствующих встроен-
ным классам.
Похоже, при вызове ASnative() с аргументом 800 появляется возможность вызова
методов ввода/вывода классов Key и Mouse, в том числе и недокументирован-
ных. Попробуйте выполнить следующий фрагмент:
this.onEnterFrame = functionO {
i f (ASnative(800; 2)(D) {
trace("Detected something..."): ,

Если выполнить этот код и щелкнуть левой кнопкой мыши, сценарий выведет
строку «Detected something...». Оказывается, вызов ASnative(800,2)(1) возвраща-
ет информацию о состоянии левой кнопки мыши: 1 (логическая истина), если
кнопка нажата, или 0 (логическая ложь), если кнопка не нажата. Хотя факт
нажатия левой кнопки мыши можно обнаружить при помощи документирован-
ного события Mouse.onMouseDown, приведенный выше код позволяет проверить
его состояние на текущий момент (например, чтобы узнать, остается ли левад
кнопка нажатой, без установки флага и ожидания события Mouse.onMouseUp).
Если последний аргумент вызова ASnativeQ равен не 1, а 2, результат получается
еще более интересным - функция возвращает информацию о состоянии правой
кнопки мыши:
this.onEnterFrame = functionO {
i f (ASnative(800. 2)(2)) {
trace("Right-click!"):
Правая и средняя кнопки мыши 297

Если последний аргумент равен 4, вызов ASnative() возвращает значение, кото-


рое меняется на противоположное при каждом изменении состояния средней
кнопки трехкнопочной мыши. Большинство мышей для Windows имеет колесо,
которое может использоваться в качестве третьей кнопки; нажатие и отпускание
колеса эквивалентно «щелчку третьей кнопкой».
this.onEnterFrame = functionO {
i f (ASnative(800. 2)(4)) { ,,
trace("Middle mouse button has changed state"):

Итак, теперь мы можем проверять состояния левой, правой и средней кнопок мы-
ши! Если мышь имеет более трех кнопок, состояния дополнительных кнопок про-
веряются вызовами ASnative(800,2)(5) и ASnative(800,2)(6). Вызов ASnative(800,2)(3)
вроде бы ничего не делает (по крайней мере, при вводе данных с мыши).

ПРИМЕЧАНИЕ
Функция ASnative() не документирована, а следовательно, не поддерживается
официально. Вызовы ASnative(), описанные в тексте, работают в Flash Player 5,
6 и 7, но они не прошли полного тестирования, а их работоспособность в буду-
щих версиях не гарантирована.

В этой методике состояние кнопок мыши проверяется посредством опроса в об-


работчике onEnterFrame, потому что основная кнопка мыши генерирует только
события onMouseDown и onMouseUp.
Конечно, опрос неэффективно расходует ресурсы процессора, поэтому этот спо-
соб следует применять лишь при крайней необходимости. Разумеется, код опро-
са не следует включать в клип, поскольку множественные экземпляры клипа
будут выполнять избыточный опрос (ведь состояние кнопок мыши остается од-
ним и тем же независимо от того, каким клипом оно проверяется). Вместо этого
следует организовать централизованный опрос и рассылать события объектам,
зарегистрированным в качестве слушателей. Файл rightMousePoller.fla, находя-
щийся на сайте книги, демонстрирует различия между двумя подходами. В нем
созданы четыре «плохих» и три «хороших» слушателя. Если щелкнуть правой
кнопкой мыши, все семь слушателей сообщают, сколько раз выполнялся опрос
для получения результата. Для «хороших» слушателей это число всегда будет
меньше, потому что все три слушателя обслуживаются одним опросчиком, тогда
как каждый «плохой» слушатель выполняет опрос сам для себя.

Итоги
Мыши для Macintosh часто имеют только одну кнопку, поэтому описанная ме-
тодика применима в основном для Windows. Тем не менее, если вы захотите
проверить состояние правой кнопки мыши, учтите, что при тестировании в бра-
узере щелчок правой кнопкой вызывает меню Flash Player. У третьей кнопки
функция по умолчанию отсутствует, но так как в большинстве программ третья
кнопка не используется, многие пользователи закрепляют за ней какую-нибудь
специализированную функцию - например, сворачивание всех окон на рабочем
298 Глава 8. Элементы пользовательского интерфейса

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


этому не стоит предполагать наличие третьей кнопки для выполнения важных
функций. Короче говоря, данный трюк в основном стоит рассматривать как ку-
рьез, если только вы не используете специализированное оборудование с пол-
ным управлением конфигурацией мыши и программного обеспечения (напри-
мер, интернет-киоск).
Flash Player 7 поддерживает новое свойство TextField.mouseWheelEnabled для
прокрутки текстовых полей с помощью колеса мыши. Flash Player 7 для Windows
также поддерживает нового слушателя события Mouse.onMovieWheel, оповещае-
мого о перемещении колеса мыши.

ТРЮК Кнопочные клипы


№63 Создание расширенных кнопок Flash на базе класса MovieClip (вместо
класса Button).
Кнопки Flash традиционно создаются как экземпляры класса Button (не путайте
с компонентом Flash MX Button из пакета mx.components). Кнопка Flash имеет
три состояния (up, down, over), кроме того, с ней связывается некоторая область
попадания. Flash отображает состояние up, когда указатель мыши находится за
пределами кнопки, состояние over - когда указатель мыши проходит над кноп-
кой, и состояние down - когда пользователь щелкает на кнопке мышью. Облас-
тью попадания называется графический объект, определяющий совокупность
точек, щелчок на которых интерпретируется как щелчок на кнопке. Часто этот
объект совпадает по размерам с графическими объектами состояний up, over
и down. Все атрибуты представлены кадрами на временной диаграмме символа
кнопки (рис. 8.5).

Рис. 8.5. Состояния кнопки представлены именованными кадрами


на временной диаграмме

Стандартные кнопки легко создаются и понятно работают. Они очень полезны


для новичков и дизайнеров, торопящихся со сдачей проекта. Класс Button содер-
жит многие свойства и обработчики событий класса MovieClip, но ни одного из
его методов, а также не имеет полноценной временной диаграммы. Соответствен-
но, вам не удастся заставить экземпляр кнопки работать как нормальный анима-
ционный клип. Но если учесть, что клипы Flash MX и Flash MX 2004 поддержи-
вают все методы класса Button, можно создать кнопочный клип, то есть клип,
который работает как полноценная кнопка.
Дизайнер с навыками программирования на Action Script вообще может обой-
тись без стандартных кнопок. Кнопочные клипы обладают рядом особенностей,
которые просто не реализуются при использовании стандартных кнопок. В ча-
стности, кнопочные клипы могут:
• использовать методы класса MovieClip, не поддерживаемые классом Button;
Кнопочные клипы 299

• определять обработчик события onEnterFrame для анимации кнопки;


• создаваться динамически на стадии выполнения.
Кнопочный клип не является новым типом символа. Это вполне обычный клип!
Чтобы создать кнопочный клип, который обладает всеми возможностями стан-
дартных кнопок, начните с создания символа клипа с именем hit. В символе hit
задайте первому слою имя actions, а затем создайте второй слой с именем hit, как
показано на рис. 8.6.

п г

Рис. в.6. Создание области попадания для кнопочного клипа

На слое hit должен находиться прямоугольник (или круг, если вы предпочитаете


круглые кнопки), эта фигура определяет область идентификации щелчков на
кнопках. Свяжите с кадром 1 слоя actions следующий сценарий:
this._visible = false;
_parent.hitArea = this;
Создайте второй символ клипа, который будет служить кнопочным клипом, и при-
свойте ему имя clipButton. Переименуйте его первый слой в actions. На панели
свойств задайте первому кадру слоя actions имя _ир. Создайте еще два ключевых
кадра (Insert • Timeiline • Keyframe или Insert • Timeline • Blank Keyframe) и задайте
им метки _over и down (рис. 8.7).

J j П t"P * over
П о— nr down
U|o—
so— r U
Рис. 8.7. Имитация состояний кнопок посредством создания
именованных кадров в клипе

Г!
ПРИМЕЧАНИЕ
Чтобы кнопочный клип нормально работал, необходимо использовать именно
метки _up, _over и _down, соответствующие трем состояниям кнопки.

Свяжите с каждым ключевым кадром операцию stop() (по одной операции для
каждого состояния кнопки) при помощи панели Actions.
Разместите три графических представления кнопки в трех ключевых кадрах
так, как вы бы сделали это для обычной кнопки; используйте столько дополни-
тельных слоев, сколько потребуется. Разместите все новые слои под уровнем
actions (рис. 8.8).
300 Глава 8. Элементы пользовательского интерфейса

Рис. 8.8. Состояния кнопки в кнопочном клипе

Добавьте новый слой с именем hit (рис. 8.9). В первом кадре этого слоя размес-
тите экземпляр символа клина hit; если потребуется, измените его размеры по
размерам графики в других кадрах. Затем скройте слой hit.

Рис. 8.9. Размещение клипа hit на слое hit главного кнопочного клипа

Если теперь разместить экземпляр кнопочного клипа на сцене и присоединить


к нему сценарий, клип будет вести себя точно так же, как обычная кнопка. Ина-
че говоря, после прикрепления обработчика событий кнопки анимационный клип
работает как кнопка. Для этого сначала присвойте кнопочному клипу имя эк-
земпляра (например, cButton) на панели свойств. Затем создайте на главной вре-
менной диаграмме (не на временной диаграмме клипа!) новый слой с именем
actions и свяжите с его первым кадром следующий сценарий:
cButton.onRelease = functionO {
traceC'you clicked me");
}:
Как же работает описанная схема?
При связывании кнопочного сценария с клипом (что было сделано косвенно
с использованием предыдущего фрагмента ActionScript на главной временной
диаграмме вместо присоединения сценария к временной диаграмме клипа) Flash
направляет индикатор текущей позиции на кадры с метками _up, _over и „down
при возникновении соответствующих событий.
Сценарий, связанный с символом клипа hit, назначает его невидимой областью
попаданий для родительского клипа (то есть для нашего кнопочного клипа).
Все это, конечно, хорошо, но пока мы не увидели ничего принципиального ново-
го или заслуживающего наименования «трюка». Все, что у нас получилось, -
это клип, который работает как стандартная кнопка.
Однако с кнопочными клипами можно делать то, что невозможно сделать со
стандартными кнопками.
Прежде всего вы можете использовать методы класса MovieClip, в том числе и те,
которые не поддерживаются классом Button. Например, клип можно перевести
в нужное состояние на программном уровне, без операций с мышью. Если выз-
вать метод cButton.gotoAndStop("_over"), кнопочный клип перейдет в состояние,
которое обычно активизируется при нахождении над ним указателя мыши. Та-
кая возможность может пригодиться для динамического изменения кнопок.
Кнопочные клипы 301

Например, если кнопка предназначена для загрузки изображения, в свободном


состоянии на ней можно отображать сообщение «load image», а в нажатом - со-
общение «loading...». Или другой вариант - когда пользователь щелкает на кнопке,
она должна остаться в нажатом состоянии до полной загрузки изображения,
даже если пользователь отпустил кнопку мыши. Задача легко решается методом
MovieClip.gotoAndStop{).
Другая интересная возможность - связывание обработчиков onEnterFrame с кно-
почным клипом. В частности, это позволит анимировать элементы пользова-
тельского интерфейса после щелчка. В следующем сценарии кнопочный клип
работает как обычная кнопка до тех пор, пока на нем не будет сделан щелчок.
В обработчике onRelease кнопка удаляет свой обработчик onRelease и определяет
обработчик onEnterFrame, который уводит ее за пределы экрана (слева направо):
btnjnc.onRelease = function О {
// Операции кнопки (не приводятся).
// Возвращение к анимированному клипу,
delete this.onRelease;
this.onEnterFrame = functionO {
i f (this._x < 600) {
this._x += 10:
} else {
delete this.onEnterFrame:

Но еще важнее другое - появляется возможность динамического создания кно-


почных клипов методами MovieClip.duplicateMovieClipO и MovieClip.attachMovie() и
размещения в них текста методом MovieClip.createTextField(). Co стандартными
кнопками это невозможно, потому что класс Button не поддерживает указанные
методы.
Таким образом, эмулируя кнопку на базе анимационного клина, мы получаем
массу возможностей, выходящих за рамки стандартных кнопок. А если модифи-
цировать кнопочный клип и использовать нетривиальные возможности времен-
ной диаграммы, можно будет реализовать дополнительную функциональность.

Добавление состояний кнопок


В кнопочный клип легко добавляются новые состояния кнопок. Простейшее
решение основано на включении всего необходимого кода во все клипы через
свойство MovieClip.prototype (работает в ActionScript 1.0 и 2.0):
MovieClip.prototype.disable = functionO {
this.enabled = false;
thi s.gotoAndStopC"_di sable");
}:
Приведенный фрагмент включает в класс MovieClip метод disable(). Этот метод
переводит временную диаграмму кнопочного клипа к кадру _disable; фактически
мы создаем новое состояние блокировки, в котором клип не реагирует на события.
302 Глава 8. Элементы пользовательского интерфейса

Чтобы реализовать состояние блокировки, добавьте соответствующее изображе-


ние (обычно это графика _ир, оттененная серым цветом) в кадр с меткой _disable
на временной диаграмме кнопочного клипа (рис. 8.10).

зо .:• 35
"disable'

Рис. 8.10. Определение состояния блокировки для кнопочного клипа

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


ду лишь несколько примеров:
• состояние выдачи справки, в котором через секунду после события onRollOver
рядом с кнопкой появляется справочный текст, исчезающий по событию
onRollOut;
• состояние по умолчанию (исходное состояние кнопки до первого щелчка).
Если в кадре 1 на кнопку помещается исходное изображение, а переход к со-
стоянию _ир происходит лишь после первого щелчка (после этого кнопка
будет постоянно находиться в состоянии _ир, пока указатель мыши находит-
ся за ее пределами);
• анимированные состояния кнопок (без внедрения клипов). Вместо того что-
бы останавливать временную диаграмму в каждом состоянии, позвольте вре-
менной диаграмме продолжить анимацию. Не забудьте остановить анимацию
на последнем кадре текущего состояния, пока она не перешла к следующему
состоянию!

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

ТРЮК Полосы прокрутки


№64 Создание упрощенного компонента полосы прокрутки для Flash MX 2004.

Компоненты v2, входящие в комплект поставки Flash MX 2004, ориентированы


на создание сложных пользовательских интерфейсов и RIA. По сравнению с ком-
понентами vl в них был внесен ряд усовершенствований, включая поддержку
управления глубиной и управления передачей фокуса#с клавиатуры. Компонен-
ты v2 были полностью переписаны для ActionScript 2.0 (в частности, в них ис-
пользовались строгая типизация данных и различия в регистре символов). В них
Полосы прокрутки 303

используется общая архитектура компонентов, спроектированная для оптими-


зации размера файла при использовании пяти и более компонентов в одном
SWF-ролике (согласно исследованиям Macromedia, эта ситуация вполне типична).
Тем не менее, компоненты Flash MX 2004 не могут использоваться как простая
замена для компонентов Flash MX vl, что объясняется рядом причин:
• первый компонент v2, включенный в SWF, требует дополнительных 30 Кбайт
данных для инициализации классов библиотеки компонентов. Правда, при
включении дополнительных компонентах объем загружаемого файла увели-
чивается незначительно, поскольку все компоненты v2 работают на общей
основе;
• среди компонентов v2 для Flash MX 2004 нет автономной полосы прокрутки
(хотя ожидается, что в версии 7.2 этот компонент появится).
При экспортировании SWF в формат Flash Player 7 нельзя просто использовать
старые компоненты vl> поскольку старые компоненты не соответствуют требо-
ваниям Flash Player 7 к регистру символов (данная тема обсуждается на страни-
це http://swfoo.com/archives/000034.html). Даже если обновить файл Flash MX
(Flash Player 6) до формата Flash MX 2004 (Flash Player 7) и включить различия
в регистре символов в сценарии, код, связанный с компонентами vl, может
отказаться работать из-за несогласованности регистра символов и преобразова-
ния типов в самих компонентов, а также различий в поведении некоторых
встроенных функций ActionScript в Flash Player 6 и 7. Обходное решение этой
проблемы - использовать обновленные «компоненты Flash MX для Flash MX
2004», как описано далее.
Существует немало компонентов, разработанных сторонними фирмами, но все
же было бы неплохо использовать компоненты Macromedia для обеспечения
совместимости с будущими версиями Flash Player (Macromedia прикладывает
серьезные усилия к тому, чтобы старые SWF без изменений работали в новых
версиях Flash Player).
Автономная полоса прокрутки входила в число компонентов vl в Flash MX.
Этот компонент может использоваться в Flash MX 2004 при экспортировании
SWF в формат Flash Player 6 (хотя смешивать компоненты vl и v2 в одном
проекте не рекомендуется). Версии компонентов vl, совместимые с Flash Player 7,
но занимающие меньший объем, чем компоненты v2, находятся в хранилище
Flash Exchange по адресу http://www.macromedia.com/exchange/flash в категории
User Interface, под заголовком «Flash MX Components for Flash MX 2004».
К Flash Exchange также можно обратиться командой Flash Help • Flash Exchange.
Компоненты vl распространяются в формате файлов .mxp. Для их установки
необходимо установить программу Macromedia Extension Manager, также дос-
тупную в Flash Exchange.
После установки обновленные компоненты Flash MX появляются на панели
Components Flash MX 2004 в категории Flash MX Ul Components (рис. 8.11). Ком-
поненты Flash MX 2004 выделены на панели Components в отдельную категорию
и не смешиваются с обычными компонентами пользовательского интерфейса
в категории Ul Components.
304 Глава 8. Элементы пользовательского интерфейса

ChedcBox
Up ComboBox
-Щ ListBox
-!ll PushButton
•• Д RadioButton
Ц SaollBar
•••§^ ScrollPsne
i Media Components
I Ul Components

Рис. 8 . 1 1 . Категория Flash MX Ul Components на панели Components в Flash MX 2004

Компоненты Flash MX не обладают всеми эффектными возможностями компо-


нентов Flash MX 2004. Тем не менее, если вам всего лишь нужно использовать
полосу прокрутки для текстового поля или другого элемента с прокруткой
(рис. 8.12), просто перетащите полосу прокрутки с панели Components и разме-
стите ее на сцене точно так же, как в Flash MX. Элемент будет нормально работать
даже в том случае, если в параметрах публикации будет выбран формат Flash
Player 7 и ActionScript 2.0. Но самое приятное - то, что полоса прокрутки
Flash MX увеличивает размер SWF-файла всего на 6 Кбайт.

Dim; SSO X 405 pbceb


Fr rste;
32 KB-
iS KB-
Size; 6 KB £643i B) 8 KB-
Duration: [
It 16 fr {1.3 s} IKBi
403 Bl

Frasne; 1
6 KB (6433 B)

applications. They are Щ


not without one or two ^
disadvantages though;

Рис. 8.12. Использование компонента Scrollbar


Полосы прокрутки 305

Итоги
Прогресс - замечательная вещь, и компоненты Flash MX 2004 обладают множе-
ством дополнительных возможностей. Они обеспечивают управление глубиной
и передачей фокуса, вывод вспомогательной информации для пользователей с де-
фектами зрения... но иногда все, что вам нужно, - это самая обычная полоса
прокрутки!
В таких ситуациях (а особенно если увеличение размера файла на 30 Кбайт ради
одного компонента неприемлемо) следует использовать надежную хорошо зна-
комую полосу прокрутки Flash MX из компонентов vl.
ГЛ Д В Д 9

Быстродействие и оптимизация
Трюки № 65-73
Механизм анимации Flash не блещет быстротой, потому что основным критери-
ем оптимизации Flash Player была не скорость, а минимальный размер передава-
емого файла. Кроме того, этот механизм проектировался с расчетом на исполь-
зование в Веб, то есть оптимизация ориентировалась на малые файлы, а не на
большие, сложные анимации. Для обеспечения минимального уровня требова-
ний и максимальной совместимости Flash Player не поддерживает аппаратное
ускорение. Из-за этого Flash-дизайнеры часто сталкиваются с проблемами быс-
тродействия.
В Flash можно выделить следующие области потенциальной оптимизации:
• сокращение времени загрузки за счет эффективного использования объема
контента или изменения способа загрузки (см. трюк 73);
• повышение скорости анимации посредством оптимизации перерисовки;
• повышение скорости обработки данных посредством написания быстро вы-
полняемого кода.
Все перечисленные способы более подробно описаны далее.

Оптимизация размера файла и времени загрузки


Технология Flash начиналась с простого модуля векторной анимации для Веб,
но сейчас она нередко используется и для более серьезных приложений. Дизай-
нер должен позаботиться о том, чтобы пользователю не приходилось подолгу
ждать загрузки контента. Чтобы обеспечить минимальное время ожидания, не-
обходимо почаще тестировать сайт на стадии разработки.
До выхода обновления Flash MX 2004 версии 7.0.1 встроенный профайлер обла-
дал минимальными средствами реалистичного моделирования сайтов, исполь-
зующих несколько SWF и внешних ресурсов. Хотя последняя версия способна
тестировать несколько SWF и вести статистику использования внешних ресур-
сов, она по-прежнему не обеспечивает совместного использования шрифтов и не
позволяет протестировать сайт из браузера.
Инструментарий независимых фирм (см. трюк 66) позволяет преодолеть огра-
ничения встроенного профайлера и протестировать весь сайт (то есть как ресур-
Быстродействие и оптимизация 307

сы Flash, так и внешние ресурсы) в условиях канала с низкой пропускной спо-


собностью непосредственно в браузере.

Оптимизация графики
Широкое распространение Flash в немалой степени объясняется малыми размерами
Flash Player и способностью создания контента для каналов с низкой пропуск-
ной способностью. Тем не менее, за оптимизацию размера файла приходится
расплачиваться снижением быстродействия при возрастании сложности.
Векторная графика более компактна, чем другие графические форматы, поскольку
в ней определяются не низкоуровневые графические данные, а математические
объекты (точки, кривые и заливки), необходимые для прорисовки изображения
на стадии выполнения. Тем не менее, преобразование векторных данных в ито-
говое изображение занимает много времени, к тому же эту операцию приходит-
ся выполнять при каждом изменении внешнего вида или позиции графики. Если
изображение содержит области со сложными контурами или заливками, изме-
няющиеся в каждом кадре, анимация будет работать довольно медленно.
В этой главе рассматриваются некоторые методы борьбы со снижением быстро-
действия, специфическим для векторной графики. В частности, будут описаны
общие рекомендации по проектированию графики (см. трюк 68) и замене век-
торных изображений растровыми (см. трюк 72).

Повышение быстродействия кода


В отличие от таких языков, как C++, ActionScript не компилируется в низко-
уровневый машинный код. Вместо этого он преобразуется в байт-код, который
превосходит интерпретируемые языки по скорости обработки, но уступает ма-
шинному коду. Хотя ActionScript может быть медленным, в большинстве муль-
тимедийных презентаций основные ограничения по быстродействию обычно
обусловлены графикой, аудио и видео. Более того, общее быстродействие (то
есть субъективное быстродействие с точки зрения пользователя) также зависит
от времени загрузки, а не только от времени выполнения. Конечно, в RIA-при-
ложениях, работающих с базами данных, быстродействие также будет зависеть
от скорости обработки запросов, эффективности передачи данных и их пред-
ставления.
Многие трюки, описанные в книге, связаны с оптимизацией ActionScript. Более
того:
• Flash Player 7 изначально оптимизирован для кода с большим количеством
вызовов функций и локальных переменных (см. трюк 100), поэтому старые
приемы стали менее актуальными;
• многие приемы оптимизации не являются специфическими для ActionScript
и представляют собой хорошо известные методы, применяемые при програм-
мировании на любых языках без оптимизирующего компилятора. Например,
для ускорения циклов из них выносятся все элементы, не изменяющиеся при
каждой итерации;
308 Глава 9. Быстродействие и оптимизация

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


вам стоит сократить масштаб приложения или поискать другое решение про-
блемы. Например, попробуйте выявить и ликвидировать критические точки
посредством оптимизации графики;
• помните, что быстродействие - показатель субъективный (см. трюк 71). Если
попытаться выполнить слишком много работы в одном кадре, Flash не успеет
построить изображение и пользователь заметит замедление. Если разбить
выполняемую работу на несколько частей, Flash успеет обновить сцену за по-
ложенное время и пользователь ничего не заметит.
Хотя правильно написанный код ActionScript обычно не содержит «узких мест»,
возможности для улучшения остаются всегда. Читателям, интересующимся те-
мой оптимизации ActionScript, стоит ознакомиться со следующими ссылками:
• gotoAndPlay (http://www.gotoandplay.it/_articles/2004/01/as_optimizations.php) -
учебник по оптимизации ActionScript;
• Odd Hammer (http://www.oddharnmer.com/actionscriptperformance) - сравни-
тельные тесты производительности разных приемов оптимизации ActionScript
в разных версиях Flash Player.
В этой главе мы рассмотрим методы анализа и оптимизации быстродействия
в тех областях, которые с наибольшей вероятностью влияют на быстродействие
на стадии выполнения, время загрузки и субъективные впечатления пользовате-
ля. Как это часто бывает, выбор оптимальной методики зависит от ситуации,
поэтому вам нередко придется выбирать между скоростью и удобством исполь-
зования или временем загрузки и быстродействием на стадии выполнения. Трю-
ки этой главы помогут вам сделать разумный выбор в конкретной ситуации.
На страницах книги встречаются и другие трюки, связанные с оптимизацией, -
например, оптимизация звука (см. трюк 58) или анимация текста (см. трюк 28).

Борьба с разрастанием файлов Flash


Иногда можно заметить, что документ FLA увеличивается в размерах при
каждом сохранении, даже если из него удаляются неиспользуемые ре-

~ сурсы (графика и звук). Данный трюк поможет вам справиться с разрас-
танием файлов.
При публикации Flash-контента одной из главных проблем становится размер
загружаемого файла. Чем меньше опубликованный файл, тем быстрее проходит
загрузка. При компиляции FLA в SWF Flash исключает из библиотеки неис-
пользуемые ресурсы (см. трюк 73). Тем не менее, исходный FLA-файл содержит
не только исходные ресурсы библиотеки, но даже те старые ресурсы, которые
были из нее удалены! Именно по этой причине происходит разрастание FLA-фай-
лов. На SWF-файлы оно не распространяется, и все же об этой проблеме следу-
ет знать.
В версиях, предшествующих Flash MX 2004, файлы увеличивались при каждом
сохранении командой File • Save, даже после удаления из них неиспользуемых
ресурсов. Хотя команда Flash MX 2004 File • Save and Compact уменьшает размер
Борьба с разрастанием файлов Flash 309

файла FLA, в более ранних версиях Flash эта команда не поддерживается. Более
того, файл, сохраненный в формате Flash MX 2004, не удастся открыть в преды-
дущих версиях (хотя Flash MX 2004 и Flash MX Professional 2004 используют
общий формат файла).

Почему увеличиваются файлы?


Так что же вызывает эффект разрастания файлов? Во всех версиях Flash коман-
да File • Save сохраняет в FLA только информацию об изменениях по сравнению
с предыдущей версией (так называемое добавочное сохранение). Flash не опти-
мизирует сохраняемые файлы, исключая из них удаленные данные.
Чтобы убедиться в этом, создайте новый FLA-файл и импортируйте в него боль-
шой ресурс (например, растровое изображение или звуковой файл). Затем со-
храните файл командой File • Save; также молено использовать комбинацию кла-
виш Ctrl+S (Windows) или 3S+S (Mac). Запомните размер сохраненного файла.
Затем удалите большой ресурс со сцены и из библиотеки, после чего сохраните
файл заново командой File • Save. Вы увидите, что размер файла остался неиз-
менным даже после удаления ресурса!
В этом заключается причина разрастания файлов: при внесении изменений в FLA-
файл удаляемые данные остаются в сохраненном файле. Теперь представьте, что
вы временно использовали какие-то запатентованные материалы (или другие, ко-
торые бы вам почему-либо не хотелось афишировать), а затем случайно переда-
ли их клиенту. Конечно, чтобы получить эти данные, клиенту придется пере-
компилировать FLA (см. трюк 98), но лучше сразу застраховаться от возможных
неприятностей. Конечно, обычно в Веб публикуются только SWF-файлы, и все
же не забывайте сохранять FLA-файлы со сжатием, передавая их кому-либо в ка-
честве примеров, а также при распространении среди клиентов или коллег.

Решение проблемы
Заставить Flash сжимать FLA-файлы можно двумя способами. Это:
• сохранение файла командой File • Save and Compact (только в Flash MX 2004
и Flash MX Professional 2004). В процессе сохранения Flash удаляет всю лиш-
нюю информацию. При этом весь файл переписывается заново, поэтому опера-
ция занимает больше времени в зависимости от объема сохраняемого контента.
Открыть файл в предыдущих версиях Flash не удастся, так что будьте внима-
тельны и сохраняйте архивы унаследованных FLA-файлов! Архив лучше хра-
нить под другим именем на тот случай, если операция сжатия почему-либо
завершится неудачей;
• сохранение и переименование файла командой File • Save As (все версии
Flash). Происходит то же самое, что и при выполнении команды File • Save
and Compact, но с переименованием файла. Переименование окажется по-
лезным на случай сбоев при сохранении, однако файл можно сохранить и под
исходным именем - когда Flash выдаст предупреждение о том, что файл
уже существует (щелкните на кнопке Yes).
310 Глава 9. Быстродействие и оптимизация

Так почему же Macromedia не изменит свой продукт так, чтобы команда File • Save
выполняла сохранение одновременно со сжатием? Дело в том, что добавочное
сохранение выполняется гораздо быстрее. Таким образом, оптимальная схема
выглядит так:
• для частых сохранений используйте комбинации клавиш Ctrl+S (или <HS+S).
Файл сохраняется практически мгновенно, что позволяет продолжить работу
без задержек;
• периодически архивируйте файл, чтобы предотвратить потерю данных и при
необходимости иметь возможность вернуться к предыдущей версии;
• время от времени выполняйте команду File • Save As или File • Save and Compact
(например, в конце дня или перед архивацией файлов), чтобы сохранить файл
со сжатием;
• прежде чем создавать постоягшую архивную копию FLA-файла, создайте ре-
зервную копию. Затем удалите лишние ресурсы из библиотеки (помните, что
ресурсы, используемые из ActionScript, удалять нельзя). Затем сохраните
и сожмите файл одним из способов, описанных ранее, чтобы свести к мини-
муму его объем при хранении.

Итоги
Проблема с разрастанием файлов была учтена в Flash MX 2004, однако вы все
равно должны хорошо разбираться в сути этой проблемы, чтобы эффективно
организовать свой рабочий процесс. В ходе Flash-разработки часто происходят
многочисленные изменения в дизайне и наборах ресурсов, поэтому файлы раз-
растаются очень быстро. Минимизация размера FLA-файлов ускоряет их за-
грузку в среде разработки и экономит место при архивировании и пересылке.
Аналогичные проблемы существуют и в других коммерческих программных про-
дуктах, в том числе в Macromedia Director и Microsoft Word.

Тестирование загрузки канала связи


ТРЮК

№66 для сложных сайтов


WebSpeed Simulator помогает справиться с таким недостатком Bandwidth
Profiler, как невозможность протестировать загрузку канала в браузере.
В процессе работы над сайтом требуется узнать, сколько времени потребуется
для его загрузки на определенной скорости подключения. Полученная информа-
ция поможет создать наилучшее впечатление у посетителей сайта, большинство
из которых работает на более медленных подключениях, чем разработчики. Встро-
енный профайлер Flash Bandwidth Profiler позволяет оценить время загрузки
одиночного SWF-файла при имитации в режиме тестирования. Для этого следу-
ет включить режим тестирования командой Control • Test Movie, а затем открыть
окно Bandwidth Profiler командой View • Bandwidth Profiler. Тем не менее, Bandwidth
Profiler предполагает идеально работающее подключение, поэтому выберите ско-
рость подключения чуть ниже самой низкой ожидаемой скорости. Например,
для имитации типичного модема со скоростью 56 Кбит/с лучше выбрать ско-
рость 28,8 Кбит/с.
Тестирование загрузки канала связи для сложных сайтов 311

И все же Bandwidth Profiler, включенный в поставку Flash MX 2004 версии 7.0,


слишком примитивен для нетривиальных сайтов. Коммерческие сайты на базе
Flash обычно не ограничиваются единственным SWF-файлом. На стадии выполне-
ния загружаются дополнительные ресурсы - вторичные SWF-файлы, графика, звук
МРЗ, видеофайлы, удаленные данные и текстовые файлы (CSS, XML и т. д.) До
выхода обновления Flash MX 2004 7.0.1 Bandwidth Profiler не включал эти ресурсы
в имитацию, поэтому время загрузки оказывалось заниженным. Полезной альтер-
нативой для Bandwidth Profiler является WebSpeed Simulator (http://www.xat.com).
Работа программы основана на создании локального сервера HTTP с ограничен-
ной скоростью канала. В частности, WebSpeed Simulator позволяет:
• наблюдать из браузера в реальном времени за процессом загрузки сайта в ими-
тируемом подключении с ограниченной скоростью канала;
• просматривать содержимое кэша браузера, снабженное временными помет-
ками. Таким образом можно узнать порядок загрузки файлов (а также состав
данных, остающихся в кэше после посещения сайта).
WebSpeed Simulator чрезвычайно прост в использовании. С другой стороны, рабо-
тая в режиме сервера HTTP, он не способен эмулировать защищенные серверы.
Допустим, мы хотим протестировать сайт с локального жесткого диска. Щелкните
на кнопке Setup на панели инструментов WebSpeed Simulator (на экране появляет-
ся диалоговое окно Setup Web Server (рис. 9.1) и задайте местонахождение сайта
(то есть местонахождение папки с домашней страницей - например, index.html).
Возможно, вам также придется очистить кэш браузера, хотя это зависит от его
текущих настроек. Так, очистка кэша в Internet Explorer осуществляется ко-
мандой Сервис • Свойства обозревателя • Общие • Удалить файлы (Tools • Internet
Options • General • Delete Temporary Internet Files).

R
*** ^'i5i^ffr,^ ..^LocalW^tetonbcalhaiddnve)
,Ht Name Ил Foidl! .
~~" i C:\Documents and SettinqtASham B\My Documents^Flash Sites Щ>.

"' Remote Website (oyet a network)


URL: www.xat.com
Port:: [SO (Defaultis 90) ;::
:
•WebSpeed Simulator Options
P Corivert Absolute Links to Local Links
\ i Port:
Г :
(Defautis8j) : Г Log hits to file

ШШАШ: :,:;:.'pK•-.'.', |. Cancel:


i
I
L.
......... :,.
icresses... ^'^Ж^Й^Ш^ШШЙШ!!^
Рис. 9 . 1 . Диалоговое окно Setup Web Server в WebSpeed Simulator
312 Глава 9. Быстродействие и оптимизация

Затем щелкните на кнопке Restrict и введите скорость имитируемого подключе-


ния в диалоговом окне Restrict Web Server (рис. 9.2). В этом окне выполните
также сохрание содержимое кэша браузера (тогда при повторном посещении
сайта контент, уже находящийся в кэше браузера, загрузится немедленно).

Link Speed Emulation. \Ш

CustuiTi speed (6it/s): : j > •:

: : IJik Utilization % . : — | 5 T 3 I
1ЩШ • • •-.•' , I.

f Allow ВFowser.Caching,.; :

Рис. 9 . 2 . Диалоговое окно Restrict Web Server в WebSpeed Simulator

Щелкните на кнопке Browse. Имитатор направляет браузер в папку, заданную


во время начальной настройки, и начинает выполнять функции сервера с про-
пускной способностью, заданной в диалоговом окне Restrict Web Server. В про-
цессе загрузки объектов в браузере WebSpeed Simulator выводит информацию
о времени загрузки каждого файла, порядке загрузки и размере файлов (рис. 9.3).

Fife Ve
i w. Server '.-..Help.

:;Setep; Res tret ; о


<
[ | dracjpg In Fodler satcom;: About
C:pocumeRts and Settings^ham В Н у Docum... 12KB
oad/
2.1 Sees
LJ burnmediajrionstaf .s.wf Ci'poatmentsandSettings^hameV^yDocum... 1.9КБ 3.4 Sees
p
[ J bummedia_game.swf C:V3oi:uments and Setbngs^ham ВЩ- Docum....
CiVJocuments and Settings'^ham 8V*1y Docum...
29KB
Ж6
5.3Sees
1.2 Sees
Q тал .swd Ci'ftocuments and Settings'^ham 8f\^ Oocum... 211KB 38.6 Sees
Q mairi.svrf Ci^ocuments and Settings\Sham В ^ y Docum... 80KB 14, S Sees
Gl hdexvswf С; '-Documents and Settirigs'^ham ВЩ</ Docum... -KB 0.7 Sees
[ | index Jhtml С:'documents and Settings^ham БуИу Docum... 1KB 0.1 Sees
Ш 302 Redrecbon

I l i i i i i i i i i i i
Waiting for web accesses.. ;Uptirne: OOhOBrn

Рис. 9.З. Результаты работы WebSpeed Simulator

Я часто использую WebSpeed Simulator во время работы с Flash. Эта программа


заполняет пробелы Bandwidth Profiler и предоставляет удобный интерфейс для
тестирования в условиях разных пропускных способностей каналов. Настройка
выполняется достаточно тривиально; для проведения тестирования на разных
Маскировка последствий снижения качества 313

скоростях вам не придется изменять параметры браузера или физического под-


ключения, так что программа легко интегрируется в обычный рабочий процесс.
Она даже позволяет проводить измерения на смешанных сайтах HTML+Flash,
тогда как Flash Bandwidth Profiler работает только с SWF-файлами. Опыт рабо-
ты с WebSpeed Simulator показывает, что его данные весьма точны, - время,
предсказанное программой, оказывается очень близким к фактическому време-
ни загрузки контента.

Итоги
Хотя WebSpeed Simulator распространяется не бесплатно (программа стоит $99,
но пользователям предоставляется 30-дневный пробный период), эта среда луч-
ше всего подходит для тестирования требований к пропускной способности ка-
нала в процессе разработки веб-сайтов, особенно многофайловых.
Если WebSpeed Simulator будет постоянно находиться у вас под рукой во время
разработки, это поможет избежать многих неприятных сюрпризов. Программа
настраивается элементарно, поэтому вы сможете, например, продемонстриро-
вать клиенту работу сайта в имитируемых условиях на портативном компьюте-
ре. Подобные демонстрации помогут клиенту лучше понять, как пропускная
способность канала отразится на работе сайта, и принять более обоснованные
решения. Этот способ подходит для приложений Flash, загружающих большое
количество динамических данных, поэтому он окажет бесценную помощь как
разработчикам RIA, так и дизайнерам компьютерных анимаций.

Маскировка последствий снижения


ТРЮК

№67 качества
Повышение быстродействия и сохранение внешней привлекательности
за счет маскировки последствий снижения качества.
Повышение качества неизбежно приводит к снижению быстродействия, поэто-
му в Flash существуют несколько режимов визуализации с разным качеством.
Хорошо разобравшись в этой теме, вы сможете принимать правильные решения
в конкретных ситуациях и обходить некоторые недостатки встроенных режимов
визуализации.
Механизм визуализации обычно использует сглаживание для маскировки рез-
ких краев векторных контуров и субъективного повышения качества. Резкие
переходы между областями контрастных цветов сглаживаются за счет добавле-
ния пикселов промежуточных оттенков. На кривой в левой части рис. 9.4 хоро-
шо видны неровности, возникшие из-за того, что слишком большой размер пик-
селов не позволяет точно воспроизвести кривую. Сглаженная кривая справа
выглядит более ровной.
Учтите, что сглаживание не исправляет ошибки, а лишь скрывает их от чело-
веческого глаза посредством смягчения перехода между контрастными цве-
тами.
314 Глава 9. Быстродействие и оптимизация

Сглаживание интенсивно расходует мощности процессора, поэтому иногда его


приходится отключать ради повышения быстродействия.

'•..

"ч.
Рис. 9.4. Исходная (слева) и сглаженная (справа) кривые

Глобальное отключение сглаживания для всего контента, отображаемого в Flash


Player, производится следующей строкой:
_quality = "LOW":
Качество визуализации также можно задать командой File • Publish Settings •
HTML • Quality. Учтите, что свойства MovieClip._quality и TextField._quality являют-
ся обычными синонимами для глобального свойства quality и определяют гло-
бальный режим сглаживания. Качество визуализации не может задаваться на
уровне отдельных экземпляров.
Кроме значения "LOW", свойство quality также может принимать значения
"AUTOLOW", "MEDIUM", "AUTOHIGH", "HIGH" и "BEST". В режимах с высоким каче-
ством сглаживаются текст, а также растровая и векторная графика. В режимах
с низким качеством сглаживание не выполняется вообще. Дополнительную ин-
формацию о режимах визуализации можно получить на панели Help (команда
Help • Help или клавиша F1), выполнив поиск по ключевому слову «_quality».
На практике рекомендуется использовать максимальное качество, обеспечивае-
мое вашим контентом и компьютерами пользователей. Обычно это означает ре-
жим "BEST" для больших статических сайтов, режимы "HIGH" и "MEDIUM" для
большинства общего контента и режим "LOW" в тех случаях, где скорость имеет
критическое значение (например, в играх).
При выборе режимов "AUTOHIGH" и "AUTOLOW" обеспечивают избирательное
применение сглаживания. В этих режимах Flash автоматически переключается
между сглаженным и несглаженным выводом в зависимости от скорости вос-
произведения на компьютере, на котором выполняется анимация. Режим "AUTO-
HIGH" начинает работать с включенным сглаживанием и отключает его при ухуд-
шении быстродействия (то есть при неприемлемом снижении частоты смены
кадров), тогда как режим "AUTOLOW" не применяет сглаживания изначально, но
включает его при достижении правильной частоты смены кадров.
Режимы с префиксом "AUTO" используются редко, потому что переход от высо-
кого качества к низкому обычно хорошо заметен и раздражает пользователя.
Маскировка последствий снижения качества 315

Для выбора оптимального быстродействия попробуйте задать режим "LOW" и по


возможности скрыть снижение качества изображения.

Применение малоконтрастных цветов


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

Рис. 9.5. Сглаженная {справа) и несглаженная (слева) кривые на малоконтрастном фоне

Если вы пытаетесь повысить субъективное качество изображения за счет приме-


нения малоконтрастных цветов, избегайте некоторых цветовых комбинаций:
• Черный цвет на белом и желтом фоне - две самые контрастные комбинации
цветов. Наибольший контраст составляют черный и желтый цвета, именно
поэтому пчелы и осы имеют черно-желтую предупреждающую окраску, а те-
лефонные справочники печатаются на желтых страницах).
• Человеческий глаз наиболее чувствителен к зеленому цвету. Соответственно,
он лучше различает оттенки зеленого, чем оттенки красного или синего. При
прочих равных условиях старайтесь избегать зеленого цвета при использова-
нии режимов с низким качеством вывода.
• Существует несколько типов «цветовой слепоты» с множеством разновидно-
стей вдоль всего спектра, но самый распространенный недостаток - дальто-
низм, или неумение различать красный и зеленый цвета. Избегайте цветовых
схем с красным цветом на зеленом фоне или зеленым - на красном фоне.
За дополнительной информацией о цветовых схемах для пользователей с рас-
стройствами зрения обращайтесь на сайт Toledo-Bend (http://www.toledo-
bend.com/colorblind), где обсуждаются различные дефекты цветового вос-
приятия.
316 Глава 9. Быстродействие и оптимизация

Другие приемы
Существуют и другие способы маскировки неровностей на векторных контурах.
Попробуйте сделать так, чтобы фигуры в ваших анимациях были заполнены
прямоугольными заливками (по возможности), быстро перемещались или со-
стояли только из вертикальных и горизонтальных линий.
Горизонтальные и вертикальные линии, в том числе и стороны прямоугольни-
ков, не нуждаются в сглаживании. С другой стороны, на быстро движущейся
фигуре неровности просто не разглядеть. Последнее обстоятельство может ис-
пользоваться в видеоиграх, написанных на Flash. На начальной заставке или
экране с инструкциями для игрока использование режимов "HIGH" и "BEST" не
повредит быстродействию, но при переходе к самой игре быстрая графика выхо-
дит на первый план, поэтому с большой вероятностью качество стоит снизить.
Кроме того, если объекты в игре движутся достаточно быстро (а статическая
графика состоит только из вертикальных и горизонтальных линий, как в игре
Pacman), пользователь даже не заметит снижения качества.
Впрочем, следует учитывать некоторые обстоятельства: при проектировании
графики для вывода на видео избегайте горизонтальных линий толщиной 1 пик-
сел. Поскольку на обычном телевизоре используется чересстрочный видеосиг-
нал, линии должны иметь толщину минимум 2 пиксела, чтобы предотвратить
мерцание. Даже при воспроизведении видеороликов в некоторых алгоритмах
сжатия могут возникать проблемы с очень тонкими линиями, поэтому проведи-
те тестирование перед выбором окончательного варианта дизайна.
Впрочем, даже идеально горизонтальные и вертикальные линия иногда выигры-
вают от сглаживания. Это особенно заметно для ярких цветов, воспроизводи-
мых на белом фоне.

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

The q u i c k b r o w n fox jumps over the lazy d o g .

Рис. 9.6. Растровые шрифты и мелкий текст лучше смотрятся без сглаживания

Общая информация о растровых шрифтах приводится в списке FAQ на сайте Web


Page Design for Designers (http://www.wpdfd.com/pffaq.htm). Учебник по примене-
нию растровых шрифтов находится по адресу http://www.wpdfd.com.wdtypo3a.htm.
Оптимизация графики 317

Далее приводится список ресурсов, посвященных специфике применения рас-


тровых шрифтов в Flash:
• Minimi (http://www.miniml.com) - коллекция растровых шрифтов, созданных
на базе векторных;
• Fonts for Flash (http://www.freepixelfonts.com/faqs.html) - список FAQ о при-
менении растровых шрифтов в Flash;
• Best Flash (http://www.bestflashanimationsite.com/pixel-fonts) - ссылки на ре-
сурсы, посвященные работе с растровыми шрифтами в Flash.

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

ТРЮК Оптимизация графики


№68 Графика вносит большой вклад в объем данных, передаваемых по кана-
лу связи. Оптимизация графики способна заметно повысить общее быс-
тродействие приложения.
Графический механизм Flash проектировался для снижения объема контента за
счет применения векторной графики вместо растровой. После того как графика
будет загружена на компьютер пользователя, основное время обычно затрачива-
ется на визуализацию изображения на сцене (время выполнения большинства
сценариев ActionScript обычно пренебрежимо мало). Чем большая часть сцены
обновляется в одном кадре, тем медленнее происходит графический вывод. Та-
ким образом, для вывода больших векторных изображений, несмотря на малый
объем данных, все равно необходимо время.
В следующем разделе приводятся рекомендации по ускорению работы Flash-сай-
тов, основанные на собственном опыте автора, а также других разработчиков.

Скорость как фактор проектирования


Звучит тривиально, но большинство разработчиков забывает, что Flash не успе-
вает сделать все сразу. Вот лишь некоторые операции, приводящие к снижению
быстродействия:
• Загрузка контента. Потоковая подгрузка анимации параллельно с воспроизве-
дением снижает максимально достижимую частоту смены кадров по сравнению
318 Глава 9. Быстродействие и оптимизация

с предварительной загрузкой контента и его воспроизведением после полной


загрузки. Часто лучше выдать экран с просьбой подождать, чем пытаться
воспроизводить анимацию до завершения ее полной загрузки (в этом случае
все равно придется ждать подгрузки, но в процессе воспроизведения).
• Воспроизведение МРЗ-файлов, особенно длинных. МРЗ-файлы распаковываются
во время воспроизведения, причем в ходе распаковки интенсивно использу-
ется процессор. Flash легко справляется с одним-двумя короткими звуками,
но при длительных звуках и выводе с несколькими звуковыми каналами можно
ожидать замедления анимации.
• Обновление текстовых полей. Обновление содержимого текстовых полей на
каждом кадре - одна из самых затратных операций, которая легко предот-
вращается. Вместо этого значения текстовых полей следует обновлять толь-
ко при фактическом изменении их содержимого или по крайней мере на-
столько редко, насколько это возможно. Например, таймер, отображающий
время в секундах, не обязательно обновлять с частотой смены кадров 30 fps.
Вместо этого лучше сохранить старое значение и обновлять текстовое поле
только в том случае, если новое значение отличается от предыдущего.
• Использование компонентов Flash MX 2004 v2. Обычно компоненты использу-
ются в приложениях с минимальной анимацией, поэтому быстродействие
компонентов не является определяющим фактором. Компоненты Flash MX
2004 v2 явно не были рассчитаны на минимальные требования. Они не только
занимают большой объем: одновременное размещение нескольких компонен-
тов на экране приводит к заметному снижению быстродействия. Если вы
хотите, чтобы анимация шла быстро, используйте компоненты Flash MX vl
(см. трюк 73) или пользовательские компоненты или разработайте упрощен-
ный интерфейс, не требующий применения компонентов.

Создание и тестирование оптимизированной графики


Растровая графика превосходит векторную по объему пересылаемых данных, но
пикселы, необходимые для построения изображения, не нужно заново пересчи-
тывать на стадии выполнения. Полностью загруженное растровое изображение
выводится на экран относительно быстро. С векторной графикой дело обстоит
наоборот. Векторные изображения хранятся в виде математических описаний,
поэтому они чрезвычайно компактны. Тем не менее, в отличие от растровых
изображений, пикселы, задействованные в отображении векторного содержимо-
го, вычисляются на стадии выполнения. Иногда применение растровой графики
вместо векторной (см. трюк 72) позволяет повысить быстродействие, но на прак-
тике все же чаще применяется векторная графика, с которой проще и удобнее
работать в Flash.
Следующие рекомендации помогают создать векторную графику, которая быст-
ро выводится на экран:
• Постарайтесь обойтись без прозрачности (альфа-канала). Flash анализирует
каждый пиксел, находящийся под прозрачной фигурой, что существенно за-
медляет вывод. Чтобы скрыть клип, задайте его свойству visible значение
Оптимизация графики 319

false, вместо того чтобы обнулять свойство _alpha. Иначе говоря, графика
быстрее всего воспроизводится при свойстве _alpha=100. Присваивание
временной диаграмме клипа пустого ключевого кадра (то есть полное от-
сутствие отображаемого контента) обычно способствует повышению быстро-
действия. Впрочем, иногда Flash пытается воспроизводить невидимые кли-
пы; попробуйте задать свойствам _х и _у значения (-1000, -1000) помимо
задания свойства _visible=false, чтобы полностью предотвратить подобные по-
пытки.
• Избегайте применения градиентных заливок. По возможности старайтесь за-
менять их растровыми заливками.
• Скорость графического вывода зависит от количества точек в кадре. Всегда
оптимизируйте сконструированные фигуры - откройте подменю Modify •
Shape и выберите одну из команд, Smooth, Straighten или Optimize (в зависи-
мости от типа фигуры), чтобы сократить количество точек, необходимых для
прорисовки фигуры. Замена контуров волосяными линиями (или их полная
отмена) существенно снижает количество необходимых точек. Чтобы узнать
количество точек в контуре, выделите его инструментом Subselection; если
теперь щелкнуть на любом из участков, вы увидите входящие в него точки.
• Скорость графического вывода в Flash также связана с количеством пиксе-
лов, изменяющихся между кадрами, поэтому постарайтесь избегать больших
изменений. Анимированный контент должен занимать как можно меньше
места - например, при уменьшении изображения на 10 % по каждому на-
правлению его общая площадь сокращается на 19 %. Если сцена содержит
несколько копий одного символа, экономия быстро накапливается.
• По возможности используйте пустые (лишенные заливок) фигуры или дру-
гие фигуры, сокращающие количество выводимых пикселов.

ПРИМЕЧАНИЕ
без применения альфа-эффектов пикселы, не изменяющиеся между кадрами,
практически не влияют на быстродействие.

Итоги
Итоговое быстродействие анимации Flash определяется многими факторами.
Оптимизация графики - одна из областей, оказывающих наиболее серьезное
влияние. Вообще говоря, оптимизация графики может выполняться на любой
стадии разработки, но наибольший эффект она приносит на более ранних стади-
ях. Если ждать до последней минуты, у вас останется мало времени, и многие
меры, которые можно было бы принять раньше (например, отмена прозрачнос-
ти), создадут гораздо больше трудностей. Мораль: оптимизируйте как можно
раньше и как можно чаще.
Сторонние программы оптимизации векторной графики - такие как Optimaze
(http://www.vecta3d.com) - уменьшают размер файлов до 60 % и ускоряют вы-
вод, потому что оптимизированные векторные данные проще обрабатываются.
320 Глава 9. Быстродействие и оптимизация

ТРЮК Хронометраж
№69 Bandwidth Profiler и утилиты независимых фирм позволяют оценить вре-
мя загрузки проекта Flash. Эталонное тестирование быстродействия так-
же поможет оптимизировать процесс воспроизведения.
Встроенный Bandwidth Profiler и программа WebSpeed Simulator (см. трюк 66)
оценивают предполагаемое время загрузки, но не решают проблему хронометра-
жа на стадии выполнения. Если скорость загрузки зависит от скорости подклю-
чения, то скорость выполнения определяется вычислительной мощностью ком-
пьютера, на котором воспроизводится ролик. Общее впечатление пользователя
складывается из времени загрузки и скорости воспроизведения, поэтому вы дол-
жны выбрать разумный компромисс между этими факторами - например, заме-
нить векторные изображения растровыми (см. трюк 72).
Многие склонны связывать скорость воспроизведения с частотой смены кадров,
выбранной разработчиком. Если Flash успевает прорисовать все за время, отве-
денное для вывода следующего кадра, тогда не так уж важно, остается у него
свободное время или нет. Но при таком подходе упускаются из виду проблемы,
которые могут возникнуть при повышении частоты смены кадров. Лучше зара-
нее определить, анимация какой графики занимает больше всего времени и ка-
кие сценарии ActionScript выполняются дольше других. Это позволит оптими-
зировать выполняемые операции и зарезервировать процессорное время для
других целей (например, для воспроизведения звука).
Далее приводится программа, которую я использую для проверки результатов
оптимизации. Вместо события onEnterFrame, привязанного к частоте смены кад-
ров, в ней используется интервальный таймер продолжительностью 1 мс, со-
зданный функцией setlnterval() (см. трюк 27). Программа заставляет Flash пе-
рерисовывать экран с максимальной частотой, хотя перерисовка и не будет
выполняться каждую миллисекунду по ограничениям, обусловленным быстро-
действием (скорее, это будет происходить примерно раз в 3 мс).
function animate(target) {
// Сценарий для перемещения клипа target по сцене
target._х = (target._х + I) % 400;
count++;
updateAfterEventO;
}
function controller() {
clearlnterval(animater);
// Вывод среднего времени перерисовки (в миллисекундах).
trace(clip[clipPointer]+ " " + 20000/count):
// 20-секундная анимация следующего клипа
// (если еще остались клипы для тестирования).
clipPointer++;
i f (clipPointer < clip.length) {
count = 0;
animater = setlnterval(animate. 1. c l i p [ c l i p P o i n t e r ] ) ;
} else {
// Если клипов не осталось - остановиться.
Хронометраж 321

clearlnterval(timer);

// Настройка
var clip:Array = new ArrayO;
var clipPointer:Number = 0;
var count .-Number = 0:
clip[0] = clipOl:
c l i p [ l ] = clipO2;
clip[2] = clipO3;
var animater:Number = setlnterval(animate. 1. clip[cl1pPointer]);
var timerNumber = setlnterval (controller, 20000):
Если clipOl, clipO2 и clipO3 являются тремя экземплярами одного клипа (напри-
мер, тремя версиями одной фигуры с разными уровнями оптимизации кривой
из подменю Modify • Shape), программа анимирует каждый экземпляр с макси-
мально возможной скоростью в течение 20 с. Далее выводится среднее время
перерисовки клипа в миллисекундах, и полученные результаты используются
для сравнительного анализа.

П
ПРИМЕЧАНИЕ
Представленная программа предназначена для тестирования умеренно слож-
ных фигур. Она не учитывает времени, потраченного на выполнение кода, но
дает представление о соотношении времен перерисовки.

Тестирование по такой схеме дает объективные данные, не зависящие от быст-


родействия системы. Конечно, такая информация гораздо надежнее простого
опроса бета-тестеров на тему «не притормаживает ли анимация?». Вы можете
накопить статистику по разным компьютерам, особенно по маломощным, и по-
добрать оптимальное соотношение между внешним видом и быстродействием.
Часто выясняется, что небольшое снижение качества (остающееся незаметным
для пользователя) заметно увеличивает быстродействие приложения.

Итоги
Применяя программный хронометраж, вы получите более реалистичную оценку
быстродействия, чем полагаясь на общие правила оптимизации. Хронометраж
поможет провести сравнительный анализ разных приемов экономии ресурсов
процессора. Например, сложные фигуры с большим количеством точек могут
анимироваться быстрее, чем простой, но большой круг. Более того, однородная
фигура, движущаяся перед растром, может снизить быстродействие в большей
степени, чем клип с прозрачностью, движущийся на гораздо более простом фоне.
Программный хронометраж позволит лучше понять, какой фактор оказывает
наибольшее влияние на быстродействие в конкретной анимации. Такой тип хро-
нометража лучше всего подходит для сравнения приемов, а не для получения
оценок скорости анимации или приложения в реальных условиях (см. трюк 70),
поскольку этот показатель сильно зависит от компьютера конечного пользовате-
ля и текущей загрузки системы.
322 Глава 9. Быстродействие и оптимизация

Динамическая настройка скорости


ТРЮК

№70 анимации
Измерение производительности Flash Player во время выполнения по-
зволяет выполнить динамическую регулировку эффектов или анимации
для достижения оптимального быстродействия как на мощных, так и на
слабых компьютерах.
Ранее мы рассматривали приемы повышения быстродействия, основанные на
оптимизации ресурсов Flash на стадии разработки; эти приемы не зависели от
компьютера, на котором воспроизводится анимация. В сущности, оптимизация
такого рода составляет минимальный набор «на все случаи жизни». Трюк, опи-
санный в этом разделе, позволяет повысить до максимума качество анимации
и других эффектов на мощных компьютерах, но при этом сохранить нормаль-
ную работоспособность на более медленных машинах.
Хотя Flash Player 7 работает быстрее предыдущих версий, он все еще не идеа-
лен. Проектировщики Flash стремились оптимизировать размер файлов (для
уменьшения времени загрузки), а не добиться потрясающего быстродействия.
Хотя быстродействие можно улучшить посредством снижения качества
(см. трюк 67), во многих случаях отключение сглаживания оказывается непри-
емлемым из-за того, что сайт начинает выглядеть слишком убого.
Другой, более правильный способ повышения быстродействия основан на регу-
лировке сложности (то есть объема работы, выполняемой за один кадр) графи-
ческого эффекта, а не качества или частоты смены кадров. В широком диапазоне
пользовательских систем с разной вычислительной мощностью такой подход
дает лучший результат, чем «универсальная» оптимизация.
Регулировка сложности часто является итеративным процессом, основанным
на экспериментах (со временем она станет вашей второй натурой и потребует
меньшего числа итераций):
• задайте нужную частоту смены кадров - например, 18 fps;
• измерьте фактическую частоту смены кадров (см. далее);
• если нужная частота смены кадров недостижима на тестовом компьютере,
уменьшите сложность эффекта;
• если эффект воспроизводится достаточно быстро, значит, его сложность можно
повысить.
Теперь, когда вы знаете основную схему динамической регулировки эффектов,
попробуем автоматизировать ее, чтобы Flash принимал решение об уменьшении
или повышении сложности анимации. Тем самым мы избавимся от «торможе-
ния» на медленных компьютерах и добьемся улучшения эффектов (при грамот-
ной реализации) на быстрых.
Изменяться будет не частота смены кадров, а сложность эффекта, причем
так, чтобы модификация полностью завершалась перед началом следующего
кадра.
Динамическая настройка скорости анимации 323

Вычисление фактической частоты смены кадров


Следующий код создает пустой клип perfMon и связывает с ним обработчик
события onEnterFrame. Обработчик события вычисляет среднюю продолжитель-
ность вывода кадра (в миллисекундах) по данным двух последних измерений
и накапливает скользящее среднее time. Это значение проверяется по ожидае-
мой продолжительности FRAME_DUR, и в зависимости от того, удается ли Flash
Player обеспечить нужную частоту смены кадров, логическому флагу slow при-
сваивается значение true или false.
function performanceMonitorO {
thi s.createEmptyMovi eCli p("perfMon", 10000);
perfMon.onEnterFrame = functionO {
time = (getTimerO - lastTime)/2;
lastTime = getTimerO;
// Переменной slow присваивается true или false
// в зависимости от того, превышает ли время вывода
// допустимое значение.
slow = time > FRAMEDUR;

}
// Переменной FRAME_RATE присваивается целевая частота смены кадров.
var FRAME_RATE:Number = 18;
var FRAMEJUR: Number = (1 / FRAME_RATE) * 1000:
var time:Number = 0;
vdr lastTime:Number = getTimerO;
performanceMonitor():
Переменная slow=false означает, что Flash Player может выполнить дополнитель-
ную работу без снижения быстродействия, потому что вся необходимая работа
выполняется до начала следующего кадра. В идеальном случае Flash Player дол-
жен завершать обработку текущего кадра непосредственно перед началом сле-
дующего кадра. Мы узнаем об этом, когда скользящее среднее time сравняется
с ожидаемой продолжительностью вывода кадра FRAME_DUR.

Регулировка сложности в зависимости


от быстродействия
Давайте посмотрим, как увеличить или уменьшить сложность анимации в зависи-
мости от полученных данных. Один из простых способов - увеличивать или умень-
шать число клипов в зависимости от состояния флага slow. Для примера возьмем
эффект звездного потока (см. трюк 33). Следующий код предполагает, что по
умолчанию сцена содержит 550 х 400 пикселов с темным фоном. Оптимальная
работа эффекта достигается при частоте смены кадров 18-24 fps. Чтобы изменить
цвет фона и частоту смены кадров, выполните команду Modify • Document и задайте
нужные значения свойств. В следующей программе используется частота смены
кадров 24 fps; если вы выберете другую частоту, измените следующую строку:
var FRAME RATE:Number = 24;
324 Глава 9. Быстродействие и оптимизация

Обратите внимание: настройку приходится выполнять вручную, потому что


в Flash нет метода или свойства, возвращающего целевую частоту смены кадров
(странно, но факт!).
Функция starfield() из трюка 33 была изменена так, чтобы она при каждом вызо-
ве рисовала только одну звезду. Вместо того чтобы устанавливать флаг slow при
малой скорости анимации, мы регулируем ее сложность в команде if. Если анима-
ция идет достаточно быстро, мы рисуем дополнительные звезды функцией
starfieldQ в противном случае для сохранения быстродействия звезды удаляются.
Еще раз подчеркну важное обстоятельство: мы изменяем не частоту смены кад-
ров, а сложность анимации, чтобы время, затраченное на построение каждого
кадра анимации, сравнялось с полным промежутком, определяемым заданной
частотой.
function performanceMonitorO {
var perfMon:MovieClip = this.createEmptyMovieClipC'perfMon". 10000):
perfMon.onEnterFrame = functionO {
time = (getTimerO - lastTime)/2;
i f (time<(FRAME_DUR)) {
// Нормальная скорость
stars++;
starFieldO;
} else i f (time>(FRAME_DUR+10)) {
// Слишком медленно
_root["star"+stars].removeMovieClip();
stars--;
}
lastTime = getTimerO;

}
function moverO {
this._y += this.speed:
this._yscale += this.speed;
i f (this._y>275) {
this._y = 0;
this.speed = Math.ceil (Math.randomO * 10);
this._yscale = 100:

function starFieldO {
var star:MovieClip = this.createEmptyMovieClipC'star" + stars, stars);
star._rotation = Math.randomO * 360:
star._x = 275;
star._y = 200;
var dot:MovieClip = star.createEmptyMovieClip("dot". 0);
dot.speed = Math.ceil(Math.random()*10);
dot.lineStyled. OxFFFFEO. 100);
dot.moveTo(0. 2);
dot.lineTo(0. 5):
dot.onEnterFrame = mover;
Динамическая настройка скорости анимации 325

// Переменной FRAME_RATE присваивается целевая частота смены кадров.


var FRAME_RATE:Number = 24:
var FRAME_DUR:Number = (1 / FRAME_RATE) * 1000:
var time:Number = 0:
var lastTime:Number = 0;
var stars:Number = 0;
performanceMonitorO:
Запустив эту программу, вы заметите, как звездный поток нарастает от нуля до
нескольких сотен звезд (рис. 9.7). Проследите за значениями переменных глав-
ной временной диаграммы на вкладке Variables панели Debugger.

У -v .'-*.*« ->-
I #>/••••/

44>\<4WM№Bti*' * • *
JH*#* .''" 'I

1 f
, / ' '^ -

Jv*Sij«. ..,.,:;. .:.-'. ;..••;•;


$ version

FSAHE RATE
bstTime
3
• j ^ ^ -
ч чч ^ mover

/ / i, iUrFssS
stsrs isss
tin» 154

.Stack

Рис. 9.7. Звездный поток с динамическим изменением количества звезд

Количество звезд растет до тех пор, пока time не приблизится к FRAME_DUR. При
достижении этой точки программа начинает добавлять или удалять звезды для
сохранения равновесия. Если выполнить какую-либо операцию, нарушающую
это равновесие (например, запустить другую программу или изменить размеры
SWF), изменение быстродействия приведет к поиску новой точки равновесия.
Обратите внимание: частота смены кадров Flash иногда подвержена случайным
изменениям даже при достижении равновесного состояния, поэтому эффект будет
постоянно создавать и удалять клипы. Для таких случаев можно реализовать
буферизацию: например, удаление или добавление клипов будет производиться
только в том случае, если фактическое время вывода кадра отличается от целе-
вого более чем на 15 %.
326 Глава 9. Быстродействие и оптимизация

Итоги
Графические эффекты, хорошо работающие на компьютере разработчика, неред-
ко начинают «тормозить» на менее производительных компьютерах конечных
пользователей. Чтобы содержание Flash нормально воспроизводилось на как
можно более широком спектре компьютеров (включая гораздо менее мощные
мобильные устройства), постарайтесь обеспечить его масштабируемость, то есть
адаптацию к компьютеру пользователя. В этом трюке представлен довольно про-
стой подход: мы вычисляем скорость работы компьютера пользователя и вносим
соответствующие изменения в сложность графики. Измерение фактического
быстродействия во время выполнения обычно выполняется проще и дает более
надежные результаты, чем, например, попытки оценить быстродействие по типу
устройства или разрешению экрана.
Среди многочисленных изменений, обеспечивающих динамическую регулиров-
ку сложности анимации, можно выделить следующие:
• ограничение числа объектов на экране (звезды в звездном потоке, монстры
в игре, пользователи в чате с использованием аватаров);
• уменьшение количества используемых альфа-каналов;
• уменьшение альфа-эффектов (например, отключение прозрачности на мед-
ленных компьютерах);
• ограничение движений или их частоты (например» уменьшение числа кадров
в цикле ходьбы - см. трюк 28). Художники, работающие в области компьютер-
ной графики и не знакомые с требованиями к быстродействию, обычно соз-
дают слишком много промежуточных позиций. Вместо типичных 15-20 по-
зиций, создаваемых художником, часто хватает 3 или 5;
• уменьшение размеров экрана или его активной области. Чтобы экран выгля-
дел больше, добавьте статическую графику вокруг активной области - напри-
мер, бордюр для реализации эффекта «картины в раме» или статические дат-
чики, создающие эффект «приборной панели»;
• использование статических растров или видеоклипов с цветовыми эффекта-
ми (см. трюк 8).
Часто оказывается, что некоторые изменения оказывают сложное влияние на
быстродействие и обеспечивают выигрыш как на мощных, так и на слабых ком-
пьютерах. Например, в игре, имитирующей работу бармена, можно уменьшить
количество посетителей и частоту, с которой они обращаются с заказами. Это
приведет к сокращению количества выводимых объектов и используемых звуко-
вых каналов. С другой стороны, можно уменьшить размеры посетителей, чтобы
они занимали меньше места на экране. На мощных компьютерах это позволит
разместить в баре больше посетителей, а на слабых - ускорит вывод изображения.
Быстродействие компьютера конечного пользователя - не единственная причи-
на для динамического изменения содержания Flash. Иногда подобная методика
применяется для регулировки интерактивных упражнений в зависимости от ре-
зультатов пользователя. Например, если пользователь сделал что-то не так или
потратил слишком много времени на выполнение операции, можно вывести зву-
ковую или визуальную подсказку. В то же время, если пользователь постоянно
Смета быстродействия 327

ошибается на первом уровне видеоигры, стоит немного понизить уровень слож-


ности.
Существует множество других способов повлиять на субъективное быстродей-
ствие приложения. Например, при выполнении команд клавишами ускоренного
вызова (см. трюк 96) пользователю кажется, что приложение реагирует на его
действия быстрее, чем при работе с мышью. Или еще один пример: многократно
воспроизводимая анимация надоедает независимо от того, насколько качествен-
но она выглядит. Сократите продолжительность анимации при многократном
воспроизведении, уменьшите число повторений или разрешите пользователю
отключить/пропустить ее.

ТРЮК Смета быстродействия


№71 Из финансовой сметы вы узнаете, как расходуются ваши деньги. Созда-
ние сметы быстродействия позволит узнать, на что расходуются ресур-
сы, и перераспределить «статьи расходов».
Ранее была описана методика оценки времени загрузки (см. трюк 66), при помо-
щи которой можно «упаковать» максимум содержания в файл наименьшего раз-
мера. Быстродействие в дизайне Flash Player обладает более низким приорите-
том, чем оптимизация размера файла. А это означает, что Flash позволяет создавать
привлекательное содержание в небольшом количестве килобайт, возможности
же для повышения быстродействия весьма ограничены. В то же время, несмотря
на общую ограниченность ресурсов процессора, доступных Flash Player, вы мо-
жете управлять распределением времени между выполнением различных подза-
дач. Это распределение отражается в смете быстродействия.

Фокусная область
Смета быстродействия; как и все сметы, должна определять приоритеты. Иначе
говоря, не все аспекты презентации равноценны. Например, с точки зрения пользо-
вателя, перебои в воспроизведении звука более заметны, чем перебои в видео
или анимации. Некоторые дизайнеры также склонны уделять особое внимание
тем аспектам, на которые рядовой пользователь обычно не обращает внимания.
Пользователи внимательно рассматривают только те объекты, с которыми взаи-
модействуют в данный момент, то есть входящие в «фокусную область», поэто-
му таким объектам следует назначать высокий приоритет в смете быстродей-
ствия. Периферийные объекты пользователь либо не замечает, либо обращает
на них внимание только тогда, когда происходит что-то неожиданное (напри-
мер, если объект сдвигается). Следовательно, распределение сметы быстродей-
ствия и проектирование интерфейса, обеспечивающего потребности пользователя,
являются взаимодополняющими задачами.
Если фокусную область можно предвидеть (или эффективно управлять ею),
у пользователя создастся ощущение хорошего общего быстродействия даже в том
случае, если периферийные объекты остаются статичными или работают с мень-
шим быстродействием.
328 Глава 9. Быстродействие и оптимизация

Например, в видеоиграх (и графике реального времени) объекты, приближенные


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

Расстановка приоритетов
Как же выделить фокусной области приложения основную долю сметы быстро-
действия? Это можно сделать множеством разных способов. Проще всего назна-
чить фокусной области «обработчик изменений», а для обновления остальных
частей ролика использовать периодические события. Например, в реализации
классической видеоигры «пинг-понг» для управления ракеткой игрока может
использоваться обработчик события onMouseMove, а для управления ракеткой
противника и шариком - обработчик onEnterFrame. Если часть игры, с которой
непосредственно взаимодействует пользователь, хорошо реагирует на его дей-
ствия, то все приложение кажется более чувствительным.
Тем не менее, простое разделение приоритетов на две категории не обеспечивает
точного контроля над распределением ресурсов. Более правильное решение - ис-
пользовать несколько разных приоритетов. В следующем примере приоритеты
назначаются на основании степени взаимодействия пользователя с процессом:
• высокий приоритет - процессы, с которыми пользователь непосредственно
взаимодействует;
• нормальный приоритет - процессы, с которыми пользователь взаимодействует
косвенно;
• низкий приоритет - процессы, с которыми пользователь взаимодействует
редко (или не взаимодействует вообще).
В игровом контексте (именно игры составляют большинство Flash-приложений
с потребностью в высоком быстродействии) высокоприоритетный процесс пред-
ставляет корабль или игрока. Процессы с нормальными приоритетами представ-
ляют графические объекты противника; хотя пользователь ожидает, что враги
будут двигаться с нормальной скоростью, небольшие замедления останутся не-
замеченными, если высокоприоритетные объекты будут двигаться без торможе-
ния. Если корабль противника замедляет движение, пользователь решит, что
так и должно быть.
Низкоприоритетные процессы представляют такие объекты, как обновляющий-
ся индикатор текущего счета или прокрутку фона. Конечно, пользователь заме-
Смета быстродействия 329

тит, если эти объекты совсем перестанут работать, но пока все идет более или
менее нормально, он обычно не обращает на них внимания.
Проектировщикам игр иногда бывает трудно выделить низкоприоритетные про-
цессы, потому что разработчики склонны дорожить каждым пикселом и каждой
нотой. Возможно, вам будет проще избавиться от этих заблуждений, если вы
поймете, что снижение приоритета для одних объектов позволит выделить боль-
ше внимания (а соответственно, и ресурсов) другим, более важным объектам.
Также не стоит забывать, что даже самый симпатичный звуковой эффект надо-
едает после того, как пользователь услышит его в тысячный раз. Самое правильное
решение - предложить бета-тестерам прототип приложения и спросить, что им
понравилось, что показалось слишком медленным, что раздражало и т. д. По
определению, перед вами те самые люди, которых вы пытаетесь развлекать, про-
свещать, чьи потребности обеспечивать и т. д., так что прислушайтесь к их мнению.
Еще один полезный прием - создать у аудитории иллюзию того, будто прило-
жение делает нечто большее, чем в действительности. Например, на время выво-
да статической таблицы рекордов можно создать звездный поток с большим
количеством звезд, но сразу же после начала игры уменьшить сложность анима-
ции (см. трюк 70). Если количество звезд будет уменьшаться постепенно, а игра
будет становиться все более быстрой и сложной, пользователь даже не заметит
происходящего. Скорее всего, он будет думать о том, как попасть на следующий
уровень!

Реализация
После выбора приоритетов необходимо реализовать их на ActionScript. Поскольку
вы не можете просто указать Flash на важность некоторого события, приоритеты
приходится внедрять косвенно, на уровне приемов программирования и исполь-
зуемых событий.
Высокоприоритетные события могут использовать:
• интервальный таймер, установленный функцией setlnterval() на период, мень-
ший интервала смены кадров (см. трюк 27);
• обработчик события onMouseMove (см. трюк 26).
Частота высокоприоритетных событий превышает частоту смены кадров, поэто-
му их обработчики должны включать команду updateAfterEvent(), обеспечиваю-
щую перерисовку сцены между кадрами.
События с нормальным приоритетом могут использовать обработчик события
onEnterFrame, чтобы операции выполнялись с частотой смены кадров.
В реализации низкоприоритетных событий используются:
• интервальный таймер, установленный функцией setlntervalQ на период, боль-
ший интервала смены кадров;
• событие, время от времени инициируемое из обработчика событий с нор-
мальным приоритетом onEnterFrame.
33D Глава 9. Быстродействие и оптимизация

На рис. 9.8 изображен экран видеоигры. Давайте распределим приоритеты для


разных аспектов игры.

Рис. 9.8. Интерфейс видеоигры

В файле gameOLfla на сайте книги приводится основная логика типичного при-


ложения, спроектированного с учетом «сметы быстродействия»; чтобы увидеть
основной код, откройте сценарий кадра 2 клипа me.world.
Ревнителей чистоты ActionScript может раздражать то, что сценарий присоеди-
нен к клипу, однако анимация занимает в игровом дизайне не менее важное
место, чем сценарии, поэтому она часто смешивается с кодом. Игры, в которых
весь код сосредоточен в одном кадре, встречаются крайне редко. Например, если
присмотреться к кораблю игрока (символ me.ship в библиотеке), выясняется,
что взрыв реализуется не в виде сценария, а в виде кадрированной анимации.
Хотя анимацией взрывов можно управлять при помощи сценарных таймеров,
анимация временной диаграммы проще создается, требует минимального пла-
нирования и оказывается более понятной для дизайнеров, которым (возможно)
придется редактировать ее в будущем.
А теперь посмотрим, как в коде FLA-файла реализованы три группы прио-
ритетов.
Единственным высокоприоритетным процессом является спрайт корабля игро-
ка. Следующая команда создает интервальный таймер, который через каждые
30 мс вызывает функцию shipController() для перерисовки корабля:
shipControl = setlnterval(shipController, 30):
Обновление фона имеет нормальный приоритет (и происходит с частотой сме-
ны кадров 18 fps). Чтобы реализовать смещение фона в каждом кадре, обработ-
чиком onEnterFrame назначается функция terrainController():
terrain.onEnterFrame = terrai nControl 1 ег:
Смета быстродействия 331

Обновление счета является низкоприоритетной задачей и выполняется только


раз в секунду:
scoreKeeper = setlntervaKscoreController, 1000);
Чтобы проследить, как работает система, проще всего запустить игру (самый
приятный способ!). Обратите внимание на некоторые обстоятельства:
• звезды двигаются медленнее рельефа. Они обладают низким приоритетом
и обновляются каждую четверть секунды. Этот факт отчасти маскируется рас-
пределенным характером обновления - каждая звезда анимируется через
четверть секунды, но не все обновления происходят одновременно;
• радар обновляется с той же частотой, что и звезды. Игра спроектирована
таким образом, чтобы замедленное обновление казалось намеренным: на ста-
рых радарах с электронно-лучевыми трубками экран обновлялся медленно
перемещающимся сканирующим лучом. Один из стандартных фокусов - за-
полнение экрана объектами, которые с точки зрения пользователя должны
двигаться медленно (например, облака или далекие горы). Медленное обнов-
ление таких объектов смотрится естественно;
• корабль игрока движется гораздо быстрее (и плавнее) кораблей агрессоров.
Многие пользователи не замечают различий, потому что они сосредоточива-
ют все внимание на своем корабле. Но даже заметив различия, они будут
лишь радоваться тому, что их корабль обгоняет неповоротливых врагов;
• корабли агрессоров, лазеры и фон двигаются с одинаковой частотой;
• счет обновляется крайне редко (раз в секунду). Обновление счета является
самым низкоприоритетным процессом в игре, потому что пользователь все
равно смотрит на свой корабль. Слишком частое обновление текстовых по-
лей - одна из основных причин снижения быстродействия в Flash. Прори-
совка даже небольшого количества текста требует обработки изрядного объе-
ма вычислений с векторными данными, особенно если Flash приходится
перерисовывать этот текст в каждом кадре!
Наш пример показывает, что в Flash вполне можно создать игру с достаточно
большим размером сцены. Более того, при правильном выборе структуры при-
ложения увеличение окна браузера не снизит быстродействия.

Итоги
«Смета быстродействия» не ускорит работу Flash Player, но создаст субъективное
ощущение скорости, подобно тому как индикатор прогресса субъективно ускоряет
загрузку. Идентифицируйте элементы, которые должны обновляться как молено
чаще, и выделите им больше ресурсов. Также определите низкоприоритетные
процессы и снизьте частоту их обновления, чтобы оставить больше ресурсов
высокоприоритетным процессам. Если повысить быстродействие в фокусной
области пользователя, ему покажется, что игра быстрее реагирует на его дей-
ствия, и он не заметит областей с более низким быстродействием.
332 Глава 9. Быстродействие и оптимизация

Использование растровой графики


вместо векторной
Векторная графика быстро пересылается, но медленно воспроизводится
на экране. Использование растровых изображений вместо векторных по-
вышает скорость воспроизведения.
Векторные изображения строятся по математическим формулам, определяющим
форму и заливку фигур. Следовательно, для векторной графики характерны чет-
кость и хорошая масштабируемость при малом объеме пересылаемых данных.
Тем не менее, построение сглаженной векторной фигуры может потребовать боль-
ше вычислительных мощностей, чем простое воспроизведение растрового (пиксель-
ного) изображения. Растровое изображение представляет собой фиксированный
блок данных. Хотя эти данные обычно занимают больше места, чем аналогич-
ные векторные изображения, после загрузки они быстро выводятся на экран.
Кроме того, при построении SWF-файла объем принимаемых данных уменьша-
ется за счет сжатия (SWF-файлы автоматически используют z-lib - алгоритм
сжатия без потери данных, напоминающий алгоритм, используемый в графичес-
ком формате PNG).
Растровая графика обеспечивает хороший компромисс между быстродействием
и объемом пересылаемых данных в нескольких случаях:
• если векторное изображение состоит из большого количества точек, оно может
занимать больший объем, чем его растровый эквивалент. Векторные изображе-
ния обычно больше подходят для штриховой графики, а растровые - для
фотографий и текстур, которые плохо воспроизводятся в векторном формате;
• если при выводе не применяются масштабирование и сглаживание, растры
обычно быстрее выводятся;
• если приложение запускается с компакт-диска и скорость пересылки не очень
существенна, подумайте о переходе на растровую графику.
Для статических фонов с множеством векторных элементов использование рас-
трового изображения обычно повышает время воспроизведения. Сложные век-
торные конструкции, состоящие из большого количества сгруппированных объек-
тов, тоже могут выиграть от преобразования в растровую форму.

Пример 1: растровые изображения движутся быстрее


векторных
В этом примере (файл tileexample_vector.fla на сайте книги) несколько анимаци-
онных клипов движутся по экрану, имитируя эффект параллакса (то есть глуби-
на по оси z имитируется замедлением движения объектов и окрашиванием их
в более темный цвет при удалении от зрителя). Клипы, использованные в этом
примере, представляют собой псевдотрехмерные графические конструкции, соз-
данные исключительно средствами векторной графики (рис. 9.9).
В верхней части сцены выводится текущая частота смены кадров. По ней можно
определить, насколько быстро Flash воспроизводит данный эффект. Тестирова-
Использование растровой графики вместо векторной 333

ние векторной версии (чтобы получить наиболее типичные результаты, протес-


тируйте ее в браузере нажатием клавиши F12) показывает, что работа Flash Player
существенно замедляется. Несмотря на то что ролику была назначена частота
смены кадров 70 fps, на достаточно быстрых компьютерах он воспроизводится
с частотой 25-30 fps.

Рис. 9.9. Мозаичная анимация, построенная из векторных элементов

Проблема решается заменой каждого векторного изображения аналогичным изоб-


ражением, использующим растровую графику. Клипы новой версии приложе-
ния (файл tileexample_bitmap.fla на сайте книги) внешне не отличаются от своих
векторных аналогов, но:
• создаются в растровом формате вместо векторного;
• цветовой эффект «затемнения с расстоянием» был заранее применен к ним
в графическом редакторе. Таким образом Flash избавляется от необходимос-
ти применять его на стадии выполнения.
Обновленная версия работает быстрее оригинала. При тестировании в анало-
гичных условиях растровая версия работает на частоте 60-70 fps. Она не от-
личается от векторной по размерам файла. Более того, поскольку все элементы
представляют собой растровые блоки с прямыми краями, a Flash сглаживает
растровые изображения лишь в режиме с максимальным качеством (см. трюк
67), выбор режима с низким или средним качеством дополнительно ускорит
процесс. Также учтите, что изменения качества на движущихся объектах менее
заметны, так что его снижение даже может остаться незаметным для пользова-
теля!
334 Глава 9. Быстродействие и оптимизация

Пример 2: предотвращение сглаживания


Нередко самой затратной составляющей воспроизведения векторной графики
становится сглаживание. Преобразование векторов в заранее сглаженные рас-
тровые изображения способно существенно повысить быстродействие.
На рис. 9.10 изображен простой символ, формирующий фон, прокручиваемый текст
и несколько дополнительных копий того же символа (файл textexample_vector.fla на
сайте книги).

praesent iuptatum zzriJ delenit augue dms dolore t§ |n |


feugaSt null;* fadlisi.

/~_ м ^ &
/з у*, д %
С// С ^ >
/I У
Lorem ipsum dotor sit amet,:cons€ctetuer adipiscing
elit, sed diam попитту пШЬ euismod ti«ddunt ut
laoreet clolore magna atiquam erat votutpat.

Ut w'isi enim ad тШт veniam, qui$ nostrud exerci


tation иПатсофег susciprt lo-bortts nist ut afiquip ex
:
ea commodo consequat ;i

Dois autem vel eum iriure dotor in hendrerit in


vulputate vefit esse molestie consequat, vet iilum
doJone eu feugiat nulia fadtisis at vero eros et
accumsan et iysto odio dignisstm qui bfandit

РИС. 9.10. Символы и прокручиваемое текстовое поле

Перемещение текста кнопками прокрутки серьезно снижает быстродействие. Ис-


пользование растрового изображения в качестве фона уменьшает объем вычисле-
ний, которые приходится выполнять Flash. Простой вывод статического растра
происходит быстрее, чем построение его векторной версии при каждой прокрутке.
Если заменить векторный фон растровым (файл textexample_bitmap.fla), скорость
работы приложения увеличивается примерно на 30 %.

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

Механизм визуализации Flash ориентирован на работу с векторной графикой,


а растровая анимация считается уделом Macromedia Director, но на практике
бывает и иначе. Во многих ситуациях применение растровой графики обеспечи-
вает заметный рост быстродействия без серьезного увеличения размера файла.
Если создаваемый проект будет запускаться с компакт-диска и размер файла не
очень важен, используйте растровую графику (если только приложение не тре-
бует масштабирования контента).
Зе Фернандо

Оптимизация загрузки и использования


ТРЮК

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

Hi Check Box !^Q gj


# Radio Button
sone
•three
four
five

Рис. 9 . 1 1 . Стандартные компоненты пользовательского интерфейса

Компоненты образуют особую категорию клипов, которые используются в каче-


стве «строительных блоков» или предоставляют классы ActionScript, упрощаю-
щие реализацию расширенных интерактивных средств или взаимодействие между
Flash и другими веб-технологиями.
В процессе компиляции FLA в SWF Flash анализирует временную диаграмму
и составляет список всех ресурсов в порядке их появления. Найденные ресурсы
включаются в SWF в указанном порядке, что обеспечивает эффективную пото-
ковую пересылку данных. Если ресурс не находится на временной диаграмме,
он не включается в список, а следовательно, не экспортируется. Тем самым обес-
печивается минимальный размер SWF-файла.
Этот прием оптимизации работает неплохо. Но если ресурс или компонент ис-
пользуется в сценарии ActionScript, а не на временной диаграмме, возникают
проблемы. Вы можете заставить Flash включать в SWF даже те ресурсы, кото-
рые не присутствуют на временной диаграмме, для этого в диалоговом окне
Linkage Properties устанавливается флажок Export for ActionScript. Для компонен-
тов этот флажок установлен по умолчанию, поэтому компоненты включаются
336 Глава 9. Быстродействие и оптимизация

в SWF даже в том случае, если они не используются на временной диаграмме.


Если разместить компоненты на сцене (что приводит к их включению в библио-
теку), а затем удалить их со сцены, компоненты останутся в библиотеке. Данный
способ идеально подходит для включения необходимых компонентов в библио-
теку. Тем не менее, не забывайте удалять неиспользуемые компоненты из биб-
лиотеки или сбрасывать флажки Export for ActionScript, иначе они будут включе-
ны в SWF даже в том случае, если эти компоненты не используются на временной
диаграмме или ActionScript.
Компоненты Flash MX 2004 (также называемые компонентами z>2) были серьез-
но усовершенствованы по сравнению с исходными компонентами Flash MX vl,
но для их работы необходима загрузка 25-30 Кбайт дополнительного кода, вы-
полняемая по умолчанию с первым кадром SWF. Для пользователей с медлен-
ными подключениями даже эта задержка может стать существенной.
Избежать задержки с загрузкой нельзя, но можно выбрать момент, в который
она произойдет. В окне File • Publish Settings • Flash выберите в списке ActionScript
Version строку ActionScript 2.0 (компоненты v2 написаны на ActionScript 2.0).
Щелкните на кнопке Settings рядом с раскрывающимся списком ActionScript Version
(кнопка становится доступной после выбора ActionScript 2.0). В открывшемся
диалоговом окне ActionScript Settings найдите текстовое поле Export Frame for
Classes и введите в нем значение 2.
В результате Flash экспортирует классы компонентов после кадра 1, а не до него,
и это позволит вывести в браузере хоть какое-то изображение на время загрузки
классов. Такая возможность будет полезной при создании сайтов с компонента-
ми Flash MX 2004, работающих на медленных подключениях.
Хотя компоненты Flash MX 2004 требуют предварительной загрузки 30 Кбайт
перед началом своей работы, использование нескольких компонентов не приво-
дит к пропорциональному возрастанию этой цифры. Иначе говоря, архитектура
компонентов v2 оптимизирована для использования пяти и более компонентов.
Компоненты также поддерживают оформление с использованием скинов, что
позволяет придать им нестандартный вид, обладают расширенными средствами
управления передачей фокуса и специальными возможностями для пользовате-
лей с дефектами зрения.
Но если в приложении используется только один компонент (и новые возмож-
ности компонентов v2 вам не нужны), вероятно, лучше обойтись без компонен-
тов v2. На сайте Flash Exchange (http://www.macromedia.com/exchange/flash), в раз-
деле «Flash MX Components for Flash MX 2004» категории User Interface, имеются
версии компонентов vl, совместимые с Flash Player 7.

ПРИМЕЧАНИЕ
Если выбрать в списке File • Publish Settings • Flash • Version формат экспорти-
рования Flash Player 7, некоторые исходные компоненты Flash MX v1 не работа-
ют в Flash MX 2004.

Некоторые компоненты vl, поставляемые с Flash MX, были написаны без учета
регистра символов, поэтому при попытке экспортировать их в формат Flash
Player 7 из Flash MX 2004 компилятор выдает ошибку (независимо от того, для
Оптимизация загрузки и использования компонентов 337

какой версии ActionScript они компилируются -1.0 или 2.0). Обновленные версии
правильно учитывают регистр символов, поэтому они будут работать в Flash
MX 2004 для любой комбинации форматов ActionScript 1.0/2.0 и Flash Player 6/7.
В Flash Exchange представлено несколько разных наборов компонентов. Также
обратите внимание на пакет Macromedia Pocket PC CDK (Content Development
Kit), доступный по адресу http://www.macromedia.com/devnet/clevices. Одну из
частей этого пакета составляют компоненты Pocket PC, оптимизированные для
малого размера файла и работающие в Flash Player для настольных систем (они
работают в Flash Player 6 и похоже, успешно работают в Flash Player 7 при
экспортировании в формат ActionScript 2.0).
Если в приложении используется минимальное подмножество функций компо-
нента, подумайте о создании собственных версий компонентов. Многие сайты
обходятся простейшими кнопками и полосами прокрутки, которые легко создать
в виде пары 1-килобайтных клипов. По адресам http://www.flashcomponents.com
и http://www.flashcomponents.net представлены альтернативные компоненты, соз-
данные сообществом Flash-разработчиков. Некоторые из них оптимизировались
для минимального размера файла.

Итоги
Компоненты v2 поставляются вместе с Flash MX 2004, но, конечно, это не един-
ственные компоненты, которые вы можете использовать в своих программах.
Компоненты v2 ориентированы на веб-приложения в условиях высокой пропуск-
ной способности канала. В других ситуациях можно использовать компоненты
Flash MX vl и даже другие компоненты от Macromedia или независимых фирм
(например, компоненты Pocket PC).
ГЛЙВД IB

ActionScript

Трюки № 74-85
ActionScript определяет истинную мощь Flash. Без ActionScript возможности Flash
ограничивались бы созданием тривиальной линейной анимации. С добавлением
минимального кода ActionScript реализуются базовые средства управления (кноп-
ки и активные зоны). Освоение нетривиальных возможностей ActionScript от-
крывает доступ к таким возможностям, как создание локальных общих объектов
(в просторечии - Flash-cookie). Без применения ActionScript не удастся создать
Flash-сайт, который бы взаимодействовал с браузером, обменивался данными с
серверными приложениями или загружал МРЗ-файлы.
Многие новые средства Flash MX 2004 или Flash MX Professional 2004 реализо-
ваны в предположении, что разработчик владеет ActionScript. Даже те из них,
которые не требуют опыта программирования (например, Behaviors и Timeline
Effects), при определенном уровне владения ActionScript реализуются более гиб-
ко и лучше структурируются.
Освоить анимацию на временной диаграмме несложно, но на то, что на ActionScript
легко делается за считанные минуты или часы, при «ручной» реализации уходят
дни и даже месяцы. А если дизайнер хочет, чтобы его приложение обладало
улучшенной интерактивностью, содержало логику принятия решений или обме-
нивалось данными с другими приложениями, ему не обойтись без изучения
ActionScript. RIA-программирование, онлайновые игры, улучшенные графические
интерфейсы - все это работает на базе сценариев.
Хотя настоящая глава полностью посвящена ActionScript, сценарии в том или
ином виде присутствуют практически в любом трюке книги. Так, в разделе «По-
вышение быстродействия кода» главы 9 рассматриваются проблемы оптимиза-
ции ActionScript. Кроме того, в книге представлены и другие трюки, относящие-
ся к быстродействию, - например, оптимизация байт-кода (см. трюк 100). Таким
образом, один из путей изучения ActionScript - практические эксперименты с трю-
ками и внесение в них всевозможных изменений. Кроме того, в предисловии
обсуждается проблема преобразования ActionScript 2.0, широко использующего-
ся в книге, в ActionScript 1.0.
Action Script 339

Изменения в Flash MX 2004


Выход Flash MX 2004 принес большие изменения в жизнь пользователей Action
Script. В область синтаксиса и структуры кода были внесены серьезные усовер-
шенствования, упрощающие программирование больших приложений ActionScript,
форматирование текста, а также расширенное управление потоковыми данными.
Архитектура компонентов Flash была переработана таким образом, чтобы в ней
использовались классы и новые возможности ActionScript 2.0, включая жесткую
типизацию.
Новые средства Flash MX Professional Slides и Forms позволяют вести разработку
в парадигме визуального программирования стиля PowerPoint или Visual Basic
с написанием минимального объема кода.
Даже интерфейс среды разработки Flash MX 2004 может настраиваться при по-
мощи программного интерфейса Flash JavaScript API (JSAPI). В разделе «JSAPI
Documentation» документации Flash MX 2004 (http://www.macromedia.com/support/
documentation/en/flash) приведены ссылки на документы, в которых объясняется,
как создавать команды и инструменты для использования в среде разработки
Flash.
Более того, язык JSFL (Flash JavaScript) позволяет программировать операции
в среде разработки. Полное описание JSFL выходит за рамки книги; далее приво-
дится короткий пример компиляции в режиме командной строки для Windows.
Этот сценарий JSFL, написанный Колином Муком, создает файл .swf для каждо-
го файла .fla в этом проекте:
// Код exportPetSupplies.jsfl:
// Открыть файл .fla
var doc = f1.openDocument("fi1e:///с|/data/projects/pet/petsuppiies.fia"):
// Экспортировать .swf
doc.exportSWF("file'7//c|/data/projects/pet/petsupplies.swf". true):
// Выход из среды разработки Flash MX 2004 (необязательно).
fl.quit(false):

// Команда, выполняемая в командной строке из каталога /pet/:


"c:\program files\macromedia\flash mx 2004\flash.exe" exportPetSupplies.jsfl
Команда должна выполняться при закрытой среде Flash MX 2004. После выпол-
нения команды в каталоге c:\data\projects\pet появляется откомпилированный
ролик petsupplies.swf:
И Flash MX 2004, и Flash MX Professional 2004 поддерживают ActionScript 2.0, но
при этом также поддерживается синтаксис ActionScript 1.0 (версия компилятора
ActionScript выбирается в списке File • Publish Settings • Flash • ActionScript Version).
Таким образом, разработчики могут сохранять верность ActionScript 1.0 или пе-
рейти на ActionScript 2.0, в большей степени приспособленный к объектно-ори-
ентированным разработкам, по своему усмотрению.
340 Глава 10. ActionScript

Новшества ActionScript в Flash Player 7


Многочисленные расширения ActionScript в Flash Player 7 доступны для пользо-
вателей как ActionScript 1.0, так и ActionScript 2.O. Подробный список изменений
приведен в электронной документации Flash (Help • ActionScript Reference Guide •
What's New in Flash MX 2004 ActionScript). Вот лишь некоторые из них:
• обработка сообщений об ошибках в реальном времени с использованием клас-
са Error, а также обработка ошибок конструкциями try/catch/finally и throw;
• настройка контекстных меню Flash Player с использованием класса ContextMenu
и нового свойства menu (классы Button, MovieClip и TextField);
• поддержка события Mouse.onMouseWheel, обнаруживающего изменения в по-
ложении колеса мыши (только для системы Windows) и недокументирован-
ные средства обнаружения нажатия колеса мыши (см. трюк 62);
• класс MovieClipLoader для создания предварительных загрузчиков (например, для
вывода информации о ходе выполнения операции во время загрузки SWF-фай-
ла);
• класс TextField.StyleSheet с поддержкой CSS;
• поддержка формата SOAP, позволяющая Flash Player 7 работать с веб-служба-
ми на базе SOAP без установки на сервере Flash Remoting (готовые компонен-
ты, обеспечивающие обмен данными в формате SOAP, входят только в ком-
плект поставки Flash MX Professional 2004);
• некоторые методы класса MovieClip, прежде всего методы управления глуби-
ной getNextHighestDepthQ и getlnstanceAtDepth();
• класс PrintJob, заметно упрощающий печать в Flash и предоставляющий боль-
ше возможностей контроля над печатным выводом, чем функции печати
ActionScript 1.0.
Большинство SWF-файлов в формате Flash Player 6 воспроизводится в Flash
Player 7 без изменений. Тем не менее, в Flash Player 7 также появилась более
жесткая политика междоменной безопасности (см. главу 12), которая может поме-
шать просмотру некоторого содержания формата Flash Player 6 в Flash Player 7.
Свойство System.exactSettings и метод System.allowlnsecureDomain() позволяют
вернуть некоторые параметры доменной безопасности к менее жесткому уровню
Flash 6, благодаря чему больше SWF-файлов формата Flash Player 6 будет рабо-
тать в Flash Player 7.
Хотя многие возможности Flash Player 7 также поддерживаются Flash Player 6.0.65
(часто встречается термин Flash Player 6r65), множество других возможностей
в этой версии отсутствует. Для обеспечения максимальной совместимости (до
тех пор, пока Flash Player 7 не появится на большинстве компьютеров) эк-
спортируйте файлы Flash MX 2004 в формат Flash Player 6 (выполните команду
File • Publish Settings • Flash и выберите в списке Version строку Flash Player 6, а за-
тем установите флажок Optimize for Flash Player 6r65) - конечно, если в програм-
ме не используются специфические возможности Flash Player 7.
ActionScript ?_U

Регистр символов и жесткая типизация


ActionScript 2.0 позволяет задавать тип данных всех свойств, переменных, парамет-
ров и возвращаемых значений функций. Информация о типе данных используется
компилятором для проверки типов. Иначе говоря, компилятор проверяет правиль-
ность типа только для тех данных, для которых он был указан. Кроме того, Action-
Script 2.0 также учитывает регистр символов (см. http://swfoo.com/archives/000034.html)
в соответствии с предложенным стандартом ЕСМА-262 Edition 4 (ЕСМА 4). Эта
тема подробно рассматривается по адресам http://livedocs.macromedia.com/flash/
mx2004/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context= =Flash_MX_2004
_Documentation&file=01_what.htm).
Многие дизайнеры, не сведущие в программировании, полагают, что без жест-
кой типизации и учета регистра в ActionScript 2.0 вполне можно обойтись, на са-
мом деле использовать эти возможности несложно, а они помогут предотвра-
тить ошибки. Например, в ActionScript 1.0 переменной можно присвоить данные
любого типа:
answer = "Einstein";
Но где-то дальше на временной диаграмме будет ошибочно записана следующая
команда:
answer = 6:
Числовое значение присваивается переменной, в которой, как предполагается,
должен храниться текст - скорее всего, произошла ошибка. ActionScript 1.0 не
обнаруживал подобные потенциальные ошибки и не мог предупредить о них про-
граммиста. Но при использовании жесткой типизации ActionScript 2.0 первая
команда принимает следующий вид:
var answer:String =."Einstein":
После двоеточия указывается тип данных String. Это означает, что переменная
answer должна содержать строку и не может принимать значения, относящиеся к
другим типам данных. При определении типа данных перед именем переменной
ставится ключевое слово var.
Допустим, позднее на временной диаграмме встречается команда
answer = 6;
При попытке откомпилировать FLA Flash выдает на панели Output сообщение об
ошибке. Жесткая типизация помогает выявлять ошибки и создавать более на-
дежный код.
Тип данных проверяется на стадии компиляции и только в среде разработки. Action-
Script поддерживает типизацию данных только в том случае, если в списке File • Publish
Settings • Flash • ActionScript Version была выбрана строка ActionScript 2.0. Но даже
при использовании компилятора ActionScript 2.0 Flash не проверяет типы пере-
менных, для которых не использовался синтаксис имя:тип. Это позволяет обнов-
лять старые сценарии ActionScript 1.0 до ActionScript 2.0 без указания типов
данных для всех переменных.
342 Глава 10. ActionScript

LiveDocs

Уследить за всеми новшествами Flash и ActionScript нелегко, поскольку из-за об-


наружения новых ошибок и выхода обновлений документация иногда оказывает-
ся устаревшей (хотя при наличии подключения к Интернету Flash MX 2004 пе-
риодически спрашивает, не хотите ли вы загрузить обновленную документацию).
Проект LiveDocs для Flash MX 2004 (http://livedocs.macromedia.com/flash.mx2004/
index.html), находящийся на ранней стадии своего существования, предоставляет
пользователям доступ к полной документации Flash. На страницах LiveDocs ото-
бражаются комментарии других пользователей и имеется специальная кнопка,
которая позволяет ввести ваши собственные комментарии по поводу содержимо-
го страницы и его полезности.
Особый интерес представляет словарь ActionScript - если у вас возникли про-
блемы с работой какого-либо фрагмента кода и найти ответ в документации Flash
не удалось, попробуйте поискать в словаре.

ТРЮК Внешние редакторы сценариев


№74 Flash MX Professional 2004 содержит редактор, позволяющий редактиро-
вать внешние файлы, но в стандартном издании Flash MX 2004 такая воз-
можность отсутствует. Использование внешнего редактора при написа-
нии кода ActionScript, JavaScript, XML или CSS сделает вашу работу более
производительной.
Включение внешнего кода ActionScript (файлов с расширением .as) поддержива-
ется со времен Flash 5. Как в Flash 5, так и в Flash MX внешние файлы ActionScript
включаются директивой #include. В Flash MX 2004 и ActionScript 2.0 директива
#include тоже поддерживается, но обычно можно обойтись и без нее.
Далее приводится краткая сводка по использованию внешних файлов ActionScript.
В ActionScript 2.0 определение класса (с ключевым словом class) должно нахо-
диться во внешнем текстовом файле. Внешний файл должен иметь расширение
.as, а его имя должно совпадать с именем класса (с учетом регистра!). При этом в
файле может находиться определение только одного класса. Например, опреде-
ление класса Box должно храниться в файле Box.as.
В ActionScript 1.0 формальный синтаксис class не поддерживается, а для опреде-
ления классов используется конструкция function:
function BoxO {
}
Определения классов ActionScript 1.0 могут ассоциироваться с кадрами и даже
кнопками или анимационными клипами, но чаще они все же хранятся во внешних
файлах .as и подгружаются в SWF директивой #include. В ActionScript 2.0 код
классов из внешних файлов .as подгружается в SWF при первом использовании
класса.
Внешние редакторы сценариев 343

Следующая команда ActionScript 2.0, конструирующая экземпляр класса Box


оператором new, заставляет компилятор автоматически подгружать в SWF код из
файла Box.as:
var someVarBox = new BoxO;
Таким образом, в ActionScript 1.0 допускается размещение определений классов
во внешних файлах .as, а в ActionScript 2.0 вы обязаны это делать.
Компилятор ActionScript 2.0 ищет внешние файлы классов в списке каталогов
классов или в пакете, заданном командой import. Добавление каталогов в список
производится в диалоговом окне Edit • Preferences • ActionScript • Language •
ActionScript 2.0 Settings (кнопка со значком + в секции Classpath включает новый
каталог в список).
Классы, расширяющие класс MovieClip, могут ассоциироваться с клипами симво-
лов, для этого нужно задать необходимые свойства в группе Linkage окна, откры-
ваемого командой Linkage раскрывающегося меню панели Library- Чтобы экспор-
тировать субкласс клипа, установите флажок Export for ActionScript в диалоговом
окне Linkage Properties и укажите имя класса (без расширения .as) в поле AS 2.0
Class того же диалогового окна.
Тем, кто работает в Flash MX 2004, для создания файлов .as понадобится внеш-
ний текстовый редактор. Более того, даже в среде Flash MX Professional 2004,
содержащей встроенный редактор файлов, может потребоваться более мощный
инструмент.
SciTE|Flash - популярный специализированный текстовый редактор для про-
граммистов ActionScript, который также может использоваться для редактирова-
ния текста, XML, JavaScript, CSS и других файлов, часто задействованных в ра-
боте профессионального Flash-разработчика. Он также может использоваться для
написания серверных сценариев на таких языках, как Perl и РНР.
SciTE (http://www.scintilla.org/SciTE.html) - текстовый редактор с открытым ис-
ходным кодом, выбор многих квалифицированных программистов (существует
на платформах Windows и Linux). SciTEJFlash (http://www.bomberstudios.com/
sciteflash) представляет собой редактор ActionScript на базе SciTe, написанный
Эйлом Муньосом (Ale Munoz) из Bomberstudios при содействии Робина Дебрей-
ля (Robin Debreuil). SciTE|Flash работает только на платформе Windows. Другие
альтернативные редакторы для Windows и Мае перечислены в разделе «Итоги».
На момент написания книги была запланирована, но еще не вышла версия
SciTEJFlash для Flash MX 2004 (то есть версия с поддержкой классов ActionScript
2.0). Читатели, желающие внести свой вклад в эту работу, могут посетить сайт
http://www.bomberstudios.com/sciteflash/status.php. Набор конфигурационных фай-
лов, обеспечивающих цветовую разметку SciTE|Flash, находится на сайте mizubitchy
(http://mizubitchy.antville.org/stories/519068).
Окно приложения SciTE|Flash состоит из двух основных панелей: панели редак-
тирования (слева) и панели вывода (справа), как показано на рис. 10.1. Переход
между панелями осуществляется клавишами Ctrl+F6.
344 Глава 10. ActionScript

:. Tacfa

ф navigate • •• function I
Щ. posTransitian •• -• function 0
«? Щ fatfeTexs *• function jfacigVaiuei i
® colTransition •• function ii i ;
~€ Щ, populateTltes ••• function
populateEvents •-•• function ip»g*lnd»x) i
if ipage!p3gsind*nl.pUnk{0i t» -IS (
tricoloi".unpO_mc*unRe!*ase « navigate,
tricolor.stnpO mc.sm№arfC.!jrr><;r •-1 true;
>
if ipag«lp»g«lnd«>a.pUnm.}!»-IS {
tricoiur.stripl г
true:
If lpae*{p»gelnd«»3.pUnkU! f- - 1 ! С
4
tricoto!".strip2_nx.:i'Si B.V!viO;":;f;i' •••• true:

.mpopulatgEvents •••• funttton О j


builclcon ••••• function Cpaqelndex? {
onTransition •• function 0 {
erit * function ii {

Рис. 1 0 . 1 . Редактор SciTEj Flash

Процесс редактирования текста в SciTE|Flash достаточно очевиден, поэтому этот


редактор прост и удобен в работе. Стоит особо выделить следующие полезные
особенности:
• свертку программных блоков. Каждый блок помечен на левом поле охватыва-
ющей скобкой, в центре которой находится кружок со знаком + или ? (рис. 10.2).
Щелкая на кружках, молено сворачивать и разворачивать отдельные блоки;
это очень удобно при работе с длинным модульным кодом - таким, как хра-
нящиеся в файлах .as определения классов;
• форматирование в синтаксисах других языков, кроме ActionScript. В частно-
сти, поддерживаются форматы CSS, HTML, JavaScript, XML и формат про-
стого текста. Это позволяет создавать и редактировать все файлы с кодом,
данными и параметрами конфигурации, задействованные в типичном проекте
Flash. Синтаксис выбирается в меню Syntax (рис. 10.3).
• поддержку закладок для быстрого переключения между разными участками
листинга (Ctrl+F2 - установка/сброс закладки для текущей страницы, F2 -
переход к следующей закладке, Shift+F2 - переход к последней закладке);
• меню Edit позволяет закомментировать и снять комментарий с нескольких
строк программы одной операцией. Также в меню Edit присутствует удобная
команда поиска парной скобки для быстрого исправления ошибок с одной
лишней или недостающей скобкой;
• автоматическое заполнение (вообще говоря, эта возможность поддерживается
панелью Flash Actions, но во внешнем редакторе она тоже не будет лишней);
• если в момент закрытия приложения некоторые файлы оставались открыты-
ми, SciTE|Flash автоматически откроет эти файлы при следующем запуске
приложения (чтобы оценить эту возможность, нужно поработать с програм-
мой хотя бы неделю!);
• переключение регистра (верхний, нижний, смешанный и т. д.).
Внешние редакторы сценариев 345

popua
l tsErents
::
function {{>agelnd№(}'{
ипрсраЫ advents •• function У (

137 Ш вой;саг) •• ftmotion SpagslndexH

17-3 ffi iconTrans lion •* function С J 5

198 ® placeCon:ersl •••• function S)|


2!£ @ stripEvent «••function i}i
Ш stripCols - ( u n c t i o n ^ f
23« ШШ strip-Pa^e ^function { H

243 nsvigatlonS3:!a ~ funcSon•{) f


24:S

botom
top »*o

populateTiles -•- (wtctiof)


uiale£vents«funcfion <pa$eimiexK
•var разеЫех;
if {jH^elpsstiffifexf^tUid^Oj •' - -1!-.(
••'••; tricolor ,strjpG_mc.0(sRete8*e ••• navigate;
< •• n true;

:; tncotor,sfrip1_rac.BnRetesse - navigate;

>}
!
0 >tf (page|pagein:dexj.pLinStf2] fa -tj f
>; • ttiootor,sSrip2_mc~3ftR*le33e « navijate;
•• tric^ar.sirip2_mc;s-S!!Hs<;s-S!".:.:.' ss- •• troe:

ф unpapuiiateEvents- •- f u t K t i o n - ^ {
127 Щ buftiteon •
••
•• function i page index;

Рис. 10.2. Свертка программных блоков в SciTE| Flash

CSS
HTML
JavaScript
Peri
PHP
Properties
Python
Text
SML

Рис. 10.3. SciTE| Flash поддерживает синтаксис разных


языков и файловых форматов

Используя SciTE|Flash для написания кода ActionScript 1.0 (а также кода Action-
Script 2.0 при использовании обновленных конфигурационных файлов с mizubitchy),
сохраняйте свои классы ActionScript во внешних файлах с расширением .as.
Чтобы протестировать сценарий, откройте новый документ FLA и свяжите с кад-
ром 1 сценарий с директивой включения внешнего файла:
#include "test.as"
346 Глава 10. ActionScript

Если в директиве указан относительный путь, компилятор Flash сам находит


внешний файл .as (при условии, что он находится в одном каталоге с файлом
.fla). Также можно указать абсолютный путь:
#include "c:\Documents and Settings\Sham B\Desktop\test.as"
Если вы пишете код для временной диаграммы, возможно, нужный код будет
проще перенести операцией копирования/вставки, но применение директивы
#include гарантирует, что при каждой перекомпиляции из внешнего файла .as
будет извлечена новейшая версия определения класса.
Более того, директива #include позволяет тестировать и отлаживать сценарии из
SciTE|Flash!
Чтобы перейти в Flash и просмотреть SWF в тестовом режиме, выполните ко-
манду Tools • Test Movie в меню SciTE|Flash.
Чтобы перенести результаты с панели Flash Output на панель вывода SciTE|Flash,
выполните команду Tools • Capture Output в меню SciTE|Flash. Flash входит в ре-
жим Test Movie, но не получает фокус и не разворачивается.
Чтобы протестировать SWF одновременно с перенесением результатов, выполните
команду Tools • Test and Capture в меню SciTE|Flash. Окно SciTEjFlash остается на
переднем плане, а среда разработки Flash входит в тестовый режим и разворачи-
вается. Это мой излюбленный режим работы при написании длинных сценариев.
SciTEjFlash также поддерживает интерфейс командной строки. Правая панель
SciTE|Flash используется не только для вывода, но и для текстового ввода команд-
ной строки. Щелкните на правой панели, чтобы войти в режим командной стро-
ки, или нажмите клавиши Ctrl+F6, чтобы переключиться между режимом редак-
тирования кода (левая панель) и командной строкой (правая панель). Комбинация
клавиш Shift+F5 удаляет текст, находящийся на панели вывода.
Например, чтобы протестировать SWF с сохранением выходных данных, введите
в командной строке следующую команду:
flush.exe-w

Итоги
Если вам потребуется быстрый и компактный внешний редактор для написания
серьезных приложений, непременно опробуйте SciTE]Flash. Он покажется осле-
пительно быстрым всем, кто испытывает приступы клаустрофобии при работе
с длинными сценариями на панели Flash Actions (механизм свертки SciTE|Flash
помогает ориентироваться в больших сценариях). Однако SciTE|Flash гораздо
компактнее внешнего редактора Dreamweaver, который явно избыточен для на-
писания небольших фрагментов XML-кода.
Конечно, существуют и другие внешние редакторы, кроме SciTE|Flash. К их числу
принадлежат SE|PY (http://www.sephiroth.it/python/sepy.php) - бесплатный редак-
тор с открытыми исходными кодами, работающий на платформах Мае и Windows,
и PrimalScript (http://www.sapien.com/primalscript.htm) с минимальной ценой $179
(предоставляется 30-дневная бесплатная пробная версия без ограничения функ-
циональности). Оба редактора обеспечивают автоматическое завершение кода
ActionScript 2.09 и просмотр классов ActionScript 2.O.
О пользе жесткой типизации 347

ТРЮК О пользе жесткой типизации


№75 В ActionScript 2.0 был включен механизм жесткой типизации для провер-
ки ошибок, связанных с несоответствием типа переменной и ее значе-
ния. Жесткая типизация помогает разработчику проводить меньше вре-
мени за отладкой и больше — за созидательной работой.
В ActionScript 2.0 появился механизм жесткой типизации для выявления несоот-
ветствий в типах данных на стадии компиляции. Нужно ли использовать жест-
кую типизацию, если вы занимаетесь сценариями для компьютерных анимаций
и не считаете себя асом от программирования, создающим объектно-ориентиро-
ванные программы с применением классов? Мой ответ - решительное «да». Важ-
нейшими аспектами компьютерных анимаций являются скорость и чувствитель-
ность к действиям пользователя, поэтому все разработчики хотят как можно
меньше времени проводить за отладкой и как можно больше - за созиданием.
Жесткая типизация уменьшает количество проверок на стадии выполнения, что
способствует повышению быстродействия, а проверка на стадии компиляции
выявляет потенциальные ошибки, которые привели бы к незаметному наруше-
нию работы программы в Flash MX.
Таким образом, проверка типов ActionScript 2.0 повышает общую надежность
кода, даже если программа довольно короткая и не использует объектно-ориен-
тированные методы. Дополнительная проверка типов повышает вероятность того,
что код будет правильно работать после успешной компиляции, и не ухудшает ее
быстродействия (см. трюк 100).

Использование жесткой типизации


Давайте на примере фрагмента кода ActionScript 2.0 посмотрим, как жесткая ти-
пизация работает при написании сценариев для компьютерной графики.
function makeDot(cliprMovieClip):Void {
// Создание точки в clip
clip.lineStyledO. 0x0. 100);
clip.moveTo(0. 0):
clip.lineTod. 0):
}
function mover():Void {
// Перемещение точки
this.sX = checkLimitsCthis.sX. this._x. 0. 550);
this.sY = checkLimitsUhis.sY. this._y. 0. 400);
this._x += this.sX;
this._y += this.sY; -
}
function checkLimits(speed:Number, limit:Number.
low:Number, high:Number):Number {
// Смена направления при соприкосновении с краем экрана
if (limit < low) || (limit > high)) {
return -speed:
} else {
return speed:
348 Глава 10. ActionScript

var ball:MovieClip:
for (var i:Number = 0: i < 100: i++) {
ball = this.createEmptyMovieClipC'dot" + i . i ) :
ball._x = Math.randomO * Stage.width:
ball._y = Math.randomO * Stage.height:
ball.onEnterFrame = mover:
ball .sX = Math.randomO * 8 + 2:
ball.sY = Math.randomO * 8 + 2:
makeDot(ball);
}
Обратите внимание: объявление var balkMovieClip означает, что переменная ball
является экземпляром класса MovieClip (то есть что ball принадлежит к типу
MovieClipfc, поскольку объявление класса, фактически, определяет пользователь-
ский тип данных с тем же именем). Объявление ball с типом MovieClip сообща-
ет компилятору, что переменная должна содержать ссылку на клип. Позднее
переменная ball будет использоваться для хранения ссылок на клипы, создан-
ные во время выполнения программы функцией createEmptyMovieClip(): dotO,
dot1 и т. д.
Тип данных следует после двоеточия, и при каждом указании типа переменной
ее имени должно предшествовать ключевое слово var.
При попытке присвоить переменной значение, не являющееся ссылкой на клип:
ball - 0;
ball = "dot+i";
компилятор Flash выводит на панели Output сообщение о несоответствии типов.
На стадии разработки такие ошибки исправляются быстро и легко, тогда как без
проверки типов вы будете смотреть на пустую сцену во время выполнения и га-
дать, в чем же дело.
Также обратите внимание на то, что в приведенном примере функции и обработ-
чики событий тоже типизированы. Функция, которая не возвращает никакого
значения, объявляется с типом возвращаемого значения Void:
function myName():Void {
// Тело функции
}:
Если функция вернет какое-нибудь значение (чего она делать не должна), Flash
выведет сообщение об ошибке во время компиляции.
Функция, которая вызывается с аргументами и возвращает значение, записыва-
ется следующим образом:
function myName(argument:тип):возвращаемый_тип {
II Тело функции
return someValue:
}:
Если попытаться передать аргумент неправильного типа или если функция возвра-
щает неправильный тип (то есть someValue не относится к возвращаемому__ти-
ny), Flash снова выводит сообщение об ошибке компиляции.
О пользе жесткой типизации 349

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


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

Ограничения
Не стоит полагать, что жесткая типизация быстро и легко применяется во всех
случаях. Давайте рассмотрим некоторые ограничения проверки типов на стадии
компиляции.
Тип динамических свойств не проверяется. Так, в предыдущем примере свой-
ства ball.sX и ball.sY объявляются без указания типа данных. При динамическом
связывании пользовательских свойств с клипами на стадии выполнения ключе-
вое слово var использоваться не может. Запрет на использование var также озна-
чает, что вы не сможете задать тип данных таких свойств. Более того, поскольку
в нетипизированных переменных могут храниться данные произвольного типа,
компилятор Flash не выдаст сообщение об ошибке для следующей команды (не-
смотря на то, что свойство ball.sX создавалось для хранения числовой, а не стро-
ковой информации):
ball.sX = "cat";
Хотя в дальнейшем мы обращаемся к свойству ball.sX в виде this.sX внутри функ-
ции moverQ и передаем его функции checkl_imits() в параметре с именем speed,
объявленным с типом Number, компилятор Flash не обнаруживает подобные кос-
венные ошибки. Нетипизированная переменная проходит все проверки без выда-
чи сообщений об ошибках.
Чтобы использовать жесткую типизацию для проверки типов данных свойств,
необходимо создать пользовательский класс. Далее в определении класса зада-
ются типы всех свойств класса и свойств экземпляров. Например, сохранение
следующего кода во внешнем файле Ball.as дает возможность создать пользова-
тельский класс Ball, производный от MovieClip:
// Этот код ActionScript 2.0 должен храниться во внешнем файле Ball.as
class Ball extends MovieClip {
var sX:Number;
var sY:Number;
}
После этого в коде из предыдущего примера переменная ball объявляется с типом
Ball вместо типа MovieClip:
val ball:Ball: ,
При таком определении класса Flash проверяет типы свойств экземпляров (та-
ких, как ball.sX и ball.sY).
Условные команды затрудняют проверку типов. Flash поддерживает проверку
типов только на стадии компиляции, поэтому проверяемый код во время проверки
350 Глава 10. ActionScript

не выполняется. По этой причине компилятор не может распознавать конструк-


ции с условным выбором команд return. Например, в следующей команде if функ-
ция checkLimits() не вернет значения, хотя она объявлена с типом возвращаемого
значения Number:
function checkLimits(speed:Number. "limit:Number,
low:Number. high:Number):Number {
i f (false) {
return -speed:

Ho Flash проверяет только тип выражения, следующего за ключевым словом return;


в данном случае выражение -speed не приводит к ошибке компиляции.

Итоги
ActionScript 2.0 обладает средствами проверки типов, отсутствующими в Action
Script 1.0. Эти средства не влияют на производительность на стадии выполнения
и не конфликтуют со старым кодом ActionScript 1.0, не обновленным до версии
2.0. Механизм проверки типов выявляет ошибки, часто упускаемые программис-
тами, и поэтому способствует написанию правильного, надежного кода.
Хотя ActionScript 2.0 не выполняет проверку типов во время выполнения, а провер-
ка типов на стадии разработки в некоторых ситуациях затруднена, применение жест-
кой типизации сэкономит немало времени и усилий разработчику любого уровня.

Кодовые подсказки
Вывод подсказок на панели Flash Actions упрощает написание сценариев
и предотвращает опечатки. Пользуйтесь подсказками, и вам не придется
снабжать переменные суффиксами, обозначающими их тип данных.
В Flash MX появилась система подсказок, отображаемых на панели Actions (F9).
Кодовые подсказки отображаются в виде контекстного раскрывающегося списка
с именами методов и свойств, соответствующих типу данных текущего объекта.
Flash MX определяет тип данных объекта по суффиксу имени. Например, для
активизации кодовых подсказок для экземпляра класса Color имя экземпляра
должно заканчиваться суффиксом _color. При нажатии клавиши «.» (точка) пос-
ле идентификатора с суффиксом появляется кодовая подсказка (рис. 10.4).

my color.
getRGB
getTransform
setRGB
setTrsnsform
Рис. 10.4. Раскрывающийся список кодовой подсказки заполняется
в соответствии с суффиксом объекта (например, _color)

Конечно, никому не захочется присваивать экземпляру цветового объекта имя


myColor_color, а экземпляру звука - имя mySound_sound. Фирма Macromedia не
Кодовые подсказки 351

стала использовать эти суффиксы даже в большей части собственной документа-


ции. Более того, при использовании суффиксов разработчику приходилось запо-
минать суффиксы всех классов (_тс для класса MovieClip и т. д.).
Одна из малоизвестных возможностей Flash MX - активизация кодовых подска-
зок без использования суффиксов, при этом тип переменной задается специаль-
ным комментарием. Например, следующий комментарий в следующей форме
(точка с запятой обязательна) активизирует кодовую подсказку для идентифика-
тора foo как для экземпляра заданного класса MovieClip:
// MovieClip foo;
Тем, кто привык использовать суффиксы или комментарии для активизации
кодовых подсказок, будет проще использовать как кодовые подсказки,/так и жест-
кую типизацию (трюк 75) в ActionScript 2.O. Указание типа данных через двоето-
чие (см. рис. 10.5) включает как жесткую типизацию, так и кодовые подсказ-
ки независимо от имени идентификатора или наличия у него суффикса.

var myColor:Color = new Color (.};


rayCoIor.
getRGB <
getTransform \
setRGB
setTransform i

Рис. 10.5. Кодовые подсказки в ActionScript 2.0 активизируются


в соответствии с объявленным типом данных объекта

Так что теперь вам не придется мучиться с суффиксами, чтобы использовать


подсказки. Типы данных молено объявлять даже для имен экземпляров, задавае-
мых для клипов, текстовых полей и кнопок на панели свойств (помните, что
кроме создания на программном уровне, эти ресурсы можно перетаскивать из
библиотеки на сцену). Просто объявите тип данных клипа, текстового поля или
кнопки директивой var (рис. 10.6).
var myciip:MovieClip;
rayClip.
ф _accProps Ш
ф _aipha r§
||ip _currentframe .!,.;...:-.b.
$$ _dr&ptar§et
ф _focusrect
ф Jframesloaded
Ш -height
<§£ Jodoroot Ш
Рис. 10.6. Объявление типов данных для имен экземпляров, определяемых
на панели свойств для клипов, текстовых полей и кнопок

Кодовые подсказки экономят время при использовании экземпляров классов (осо-


бенно MovieClip и Button), содержащих методы с длинными именами - такие, как
createEmptyMovieClip().
352 Глава 10. ActionScript

ТРЮК Клонирование объекта


№77 ActionScript копирует объекты не по значению, а по ссылке. Если вместо
ссылки на оригинал потребуется создать независимую копию объекта,
воспользуйтесь клонированием.
Для хранения данных в программах часто бывает удобнее использовать свойства
одного объекта вместо набора независимых переменных, поскольку этот способ
обеспечивает более формальный, структурный подход. Тем не менее, поведение
объектов в некоторых ситуациях отличается от поведения простых переменных.
Рассмотрим следующий фрагмент:
var х = 5:
var у = х;
trace(y); // Вывод: 5
х += 1;
trace(x); // Вывод: б
trace(y); // Вывод: 5
Мы присваиваем х значение 5, присваиваем значение х переменной у, а затем
увеличиваем х. После выполнения приведенного фрагмента переменная х равна
6, а значение у равно 5. Как и следовало ожидать, переменные не зависят друг от
друга; изменение х после выполнения команды присваивания var у = х; не приво-
дит к изменению у. Переменные, содержащие данные примитивных типов (на-
пример, числовые), копируются по значению, потому что ActionScript копирует
значение переменной х на момент ее присваивания переменной у.
Теперь попробуем выполнить аналогичную операцию с объектами:
var objl = new ObjectO;
objl.prop = 5;
var obj2 = objl;
trace(obj2.prop); // Вывод: 5
objl.prop += 1:
trace(objl.prop); // Вывод: 6
trace(obj2.prop); // Вывод: б
На этот раз мы создали объект objl, включили в него свойство prop и присвоили
объекту obj2. Привело ли это к появлению двух самостоятельных объектов? Сра-
зу же после присваивания свойство obj2.prop равно 5, как и следовало ожидать.
Но если увеличить objl.prop и проверить значения objl.prop и obj2.prop, выясня-
ется, что они равны - свойства обоих экземпляров равны 6. Но почему это про-
изошло? Казалось бы, даже после присваивания objl.prop значения б свойство
obj2.prop должно было остаться равным 6?
Дело в том, что мы создали не два самостоятельных объекта, а две ссылки на
один объект. Обе переменные, objl и obj2, вместо примитивных данных (числа 6)
содержат указатели на один блок данных объекта в памяти.
Поскольку objl .prop и obj2.prop ссылаются на один и тот лее блок данных, измене-
ния содержимого этого блока по любой из ссылок отражаются в обеих ссылках.
Можно провести аналогию с созданием нескольких экземпляров клипа много-
кратным размещением одного символа на сцене. Последующие изменения сим-
вола клипа в библиотеке отражаются на всех экземплярах. Впрочем, аналогия
Клонирование объекта 353

лишь приблизительная - экземпляры клипа зависят от символа в библиотеке,


но остаются независимыми друг от друга. Изменения в свойствах экземпляра
одного клипа не отражаются в других клипах, производных от того же символа.
Сложные типы данных (такие, как объекты и массивы) копируются по ссылке.
Они могут занимать много места в памяти, поэтому передача по ссылке получается
более эффективной. Например, чтобы выполнить операцию с массивом, Flash пе-
редает только указатель на массив и обходится без копирования всех элементов.
Но при таком способе копирования возникают проблемы, если вместо простой
ссылки на оригинал вам нужна самостоятельная копия. Объект можно клониро-
вать явным определением каждого свойства дубликата: •
var objl = new ObjectO;
objl.propl = 5:
objl.prop2 = 12;
var obj2 = new ObjectO;
obj2.propl = objl.propl;
obj2.prop2 = objl.prop2;
trace(obj2.propl); // Вывод: 5
objl.propl += 1;
trace(objLpropl): // Вывод: 6
trace(obj2.propl); // Вывод: 5 (а не б!)
Объекты objl и obj2, а также их свойства objl.propl и obj2.prop1 стали независи-
мы друг от друга.
Чтобы вместо ссылки на объект создавалась уникальная копия объекта, в класс
Object можно включить дополнительный метод clone(). Следующий код написан
на ActionScript 1.0, но он также будет работать в ActionScript 2.0:
Object.prototype.clone = functionO {
i f ( (typeof this) != "object" || (this instanceOf Button) ||
(this instanceof TextField) ) {
// Для клипов, кнопок и текстовых полей возвращается исходная ссылка
// (то есть эти типы не клонируются),
return this;
}
var с = new ObjectO;
for (var n in this) {
var о = this[n];
if ( (typeof o) == "object" &&
!(o instanceOf Button || о instanceOf TextField)) {
// Свойство также представляет собой объект, \
// выполнить рекурсивное копирование.
} else {
// Свойства примитивных типов копируются по значению.
// В противном случае это ссылка на функцию. MovieClip.
// Button или TextField'. которые копируются по ссылке.
// поскольку для них нельзя легко создать экранное представление.
с[п] = о:

return с;
354 Глава 10. ActionScript

// Предотвратить использование метода clone в циклах for..in


// и защитить его от удаления.
ASSetPropFlags(Object.prototype.["clone"].5.1):
Приведенный фрагмент включает в класс Object новый метод Object.clone(). Как
и все классы ActionScript, он также работает с большинством классов, производных
от Object. Тем не менее, этот код не пытается клонировать клипы, потому что
встроенный метод MovieClip.duplicateMovieClipO уже умеет создавать независимые
копии клипов. Хотя в методе clone() мы могли воспользоваться методом duplicateMo-
vieClip() для клонирования вложенных клипов, обычно нежелательно дублировать
клип только потому, что ссылка на него содержится в свойстве какого-то объек-
та. По тем же причинам не рекомендуется клонировать существующие текстовые
поля или кнопки. На практике чаще встречается создание новых текстовых по-
лей (например, методом MovieClip.createTextField())( нежели клонирование суще-
ствующих полей.
При наличии предыдущего определения метода clone() следующая команда соз-
дает независимую копию (то есть клонирует) obj1 и сохраняет ссылку на новый
независимый объект в переменной obj2:
obj2 = objl.cloneO;
Сравните с командой
Obj2 = objl;
которая просто сохраняет в obj2 ссылку на тот же объект, на который ссылается objl.
Обратите внимание:
• если метод cloneQ вызывается для одного из графических классов (клип, кнопка
или текстовое поле), то вместо клонирования он возвращает ссылку на объект;
• к объекту-клону присоединяются только перечисляемые свойства. В эту кате-
горию входят свойства, которые обычно просматриваются в циклах for..in (то
есть пользовательские свойства, определяемые разработчиком), но не стан-
дартные свойства, определяющие внутренние механизмы работы класса;
• недокументированный метод ASSetPropFlagsQ (см. трюк 82) защищает метод
Object.clone() от удаления и исключает его из перебора в цикле for..in.
Тестирование метода clone() выполняется следующим образом:
// Создание тестового объекта, содержащего вложенный объект.
obj = {name:"test". num:10. boo!:true.
childObj:{childName:"original child name". childNum:5}. root:_root}:
// Клонирование объекта
cloneOfObj = obj.cloneO: •

II Изменение значения в новом объекте


cloneOfObj.childObj.chi1dName = "changed child name":
// Проверка объектов на независимость
trace("obj.childObj.childName = " + obj.childObj.childName):
traceC'cloneOfObj.childObj.childName = " + cloneOfObj.childObj.childName):
Клонирование объекта 355

Программа наглядно демонстрирует, что объект-клон и его вложенный объект-


свойство существуют независимо от объекта-оригинала и его вложенного объек-
та. Метод clone() избавляет от необходимости вручную копировать свойства и поль-
зовательские методы при создании новой копии объекта.

Клонирование в компьютерной графике


Пусть меня назовут старомодным, но я все же предпочитаю рассматривать дан-
ные с визуальной точки зрения. По этой причине вашему вниманию предлагает-
ся следующий пример, наглядно демонстрирующий различия между клонирова-
нием и копированием по ссылке.
Программа создает объект sData, который используется для управления несколь-
кими полупрозрачными клипами, формирующими эффект частиц. Эффект фор-
мируется множеством идентичных клипов, каждый из которых представляет со-
бой независимый экземпляр sData с собственной временной диаграммой.
function animateC):Void {
this.sData = sData.cloneO
this._x = this.sData.x:
this._y = this.sData.у:
this.lineStyledO. 0x404040. 10);
this.moveTo(-0.5. 0):
this.lineTo(0. 0);
this.onEnterFrame = functionO {
this.sData._x += Math.randomO * this.sData.s - sData.s / 2;
this.sData._y += Math.randomO * this.sData.s - sData.s / 2;
this._x = this.sData.x:
this._y = this.sData.y;

}
var sData:Object = new ObjectO;
sData.x = 275;
sData.s = 4;
for (var i = 0: i < 500; i++) {
var dot:MovieClip = this.createEmptyMovieClipC'dot" + i .
this.getNextHi ghestDepth());
dot.onEnterFrame = animate;
}
В этом коде представлена стандартная методика копирования анимационных
клипов по ссылке. Переменная dot содержит ссылку на экземпляр клипа dot/.
Она всегда ссылается на клип, созданный в цикле, без создания дубликата это-
го клипа.
Все клипы уникальны, поэтому каждый из них обладает независимым набором
свойств, определяющих его размеры и позицию. Программа создает простейшую
имитацию броуновского движения (случайного перемещения частиц) - рис. 10.7.
Все 500 клипов независимы друг от друга.
356 Глава 10. ActionScript

Рис. 10.7. Имитация броуновского движения из 500 клипов

Если изменить первую строку функции animate() так, чтобы копирование осуще-
ствлялось по ссылке, а не посредством клонирования:
this.sData = sData:
результат будет совершенно иным (рис. 10.8).

Рис. 10.8. Замена клонирования простым копированием изменяет вид анимации

В примере с независимыми объектами каждый клип обладал собственным объек-


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

Итоги
Ссылки на существующие клипы часто используются в циклах, когда требуется обо-
значать разные клипы одним именем. Например, в следующем цикле ссылка должна
указывать на текущий клип, только что созданный методом createEmptyMovieClip().
К новым клипам гораздо проще обращаться по имени myClip, чем писать код,
который бы ссылался на них по конкретным именам экземпляров от clipO до clip9:
for (i = 0; i < 10; i++) {
var myC1ip:MovieClip = this.createEmptyMovieClipC'clip" + i . i ) :
// Операции с текущим клипом по имени myClip
myClip._rotation = 50;
}
Иногда копирование по ссылке свидетельствует об ошибке са стороны програм-
миста, который намеревался создать независимый объект. Метод Object.clone(),
представленный в этом трюке, поможет легко создавать независимые объекты.
Тайм-аут по бездействию пользователя 357

В компьютерной графике выбор между независимыми (уникальными) данными


и ссылками на них позволяет создавать абсолютно непохожие эффекты с мини-
мальными усилиями.
Грант Скиннер

Тайм-аут по бездействию
ТРЮК

№78 пользователя
В приложениях, критичных по быстродействию, не стоит тратить процес-
сорное время на постоянные проверки действий пользователя. Создайте
событие «тайм-аута по бездействию», которое не будет мешать воспро-
изведению мультимедийной информации.
Однажды мне заказали Flash-приложение для сбора информации, которое долж-
но было работать на экранах, размещенных на спинках кресел в самолетах. Когда
пользователь на некоторое время переставал работать с приложением, оно долж-
но было переключаться на воспроизведение видеоролика. Но как только пользо-
ватель перемещал мышь или щелкал ее кнопкой, приложение должно было быс-
тро вернуться в режим ввода данных. Я написал код, выявляющий бездействие
со стороны пользователя, но без оптимизации этого кода видео воспроизводи-
лось неравномерно.
В Macromedia Director существует событие idle, инициируемое по бездействию
и позволяющее использовать свободное время для полезных целей (например,
для запуска фоновых задач). Flash-разработчики нередко повышают частоту сме-
ны кадров, пока у Flash остается свободное время (хотя его всегда меньше, чем
в Director, потому что Flash обладает более низким быстродействием). Собствен-
но, по этой причине в Flash отсутствует встроенное событие, которое бы иници-
ировалось при отсутствии полезной работы.
Пришлось крепко задуматься. Задача - создать событие, которое бы обнаружи-
вало отсутствие взаимодействия с пользователем. При получении этого события
приложение должно переключиться на выполнение других действий - скажем,
запустить анимацию или выдать звуковое приглашение. В Director такие собы-
тия называются событиями тайм-аута, но, как уже говорилось ранее, в Flash не
существует встроенных средств для обнаружения бездействия пользователя.
Пользователи часто оставляют Flash-сайты открытыми на время загрузки видео
или звука и работают в другом окне браузера. Было бы неплохо, если бы вместо
окна с надписью «содержимое загружено» SWF выдавал звуковую информацию
о завершении загрузки. Или, скажем, в автоматическом киоске при отсутствии
взаимодействия с пользователем по истечении периода тайм-аута SWF может
запустить видеоролик для привлечения покупателей.
Но как создать функцию обнаружения бездействия, которая бы не потребляла
вычислительных мощностей во время общения пользователя с SWF? Самый оче-
видный кандидат для обнаружения пользовательской активности - событие
onMouseMove (мышь в руке пользователя не может оставаться абсолютно непод-
вижной - если, конечно, пользователь не забывает дышать). Но во время активной
358 Глава 10. ActionScript

работы с приложением событие onMouseMove происходит слишком часто, и лю-


бые задержки в его обработке сказываются на быстродействии SWF. Следо-
вательно, фоновому обработчику событий не стоит полагаться на это собы-
тие.
Другой, более экономный способ выявления действий пользователя основан на
создании двух интервальных таймеров:
• короткий интервал проверяет наличие действий пользователя каждые 1-2 с
(недостаточно часто для снижения быстродействия);
• длинный интервал (обычно от 15 до 120 с) задает продолжительность тайм-
аута. Когда короткий интервальный таймер обнаруживает действие пользова-
теля, длинный интервал сбрасывается.
Эти два интервальных таймера срабатывают относительно редко по сравнению
с такими событиями, как событие onEnterFrame, инициируемое для каждого кад-
ра Flash. Мы пытаемся обойтись как можно меньшим объемом программного
кода, чтобы избежать снижения быстродействия; слишком большой объем фоно-
вых вычислений замедлит работу Flash.
Следующий короткий листинг демонстрирует работу схемы с двумя интервала-
ми. Более короткий интервал выполняет минимальный объем кода (единствен-
ная команда if). Попробуйте снять комментарии с закомментированных команд
trace() и посмотрите, какие действия выполняются в течение интервалов. Учтите,
что команды trace() выполняются довольно медленно, поэтому в окончательной
версии их присутствие нежелательно.
function idleTimeO {
// Воспроизведение анимации
//traceC"playing the animation")
gotoAndStop("attract"):
}
function idles О {
// Проверить перемещения мыши за последние две секунды
if ((_root._xmouse + _root._ymouse) != mousePos) {
// Если перемещения были, перезапустить проверку таймера
//traceC"resetting"):
gotoAndStopC'noAttract"):
clearlnterval(idle):
idle = setlntervaKidleTime. 28000);
//} else {
//traceC'no movement this period");
}
// Сохранение целого числа, представляющего позицию мыши
mousePos = _root._xmouse + _root._ymouse:
}
function startldleO {
mousePos = -100000; // Инициализация фиктивным значением
idleSample = setlnterval (idleS. 2000);
}
startldleO;
stopO;
Тайм-аут по бездействию пользователя 359

Первый интервальный таймер idleSample проверяет позицию мыши каждые две


секунды (перемещения мыши лучше идентифицировать именно так, а не в собы-
тии onMouseMove, потому что событие onMouseMove происходит довольно часто
и может замедлить работу Flash-приложения). Если сумма координат измени-
лась по сравнению с предыдущим вызовом, значит, пользователь переместил мышь,
поэтому мы сбрасываем другой, более длинный интервальный таймер idle. Если
до истечения интервала тайм-аута (28 с) пользователь не взаимодействовал с
приложением, выполняется функция idleTime(), которая активизирует воспроиз-
ведение с позиции attract (обычно при этом запускается рекламная анимация или
видеоролик).
При желании модифицируйте код таким образом, чтобы функция idleTimeQ за-
пускала некую заставку, воспроизводимую в режиме ожидания, а функция idleSQ
останавливала ее.
Предыдущая программа выполняется до тех пор, пока по истечении 30 с (2000
+ 28 000 мс) Flash не вызовет функцию idleTime() с переходом к кадру attract.
Предполагается, что обработчик события onMouseMove для этого кадра прервет
анимацию и запустит презентацию заново, когда пользователь щелкнет кноп-
кой мыши.

Итоги
Для обеспечения оптимального быстродействия в Flash необходимо свести к ми-
нимуму выполнение фоновых операций на время воспроизведения материалов,
требующих больших затрат ресурсов (видео, звук или сложная анимация). Это
означает, что фоновые задачи должны быть хорошо оптимизированы. Код про-
верки бездействия пользователя, представленный ранее, выиолняется относительно
редко, поэтому во время работы пользователя с сайтом он не замедляет воспро-
изведение основного содержания.
Если пользователь на некоторое время перестает работать с программой, активи-
зируется циклическое воспроизведение рекламного ролика или заставки. Такой
режим работы хорошо подойдет для автоматизированных киосков: если взаимо-
действие с пользователем прекращается, Flash-ролик сбрасывается в начало. Не
забудьте, что интервал тайм-аута (например, 30 с) должен быть длиннее любой
анимации, которая, как предполагается, не требует ответных действий от пользо-
вателя. Возможно, вам придется увеличить интервал тайм-аута, чтобы сделать
возможными вынужденные периоды бездействия, когда пользователь следит за
работой приложения. Впрочем, если пользователю приходится пассивно ожи-
дать в течение, скажем, 90 с и более, вместо простого увеличения интервала тайм-
аута лучше пересмотреть структуру приложения.
События нажатий клавиш также должны приводить к сбросу интервального тай-
мера. Представьте, что пользователь вводит текст на форме, но не двигает мышь;
бесцеремонный переход к заставке весьма удивит его. Следовательно, если авто-
матический киоск оснащен клавиатурой, воспользуйтесь методом Key.addListener()
для вызова обработчика onKeyDown, сбрасывающего интервал бездействия.
360 Глава 10. ActionScript

Быстрый поиск в ActionScript


Операции поиска в массивах и тексте из ActionScript выполняются отно-
сительно медленно. Небольшой фокус с переводом данных в строковый
формат позволит ускорить реализацию поиска.
Хотя Flash Player 7 работает быстрее своих предшественников, операции с текстом
и массивами все равно занимают много времени. В программной реализации по-
иска часто применяются циклы while и for. Но при многократном выполнении
операций возникает проблема: Flash не является полноценным компилируемым
языком. При публикации SWF-файла Flash преобразует сценарий ActionScript,
приближенный к естественному языку, в байт-код, понятный для Flash Player.
Таким образом, во время выполнения программы при каждой итерации цикла
Flash Player приходится преобразовывать каждую строку байт-кода в исполняе-
мые инструкции.
Если исключить из цикла повторяющиеся операции, программа будет работать
быстрее. В этом нетрудно убедиться на следующем примере, содержащем три
реализации простого поиска в массиве:
methodl = function () {
// Последовательный поиск в массиве
for (var i = 0: i<arr.length:
i f ( a r r [ i ] == nr) {
return true:

}
return false:
}:
method2 = function 0 {
// Поиск с интерпретацией массива как объекта
var i:String:
for (i in arr) {
if (arr[i] == nr) {
return true;

return false:
}:
method3 = function () {
// Поиск в массиве с предварительным преобразованием
// элементов в строку.
var searchPos:Number = arr.join(" ").indexOf(nr.toString())
if (searchPos != -1) {
return true;
}
return false:
}:
// Создание массива с последовательностью чисел от 0 до 999.
var arr:Array = new ArrayO:
var el em:Number = 1000:
Быстрый поиск в ActionScript 361

for (var i = 0 ; i < el em; i++) {


arr.pushd):
}
// Случайный выбор искомого числа.
var nr:Number = Math.floor(Math.random() * elem):
trace("searching for:" + nr);
// Тестирование метода 1
var sT = getTimerO;
methodK):
eT = getTimerO - sT:
traceC'time method 1 : " + eT);
// Тестирование метода 2
var sT = getTimerO;
method20;
eT = getTimerO - sT;
traceC'time method 2 : " + eT);
var sT = getTimerO;
method30;
eT = getTimerO - sT:
traceC'time method 3 : " + eT);
Сначала в программе создается массив с числами от 0 до 999. Затем выбирается
искомое случайное число из интервала от 0 до 99£):
\/зг nr:Number = Math, floor (Math. randomO * elem);
Далее проводится тестирование трех функций поиска числа в массиве: method 1(),
method2() и method3().
Первая функция, method1(), ограничивается простейшим поиском в цикле for.
Она последовательно перебирает все элементы массива и сравнивает их с иско-
мым числом. Если число будет найдено, функция возвращает true. Во второй
функции, method2(), используется цикл for..in. Наконец, функция method3() обхо-
дится вообще без цикла. Вместо этого она генерирует строку из всех элементов
массива, разделенных пробелами ("О 1 2 3 ? 997 998 999"), а затем ищет значение
nr в сгенерированной строке.
Сравнительное быстродействие определяется многократным выполнением функ-
ций. Программный хронометраж (см. трюк 69) помогает выявить многие про-
блемы.
Самой быстрой оказывается третья функция, method3(), обеспечивающая постоян-
ное низкое время поиска. Вместо циклического перебора элементов она преобразу-
ет данные в строковый формат и применяет к результату строковые методы Flash.
Функция method3() содержит наименьшее количество команд, так как в осталь-
ных функциях используются циклы, поэтому она выполняется чуть быстрее дру-
гих операций. Метод Array.join(), преобразующий содержимое массива в строку,
выполняется довольно быстро, потому что он реализован на C++ - компи-
лируемом языке, на котором написаны встроенные функции Flash. Методы клас-
сов String и Array, задействованные в данном трюке, показывают хорошее быстро-
действие в Flash Player 6 и 7. В предыдущих версиях Flash Player они работают
медленнее.
362 Глава 10. ActionScript

Приведенные ранее функции проверяют, входит ли целевое значение в массив,


но не показывают, в какой именно позиции. Тем не менее, скорость поиска зави-
сит от положения искомой величины в массиве.
Реализация с циклом for работает быстрее, если искомое значение расположено
ближе к началу массива:
searching for: 153
time method 1
time method 2
time method 3
Если элемент находится в середине, первые два метода дают более или менее
одинаковый результат:
searching for: 418
time method 1
time method 2
time method 3
Если искомый элемент расположен близко к концу массива, вторая функция
поиска работает быстрее первой. Дело в том, что циклы for..in просматривают
свойства (элементы массива в данном примере) в порядке, обратном порядку их
создания в объекте. Иначе говоря, перебор начинается с последнего элемента
и постепенно передвигается к первому:
searching for: 777
time method 1
time method 2
time method 3
Но во всех трех случаях третья функция поиска работает быстрее всего и обеспе-
чивает постоянное время поиска. Если содержимое массива заведомо остается
неизменным, для ускорения поиска молено сохранить результат join() во времен-
ной переменной и использовать ее в будущих операциях.
Большой объем данных замедляет строковый поиск, и все же этот способ превос-
ходит по скорости другие способы, если размер массива не превышает 10 000 эле-
ментов. Впрочем, если вам приходится выполнять поиск в наборах данных тако-
го порядка, лучше выполнить его на удаленном сервере и вернуть результат - скажем,
через Flash Remoting.

Итоги
Циклы часто применяются для выполнения повторяющихся операций, но в Flash
циклы приводят к большим затратам времени. Хорошее понимание сильных и сла-
бых сторон всех трех типов поиска (последовательного перебора элементов, пе-
ребора свойств, поиска в строке без применения циклов) позволит вам создать
оптимизированный код для любого конкретного приложения.
Материей предложен Эдвином Хейджменом
Блокировка слоя actions 363

ТРЮК Блокировка слоя actions


№80 ActionScript может размещаться практически в любой позиции времен-
ной диаграммы. Храните сценарии на специальном заблокированном слое
actions, чтобы отделить код от ресурсов.
В анимационных приложениях течение времени представляется временной диа-
граммой. В начале каждого нового кадра Flash генерирует событие onEnterFrame.
Схема выглядит абсолютно логично - до тех пор, пока в приложение не начи-
нает добавляться программный код. В отличие от других сценарных языков с цен-
трализованным хранением сценариев, код Flash может связываться с любым клю-
чевым кадром временной диаграммы, обычно в порядке выполнения.
Некоторые разработчики собирают весь код ActionScript в кадре 1 главной вре-
менной диаграммы, но во многих проектах по крайней мере часть кода приходит-
ся связывать с другими кадрами. Иногда код даже связывается с кнопками и ани-
мационными клипами на разных слоях. На длинной временной диаграмме с боль-
шим количеством слоев код постепенно распыляется, а это затрудняет отладку
и сопровождение. Разработчикам часто приходится использовать Movie Explorer
(Window • Other Panels • Movie Explorer) просто для того, чтобы найти нужный
фрагмент кода!
Чтобы не создавать себе лишних трудностей, присвойте первому слою времен-
ной диаграммы имя actions (или scripts) и связывайте все сценарии только с этим
слоем. Хранение сценариев в отдельном слое способствует централизации кода
(для хранения меток кадров, создаваемых на панели свойств, можно использо-
вать этот же слой или создать отдельный слой labels).
Вместо того чтобы связывать код непосредственно с кнопками и клипами на
других слоях, задайте кнопке/клипу имя экземпляра на панели свойств. Далее
код косвенно связывается с клипом по имени экземпляра. Код ActionScript дол-
жен размещаться в слое actions, а не в слое, содержащем клип, и не на временной
диаграмме клипа. Например, создание ссылки на клип с именем экземпляра ballClip
из кода слоя actions главной временной диаграммы с последующим заданием его
координаты х выглядит так:
var ballClip:MovieClip;
ball СИ p._x = 50;

Блокировка слоя
Чтобы слой actions сохранял свою специализацию и использовался только для
хранения сценариев, держите его постоянно заблокированным. Flash позволяет
заблокировать любой слой временной диаграммы - для этого следует щелкнуть
на точке в столбце с замком (рис. 10.9). Чтобы снять блокировку со слоя, щелк-
ните на замке, обозначающем заблокированный слой (на рис. 10.9 слой Layer 2
заблокирован). Блокировка слоя не запрещает его редактирование, как можно
было бы предположить, однако она не позволит добавлять объекты со сцены
в заблокированный слой.
364 Глава 10. ActionScript

Рис. 10.9. Чтобы заблокировать слой, щелкните на точке с столбце с изображением замка

Даже после того как слой будет заблокирован, с ним возможны следующие опе-
рации:
• добавление ключевых кадров (сценарии присоединяются только к ключевым
кадрам). Чтобы добавить ключевой кадр, выделите кадр заблокированного
слоя и нажмите клавишу F6 (или выполните команду Insert • Timeline • Keyframe).
Операция выполняется точно так же, как на любом незаблокированном слое;
• присоединение и редактирование сценариев, связанных с ключевыми кадра-
ми слоя, с применением панели Actions (F9);
• вставка кадров на заблокированном слое. Чтобы вставить кадр, выделите один
из кадров заблокированного слоя и нажмите клавишу F5 (или выполните ко-
манду Insert • Timeline • Frame). Операция выполняется точно так же, как на
любом незаблокированном слое. Следующие кадры автоматически сдвигают-
ся вправо.
Итак, блокировка слоя actions предотвращает размещение на нем графических
объектов или связывание символов с его ключевыми кадрами, в результате слой
может использоваться только для хранения сценариев. Тем не менее, блокировка
слоя не мешает добавлению и редактированию ключевых кадров и сценариев.

Итоги
Никто не запрещает вам хранить код во внешних файлах с расширением .as.
Более того, во многих ситуациях это даже рекомендуется делать вместо хранения
всего кода в первом кадре временной диаграммы. Но в отдельных случаях такое
решение оказывается непрактичным:
• создание больших анимаций с управлением временными диаграммами из
ActionScript - таких, как «The Goober Story» (http://www.humbugz.com/hela.htm);
• тривиальное управление временными диаграммами. Например, создавать специ-
альный класс для остановки клипа на кадре 12 было бы явным излишеством.
Гораздо проще (и эффективнее) добавить операцию stop() в нужный кадр;
• присоединение обработчика события к экземпляру клипа, не существующему
в первом кадре. Невозможно связать обработчик события с экземпляром до
того, как он будет существовать. Если анимационный клип не существует на
временной диаграмме до кадра 34, то присоединить к нему обработчик собы-
тия можно будет только в сценарии слоя actions в кадре 34, но не в кадре 33.
Хотя все эти ситуации способствуют распылению кода, основной код все же мо-
жет храниться в кадре 1 слоя actions - запишите все сценарии и обработчики
событий в виде функций и вызывайте функции из нужных кадров. При такой
схеме практически весь код ActionScript остается в кадре 1.
Отладка и трассировка 365

ТРЮК Отладка и трассировка


№81 Функция trace() выводит текст на панели Output. Используйте ее для по-
вышения эффективности отладки.
Отладчик (Window • Development Panels • Debugger и Control • Debug Movie) помо-
гает выполнять диагностику в реальном времени, и все же довольно часто бывает
удобнее воспользоваться функцией trace() для вывода на панель Output. Однако
следует помнить, что trace() выводит только одно выражение. Чтобы вывести
больше данных, постройте более сложное выражение при помощи строковой кон-
катенации (оператор +).
Допустим, нужно вывести текущие значения следующих переменных:
var x:Number = 10:
var у:Number = 20;
var z:Array = [10. 20. 30. 40];
var w:Object = {pi:10. p2:"hello". p3:true}
Если переменные х и у определяют координаты графического объекта, уместно
вывести их в одной строке в формате (х, у):
traceC 1 (" + х + ". " + у + " ) " ) ;
Результат выглядит так:
(10. 20)
Чтобы разбить выводимые данные на несколько физических строк, воспользуй-
тесь несколькими командами trace() или служебной последовательностью \п. Так,
фрагменты
trace("x is: + x);
trace("У is: " + У):
и
trace("x is: " + x + "\n" "y is: " + у + "\n");
выводят одинаковый результат:
x is: 10
у is: 20
Простая трассировка массива (то есть передача имени массива функции trace())
выводит список всех элементов массива. Так, для определенного ранее мас-
сива z команда
trace(z)
выведет список
10.20.30.40
Обратите внимание: элементы массива не разделяются пробелами. Чтобы результат
выглядел более привлекательно, организуйте разделение при помощи метода
Array .join():
trace(z.join(". " ) :
Результат выглядит так:
10. 20. 30. 40
366 Глава 10. ActionScript

Команда
trace(z.join("\n");
выводит элементы в разных строках:
10
20
30
40
При работе с объектами для перебора перечисляемых свойств применяется цикл
for.jn. Для предыдущего определения w фрагмент
for (var i in w) {
traceC'w." + i + " = " + w[1]):
}
выведет следующий результат:
w.pl = 10
w.p2 = hello
w.p3 = true
Неперечисляемые свойства (например, встроенные свойства и методы, скрытые
от ActionScript) можно вывести недокументированной функцией ASSetPropFlags()
(см. трюк 82).
Часто сценарий ActionScript делает не то, что требуется, и вы не можете понять,
почему это происходит. Нередко причина кроется в недействительности экзем-
пляра (вы думаете, что переменная содержит действительный клип или экземп-
ляр объекта, а на самом деле в ней хранится «мусор») из-за ошибки программи-
рования или опечатки в имени экземпляра на панели свойств. К сожалению, если
Flash Player не может выполнить операцию из-за недействительности экземпля-
ра, он не выдает сообщений об ошибке. Диагностика таких проблем осложняется
рядом факторов:
• обычно проблема возникает при динамическом создании клипов и в больших
иерархиях временных диаграмм; отладчик загромождается информацией, что
затрудняет процесс диагностики;
• даже если экземпляр отображается в отладчике, он может не существовать
в начале кадра или область видимости переменной может отличаться от ожи-
даемой. Чтобы выявить подобные проблемы в отладчике, необходимо расста-
вить точки прерывания и вручную выполнять код в пошаговом режиме, строка
за строкой. Отладка такого рода занимает много времени.
Чтобы проверить действительность экземпляра на момент использования, вклю-
чите в программу отладочную команду trace() следующего вида:
for (var i in this) {
i f (i.indexOfC'myClip". 0) != -1) {
trace(myClip._name + " is on timeline " + this):

Если экземпляр myClip виден на главной временной диаграмме, то на панели


Output выводится строка myClip is on the timeline JevelO. В противном случае ин-
формация не выводится. Обратите внимание: выводимое сообщение содержит
Отладка и трассировка 367

подробную информацию о том, что и где было обнаружено, - верный признак


грамотного подхода к отладке. Если ограничиться кратким сообщением «found
it!», через полгода вы и не вспомните, что оно означает. Также проследите за тем,
чтобы команды trace() выводили разный текст, иначе вам будет трудно отличить,
какой именно команде trace() было передано управление. Например, следующий
фрагмент выводит информацию о типе аргумента incoming. Если incoming являет-
ся объектом, выводится строка «Incoming object in checkObject() is of type: object»:
function checkObject(incoming) {
trace("Incoming object in checkObjectO is of type: "
+ typeof incoming);
}
В сообщения trace() часто включаются префиксы, которые упрощают понимание
логики и результатов:
survey.fla > Starting up.
xmlutils > Loaded.
view > Loaded. Let's draw the display.
display > Drawing.

Итоги
Отладочная информация обычно выводится только на стадии разработки. Чтобы
предотвратить вывод отладочной информации в работающем приложении, от-
кройте диалоговое окно File • Publish Settings • Flash и установите флажок Omit
Trace Actions. Flash игнорирует вызовы trace() при экспортировании, и результат
будет таким же, как если бы все вызовы trace() в FLA были закомментированы.
Для решения более сложных задач отладки и сокращения объема данных, выво-
димых командами traceQ, можно создать пользовательскую, централизованную
функцию трассировки, исключаемую из окончательной версии сайта перед пуб-
ликацией.
В следующем листинге продемонстрирована простая схема изменения детализации
отладочных сообщений. Сообщения ставятся в очередь функцией сТгасе {сообще-
ние,приоритет). Если приоритет ниже пороговой величины verboseLevel, сообще-
ние не отображается на панели Output. В следующем примере при нулевом значе-
нии verboseLevel выводятся оба сообщения, а если переменная verboseLevel равна 1,
будет выведено только первое сообщение:
сТгасе = function (message, priority) {
i f (priority >= verboseLevel) {
trace(message):

}
// Применение:
verboseLevel = 1:
cTraceCImportant message", 1); // Сообщение выводится
cTrace("Low-priority message". 0): // Сообщение не выводится
Еще одно возможное усовершенствование - фильтрация сообщений. Например,
при большом количестве ошибок было бы логично начать с исправления самых
существенных проблем, а затем перейти к менее важным. Следующая программа
368 Глава 10. ActionScript

скрывает все сообщения с приоритетом, более низким, чем максимальный приори-


тет последнего сообщения. Фильтрация позволяет сосредоточиться на отладоч-
ной информации, которая с наибольшей вероятностью окажется актуальной для
исправления ошибок. В следующем примере последнее сообщение остается скры-
тым, потому что ошибка, скорее всего, обусловлена сообщением с более высоким
приоритетом.
Допустим, сообщение с наивысшим приоритетом указывает на ошибку загрузки
XML-файла. Менее важное сообщение «В XML-файле обнаружены непредви-
денные символы» следует скрыть до того момента, когда XML-файл удастся за-
грузить:
сТгасе = function (message, p r i o r i t y ) {
i f ( p r i o r i t y >= verboseLevel) {
verboseLevel = p r i o r i t y ;
trace(message):

}
// Применение:
verboseLevel = 0:
cTraceC'XML f i l e not loading". 2);
cTrace("Unexpected characters found in XML f i l e " . 1);
Наконец, если тестирование должно осуществляться за пределами среды разра-
ботки (скажем, в браузере), отладочная информация может выводиться в тексто-
вых полях. В следующем листинге диагностические данные перенаправляются
в текстовое поле myText - предполагается, что поле уже существует на сцене
(изменения выделены жирным шрифтом). Чтобы прекратить вывод отладочной
информации, проще всего переместить текстовое поле на опорный слой:
сТгасе = function (message, p r i o r i t y ) {
i f ( p r i o r i t y > verboseLevel) {
verboseLevel = p r i o r i t y :
myText.text += messsage + "\n";

Недокументированные возможности
ТРЮК

№82 ActionScript
Недокументированные возможности ActionScript интересны всем. В на-
стоящем разделе рассматривается недокументированная область види-
мости _global.
Нередко для решения какой-то важной задачи требуется перебрать свойства объек-
та. Допустим, вы хотите вывести значения свойств на панели Output для получения
отладочной информации. Другой пример - декодирование неизвестных свойств
объекта, возвращенного, скажем, при обращении к базе данных на сервере. Есте-
ственно, нам хотелось бы перебрать скрытые (недокументированные) свойства
ActionScript и посмотреть, не найдется ли в них чего-нибудь интересного.
Недокументированные возможности ActionScript 369

С точки зрения интерпретатора Flash базовый цикл ActionScript for..in означает


следующее: «Взять указанный объект и для каждого из его свойств (включая
методы, хранящиеся в свойствах) выполнить тело цикла».
Тем не менее, многие встроенные методы и свойства ActionScript по умолчанию
исключаются из перебора в цикле for..in. Фирма Macromedia предполагает, что
программиста интересуют объекты и свойства, созданные им в программе, а не
те, которые заложены в основу работы ActionScript, поэтому встроенные свой-
ства исключаются из перебора for..in. Недокументированная функция ASSetPropFlags()
позволяет сделать видимыми даже те свойства и методы, которые обычно оста-
ются невидимыми для перебора.
Macromedia часто добавляет новую функциональность в обновленные версии своих
программ. Например, многие возможности Flash Player 7 не документировались
и не поддерживались официально (но работали!) в Flash Player 6.0.65.0. Каждый
раз, когда Macromedia выпускает новую версию Flash Player (особенно на позд-
них стадиях жизненного цикла продукта), я проверяю, не появилось ли в ней
чего-нибудь интересного.
Как нетрудно догадаться по ее имени, функция ASSetPropFlags() позволяет зада-
вать флаги защиты свойств из ActionScript. Флаги указывают Flash Player, долж-
ны ли соответствующие методы и свойства включаться в перебор for.Jn.
Функция ASSetPropFlags() также позволяет запретить запись (или перебор) свойств
и методов пользовательских объектов, чтобы предотвратить их случайную моди-
фикацию. Это особенно актуально для глобальных свойств распространяемых
компонентов, чтобы предотвратить конфликты со сторонними компонентами,
используемыми в том же SWF-файле.
Давайте в общих чертах посмотрим, как же работает функция ASSetPropFlags().
Синтаксис вызова ASSetPropFlags():
ASSetPropFlадз(обьекг. свойства. маскаТгие, MacKaFalse)
где:
• объект - объект или область видимости;
• свойства - свойства/методы объекта, для которых вы собираетесь изменить
флаги защиты. Специальный аргумент null означает «все свойства»;
• маскаТгие - целочисленная битовая маска, определяющая флаги конфигура-
ции. Значимыми являются три последних бита целого числа, представляю-
щие (справа налево) флаги «защиты от перезаписи», «защиты от удаления»
и «скрытия». Например, двоичное значение НО (06 в шестнадцатеричной за-
писи, 6 в десятичной) защищает свойства, заданные вторым параметром, от
записи и удаления, но перестает скрывать их при переборе;
• MacKaFalse - другая целочисленная битовая маска, которая работает анало-
гично маскеТгие, но сбрасывает заданные флаги. MacKaFalse применяется до
применения маскиТгие.
На странице FlashCoders Wild (http://chattyfig.figleaf.com/flashcoders-wiki/7AssetProp
Flags) имеется диаграмма с описанием различных битовых масок, используемых функ-
цией ASSetPropFlags().
370 Глава 10. ActionScript

Свойства/методы, которые мы хотим сделать видимыми, принадлежат к области


видимости _global, содержащей все встроенные классы ActionScript. Таким обра-
зом, после выполнения следующей команды все классы ActionScript становятся
полностью доступными для перебора:
ASSetPropFlags(_global. null. 6. 1):
Следующий фрагмент выводит список всех классов, найденных в открытой обла-
сти видимости:
// Установить флаги защиты в _global равными 110(дв.).
// чтобы сделать их доступными для перебора
ASSetPropFlags(_global. n u l l . 6. 1);
// Составление списка объектов в _global
for (thisObject in _global) {
trace(thisObject):
}
Чтобы узнать, есть ли в этих классах что-нибудь интересное, мы последовательно
переберем все их свойства. Если при поиске обнаружится свойство prototype, в ко-
тором хранятся методы и свойства класса (в ActionScript 1.0 и 2.0), мы переберем
его содержимое:
// Установить флаги защиты в _global равными 110(дв.).
// чтобы сделать их доступными для перебора
ASSetPropFlags(_global. n u l l . 6. 1);
// Составление списка объектов в _global
for (thisObject in _global) {
ASSetPropFlags(_global[thisObject]. n u l l . 6. 1);
trace("\n" + thisObject):
for (props in _global[thisObject]) {
t r a c e r " + props):
// Вывод содержимого prototype,
i f (props == "prototype") {
ASSetPropFlags(_global[thisObject].prototype, n u l l . 6, 1):
for (protoChain in _global[thisObject].prototype) {
traceC • " + protoChain):

Если присоединить этот код к кадру 1 и протестировать ролик в Flash MX 2004, он


выведет длинный список документированных классов с методами и свойствами (в кни-
ге он занял бы около 10 страниц). Далее приведен фрагмент списка для класса String:
String
fromCharCode
proto
constructor
prototype
substr
split
substring
Недокументированные возможности ActionScript 371

slice
lastlndexOf
indexOf
concat
charCodeAt
charAt
toLowerCase
toUpperCase
toString
valueOf
_proto
constructor
Как видите, сначала перечисляются методы и свойства классов, а за ними следу-
ют методы и свойства экземпляров, объединенные в категорию prototype.
Попробуем обратиться к методам и свойствам класса из функции traceQ и посмот-
рим, что они вернут. В следующем примере вызывается метод String.fromCharCode(),
получающий один числовой аргумент (мы знаем об этом, поскольку метод fromChar
Code является документированным):
trace(String.fromCharCode(65)); // Вывод: А
Однако в список также входят недокументированные классы:
Cookie
setCookie
getCookie
proto_
constructor
Нам придется гадать, что представляет элемент списка - свойство или метод,
а если метод - с какими параметрами он вызывается. Например, команда
trace(Cookie.getCookieO):
выводит следующее сообщение:
Error opening URL "fi1e:///Сj/WINDOWS/PROFILES/SHAM^20B/
APPLICATIONX20DATA/MACROMEDIA/FLASHX20MXX202004/EN/
CONFIGURATION/Mmfdata/mmfdata3ff9fldf.xml"
В сообщении говорится об ошибке открытия конкретного файла, хотя при вызо-
ве метода никакое имя не указывалось!
Поэтому я попытался создать cookie методом Cookie.setCookie():
Cookie.setCookieC'footest data");
Далее последовал повторный вызов getCookie():
trace(Cooki e.getCooki e()):
На этот раз ошибки не было! Напрашивалось логичное предположение, что ме-
тод setCookie() успешно сохранил файл, который искал метод getCookieQ.
Я нашел файл mmfdata3ff9f1df.xml в каталоге, указанном в сообщении об ошибке,
открыл его в текстовом редакторе - и действительно, файл содержал положен-
ный текст:
footest data
372 Глава 10. ActionScript

Но вызов trace(Cookie.getCookie()); ничего не выводил на панели Output, поэтому


я проверил тип возвращаемого значения:
trace(typeof Cookie.getCookieO):
На панели Output появилась строка object. Значит, метод getCookieQ возвращает
объект! Быстрый перебор в цикле for..in дал информацию о свойствах объекта:
они совпадали со свойствами класса XML с добавлением еще нескольких свойств.
Следующий листинг подтверждает, что объект является экземпляром класса XML
(хотя более вероятно - пользовательским субклассом класса XML):
Cookie.setCookieC'footest data"):
result = Cookie.getCookieO;
trace (typeof result);
trace (result instanceof XML);
for (props in result) {
trace(props);
}
Декодирование структуры XML для получения исходного текста «footest data»,
переданного при вызове setCookie(), остается читателю для самостоятельной ра-
боты. Счастливой охоты!

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

ТРЮК «Черный ход» ASnativeO


№83 Каждый вызов метода ActionScript отображается по таблице на одну из
внутренних функций, встроенных в Flash Player. Прямой доступ к таблице
внутренних функций осуществляется недокументированным методом
ASnative().
Flash Player поддерживает ряд методов, отсутствующих в API ActionScript. Эти
функции не только не документированы, но даже не имеют имен! Они хранятся
в таблице функций, а доступ к ним осуществляется по индексам.
Недокументированная функция ASnativeO позволяет вызывать внутренние мето-
ды ActionScript, в том числе и те, которые не удается найти при помощи функции
ASSetPropFlags() (см. трюк 82). Похоже, индексирование осуществляется по таб-
лице с использованием двух индексов:
ASnative(<3. Ь);
Нетривиальное применение операторов 373

или в отдельных случаях - с передачей необязательного списка аргументов:


ASnative(t3. b){args);
Индекс а - целое число, определяющее класс ActionScript; индекс Ъ - целое
число, определяющее метод класса, a args - один или несколько аргументов,
связанных с этим методом.
Например, индекс а = 200, соответствует классу Math, поэтому изменение индекса Ь
открывает доступ к различным методам класса Math. Попробуйте выполнить сле-
дующий фрагмент:
trace(ASnative(200.0)(-4.567): // Вывод: 4.567
trace(ASnative(200.9)(144): // Вывод: 12
По результатам тестов можно предположить, что ASnative(200,0) соответствует
методу Math.abs(), a ASnative(200,9) соответствует методу Math.sqrt(). Все это, ко-
нечно, интересно, но зачем использовать малопонятные вызовы ASnativeQ для
вызова документированных методов ActionScript?
Большинство комбинаций (а, Ь) при вызове ASnativeQ в точности эквивалентны
вызовам документированных методов документированных классов. Тем не ме-
нее, некоторые индексы не имеют явных аналогов в ActionScript, поэтому их
вызов возможен только через «черный ход» ASnative().
Одним из таких примеров является вызов ASnative(800,&). Похоже, индекс 800 от-
крывает доступ к функциям ввода/вывода, включая недокументированные мето-
ды класса Mouse (см. трюк 62).

Итоги
Поиск недокументированных возможностей Flash Player до того, как Macromedia
сообщит о них, превратился в любимую игру многих пользователей Flash. На стра-
нице FlashCoders Wiki (http://chattyfig.figleaf.com/flashcoders-wiki/index.php7ASnative)
приводятся подробнейший отчет о текущем состоянии дел, а также дополнитель-
ная информация о методе ASnativeQ и его параметрах.

Нетривиальное применение
ТРЮК

№84 операторов
Недокументированные возможности ActionScript — не единственная благо-
датная почва для любопытных программистов. Оказывается, некоторым
операторам ActionScript также можно найти нетривиальное применение.
Типичный разработчик решает 90 % своих задач при помощи 10 % возможностей
ActionScript. Прочие возможности ActionScript используются очень редко или
в крайне специфических ситуациях. Впрочем, некоторые средства ActionScript
применяются редко лишь потому, что разработчики не умеют ими правильно
пользоваться или не знают, как найти им неочевидные применения.
В настоящем разделе описаны альтернативные способы использования некото-
рых команд и операторов ActionScript.
374 Глава 10. ActionScript

Оператор вычисления остатка


Оператор % возвращает остаток от целочисленного деления. Например, выраже-
ние 15%6 равно 3, то есть остатку от деления 15 на 6:
trace(15 % б): // Вывод: 3
Для чего это нужно? Так как результат а%Ь никогда не бывает больше Ь, опера-
тор % может использоваться для ограничения значений а интервалом от 0 до Ь.
Следующая анимация помогает наглядно представить результат. Присоедините
код к первому кадру нового ролика - и увидите, что центральная точка клипа
ball никогда не выходит за линию х = 300. Функция clampQ, используемая как
обработчик onEnterFrame для клипа ball, вычисляет горизонтальную координату
ball по формуле (this._x+speed)%300. Следовательно, ball._x принимает значения
из интервала от 0 до 300.
function clamp():Void {
this._x = (this._x + speed)*300:
}
// Создание клипа ball
var ball :MovieClip = this.createEmptyMovieClipC'ball",
thi s.getNextHighestDepthC));
ball.lineStyle(20. 0x0. 100);
ball.lineToCO. 1);
ball._x = 0;
ball._y = 200;

// Создание линии
t h i s . l i n e S t y l e ( n u l l . 0x0. 100);
this.moveToOOO. 190):
this.lineTo(300. 210);
var speed = 4;

// Создание анимации
ball.onEnterFrame = clamp;
Оператор % также может применяться для усечения величины до ближайшего
числа, кратного заданному. Если х=а%Ь, то прибавление или вычитание х%Ь из х
позволяет привести х к целому числу, нацело делящемуся на Ь. Следующие ко-
манды выводят 300 и 400 соответственно:
х = 350;
trace(x - х$100): // Ближайшее меньшее число, делящееся на 100
traceCx + хЯЮО); // Ближайшее большее число, делящееся на 100
В следующем примере этот прием используется для реализации перетаскивания
мышью с привязкой к координатной сетке. Клип ball следует за мышью и автома-
тически выравнивается по координате, кратной 30 пикселам:
ball.onMouseMove = function О {
this._x = _xmouse -_xmouse%size;
this,_y = _ymouse -_ymouse%size:
updateAfterEventO:
}:
size = 30:
Нетривиальное применение операторов 375

В файле dragger.fla на сайте книги этот код используется для создания набора
мозаичных пластинок, которые могут располагаться только в фиксированных
позициях вдоль сетки. Запустите пример и попробуйте перетаскивать мышью
цветные квадраты - вы увидите, что они привязываются к ближайшему узлу
сетки и плотно прилегают друг к другу, как показано в правой части рис. 10.10.

Рис. 10.10. Цветные квадраты автоматически выравниваются


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

Возможные области применения выравнивания по сетке:


• головоломки, особенно игры типа «15» и мозаики;
• игры жанра «action» со спрайтовой графикой;
• настольные игры;
• графические ОС-подобные интерфейсы (сайт выглядит как рабочий стол опе-
рационной системы, а для управления используются операции наведения,
щелчки и перетаскивание).

Оптимизация интервальных проверок


Метод Math.abs() возвращает абсолютное значение (модуль) выражения. Так,
Math.abs(5) и Math.abs(-5) равны 5. Операция довольно простая, но на ее базе
строится эффективная проверка принадлежности числа к заданному интервалу.
Просто сдвиньте интервал так, чтобы его начальная и конечная точки имели
одинаковые модули (например, -5 и +5 вместо 0 и 10).
Традиционно в проверке верхней и нижней границ для координат . г и г / клипа
было задействовано четыре условия. Чтобы сократить количество условий до
двух, достаточно сдвинуть начало координат в центр сцены. Для стандартных
размеров сцены (550 х 400) минимальное и максимальное значения координаты
х равны -275 и 275 соответственно (вместо 0 и 550), а координата у лежит в ин-
тервале от -200 до 200 (вместо интервала от 0 до 400).
376 Глава 10. ActionScript

Эффект оптимизации становится очевидным лишь в том случае, если операция


должна выполняться действительно быстро, как в следующем примере. Мы уста-
навливаем таймер с интервалом 1 мс, чтобы Flash воспроизводил анимацию как
молено быстрее. Оптимизированная интервальная проверка выделена жирным
шрифтом.
function animCtarget:MovieClip):Void {
i f (Math.abs(target._x)>275) {
target.xSpeed = -target.xSpeed;
}
if (Math.abs(target._y)>200) {
target.ySpeed = -target.ySpeed;
>
target._x += target.xSpeed;
target._y += target.ySpeed:
updateAfterEventO;
}
// Создание клипов
for (var i = 0: i < 20; i++) {
var ball :MovieClip = this.createEmptyMovieClipC'ball"+i.
this.getNextHi ghestDepth());
ball.lineStyle(5. 0x0808AF. 100):
ball ЛineTo(0. 1);
ball.xSpeed = Math.randomO * 10;
ball.ySpeed = Math.randomO * 10;
this["fastAnim"+i] = setlnterval(anim. 1. ball);
}
// Получение размеров экрана
var temp:String = Stage.sealeMode;
Stage.sealeMode = "exactFit";
var sWidth:Number = Stage.width;
var sHeight:Number = Stage.height;
Stage.sealeMode = temp:
// Перемещение начала координат сцены в центр.
this._x = sWidth/2;
this._y = sHeight/2;
// Разметка сцены.
this.1ineStyleCundefined. 0x0. 100):
this.beginFilUOxFOFAFF. 100);
this.moveTo(-sWidth. sHeight). this.lineTo(sWidth. sHeight):
this.lineTo(sWidth. -sHeight). this.lineToC-sWidth. -sHeight);
this.endFilK);
Статическое изображение на рис. 10.11 не дает нормального представления
о происходящем. На современном компьютере точки быстро передвигаются по
сцене. При недостаточной частоте обновления монитора многие точки вообще
будут незаметны, и вы увидите лишь след, остающийся за ними!
На моем компьютере оптимизация интервальной проверки для клипов размером
5 пикселов приводила к ускорению анимации на 15-20%. Прирост скорости су-
щественно зависит от производительности компьютера и сложности графики клипа
(помните, что «узким местом» по быстродействию обычно является перерисовка
экрана, а не код).
Нетривиальное применение операторов 377

Рис. 1 0 . 1 1 . Демонстрация оптимизированной интервальной проверки

В следующем листинге методы Math.minQ и Math.max() отсекают значение пере-


менной по границам интервала. Проверка условий отсутствует, значение просто
«загоняется» в нужный интервал (предполагается, что начало координат не сме-
щалось). Прием хорошо подходит для объектов с ограниченными перемещения-
ми объекта - например, перемещения бегунка вдоль шкалы, но не для объектов,
меняющих курс (например, прыгающего мяча). Предотвращение выхода за гра-
ницу сцены реализуется так:
function animCtarget:MovieClip):Void {
target._x = Math.max (0. Math.min (target._x + target.xSpeed. 550)):
target._y = Math.max (0. Math.min (target._y + target.xSpeed. 400)):
updateAfterEventO;
}
Или в более общем виде:
function clip(input:Number, minVal:Number. maxVal:Number):Number {
return Math.max (minVal. Math.min (input. maxVal)):
}
function anim(target:MovieClip):Void {
target._x = clip (target._x + target.xSpeed. 0. 550);
target._y = clip (target._y + target.xSpeed. 0. 400):
updateAfterEventO;

Инерционное движение с применением


поразрядного сдвига
Основной единицей измерения в Flash является твип (1/20 пункта). Flash позво-
ляет определять расстояния в пикселах с точностью до 0,05 пиксела (меньшие
378 Глава 10. ActionScript

приращения игнорируются), поэтому вывод пиксела с координатами (10,5; 10,5)


вполне допустим. Для вывода графики в позициях с дробными координатами
применяется сглаживание. Размывка пиксела создает иллюзию его смещения,
хотя схема адресации пикселов в видеоадаптере поддерживает только целочис-
ленные позиции - например, (10; 10). К сожалению, эффект размывки приводит
к потере детализации, поэтому графику лучше располагать с целочисленными
интервалами.
Инерционное движение (см. трюк 39) также входит в арсенал эффектов, часто
применяемых в Flash. Однако стандартный алгоритм расчета инерции возвраща-
ет дробные значения в пикселах. Например, следующий фрагмент создает хоро-
шо знакомый клип ball и анимирует его, имитируя инерционное движение к по-
зиции мыши:
inertia = function ():Void {
this._x -= (this._x - _xmouse) / 4;
this._y -= (this._y - _ymouse) / 4;
trace(this._x);
}:
// Создание клипа ball
var ball :MovieClip = this.createEmptyMovieClipC'ball",
this.getNextHi ghestDepth());
ball.lineStyle(20. 0x0. 100);
ball.lineTo(0, 1);
ball.onEnterFrame = inertia;
Ни одно из трассируемых значений (this._x) не является целым числом. Клип
может выглядеть размытым, поскольку он позиционируется между границами
физических пикселов. Другой типичный пример - добавление эффекта инерции
в раскрывающиеся меню и полосы прокрутки часто приводит к утрате четкости
текстом и нарушениям при выводе растровых шрифтов.
Деление на 4 в предыдущем примере (это произвольное значение было выбрано
лишь потому, что оно создает приятный эффект инерции на частоте смены кад-
ров 18 fps, с которой я предпочитаю работать) можно заменить сдвигом вправо на
два двоичных разряда:
inertia = function():Void {
this._x -= (this._x - _xmouse) » 2;
this._y -= (this._y - _ymouse) » 2;
trace(this._x)
};
Операция >>2 означает, что биты операнда сдвигаются на 2 разряда вправо, что
2
эквивалентно целочисленному делению результата на 2 , то есть 4. Сдвиг выпол-
няется быстрее стандартного оператора деления ActionScript /, выполняющего
вещественно деление. Теперь команда trace{) выводит только целочисленные зна-
чения, а анимация становится гораздо более четкой. Предполагается, что контент
выравнивается по ближайшему пикселу (View • Snapping • Snap to Pixels), а разме-
ры графических объектов кратны размерам пиксела (для этого следует задать
целые значения свойств Width и Height на панели свойств).
Импортирование ASC-файлов как формата XML 379

Итоги
Как видите, у стандартных операторов ActionScript находится много неочевид-
ных применений, которые часто превосходят типовые решения по компактности
или скорости. Помните о них, если быстродействие действительно критично для
вашего приложения.

Импортирование ASC-файлов
ТРЮК

№85 как формата XML


Базовая загрузка текстовых файлов может осуществляться методами
класса XML. Далее остается лишь разобрать единственный созданный
узел XML.
Распространенный формат XML применяется для отправки и получения данных
от Flash Player. Для загрузки небольших объемов данных (или при отсутствии
структурирования) также часто применяется класс LoadVars. Формат XML явля-
ется фактическим стандартом в веб-дизайне и веб-технологиях, но многие прило-
жения используют собственные форматы данных, не поддерживаемые Flash Player.
Загрузка нестандартных данных в Flash обычно производится одним из двух
стандартных способов: преобразованием данных в XML или разделением текста
амперсандами (для LoadVars). В обоих случаях при обновлении исходных дан-
ных форматирование приходится выполнять заново, что снижает эффективность
работы и повышает вероятность внесения ошибок во время преобразования.
Другой, более эффективный путь - импортирование данных из формате исход-
ного приложения. Настоящий раздел посвящен формату ASC, поддерживаемому
многими приложениями.

Формат ASC
Файл в формате ASC представляет собой последовательный ASCII-файл, содер-
жащий серию строк с данными, разделенными пробелами. Каждая строка завер-
шается символом новой строки (или другим ограничителем):
data data data data data<CR>
data data data data data<CR>

data data data data data<CR>


ASC и его аналоги обычно используются в качестве обобщенного формата, легко
загружаемого в любое приложение. Во многих программах трехмерной графики
имеются дополнительные модули экспортирования и импортирования ASC-фай-
лов, хотя лишь немногие программы обладают интегрированной поддержкой AS С.
ASC-файлы легко редактируются в любом текстовом редакторе:
• файл содержит простые ASCII-данные;
380 Глава 10. ActionScript

• в данных отсутствуют непечатаемые символы или служебные последователь-


ности (управляющие коды);
• данные структурируются в табличном виде, легко воспринимаемом человеком.
Не путайте формат ASC со специализированным форматом ASC (ActionScript
Communications), используемым Flash Communication Server MX.
В этом трюке будет использоваться ASC-файл, созданный в 3D Studio Max. Как
видно из листинга, он представляет собой простую таблицу данных:
Ambient light color: Red= 0.0 Green= 0.0 Blue= 0.0

Named object: "TorusOl"


Tri-mesh. Vertices: 100 Faces: 200
Vertex l i s t :
Vertex 0: X:-0.4 Y: 0.0 Z:61.1
Vertex 1: X:-0.4 Y:-11.8 Z:57.3

Vertex 98: X:-27.5 Y:19.0 Z:38.5


Vertex 99: X:-33.4 Z:46.6
Face l i s t :
Face 0: A:0 E C:10 AB:0 ВС:1 CA:1
Smoothing: 1
Face 1 A:0 :1 BC:1 CA:
Smoothing: 1

Face 198: A:99 B:0 C:9 AB:0 ВС:1 CA:1


Smoothing: 1
Face 199: A:99 B:90 C:0 AB:1 ВС:1 CA:0
Smoothing: 1
Данные определяют трехмерную фигуру - тор (рис. 10.12).
Как же загрузить ASC-файл в Flash? Одно из самых простых (хотя и неочевид-
ных) решений заключается в том, чтобы заставить Flash интерпретировать файл
как данные в формате XML. Поскольку в действительности файл не содержит
XML-кода, Flash считает, что в нем определяется только один узел - строка
с полным содержимым файла. Для разбора этой строки используются стандарт-
ные строковые функции (вместо функций разбора узлов XML).

Рис. 10.12. Тор в 3D Studio Max


Импортирование ASC-файлов как формата XML 381

Импортирование и разбор ASC-файла


Функции handlelncomingO и readXMLStartQ в следующем листинге заставляют Flash
загрузить ASC-файл как файл в формате XML. Если загрузка проходит успешно,
содержимое файла помещается в строку my3dFile.
Мы знаем, что каждая строка ASC-файла содержит взаимосвязанные данные и за-
канчивается символом перевода строки (\п или Key.ENTER в Flash). Чтобы раз-
бить ASC-файл на отдельные строки, мы просто перебираем файл и ищем оче-
редное вхождение \п. Функция String.split() не используется, потому что мы все
равно будем перебирать массив в поисках интересующих нас данных. Функция
readASCO разделяет ASC-файл на строки и сохраняет их в массиве с именем
shape.
handleIncoming = function (success) {
i f (success) {
readXMLstartO:

}
readXMLstart = function () {
my3dFile = xObj.firstChild.nodeValue;
readASCO:
}:
readASC = functionО {
var olndex:Number = 0:
var гIndex:Number = 0;
var el em: String = "";
while (rlndex != -1) {
rlndex = my3dFile.index0f("\n". olndex):
elem = my3dFile.substring(oIndex. rlndex);
// Пропускаем дополняемые строки (длина менее 30 символов)
if (elem.length > 30) {
shape[shape.length] = elem:
}
olndex = rlndex + 1;
}
var xObj:XML = new XMLO:
var my3dFile:String = new StringO:
var shape:Array = new ArrayO:
xObj.onLoad = handlelncoming;
xObj.load("torus.asc");
Метод String.substring() просматривает содержимое my3dFile и извлекает символы
между начальной позицией первого необработанного символа olndex и позицией
следующего перевода строки rlndex:
rlndex = my3dFile.indexOf("\n". olndex);
elem = my3dFile.substring(oIndex. rlndex):
Значение rlndex определяется поиском следующего вхождения \п с использова-
нием метода String.indexOf(). Программа узнает о достижении конца ASC-файла,
когда метод String.indexOf() возвращает -1 - признак того, что искомая строка не
найдена.
382 Глава 10. ActionScript

Некоторые строки ASC-файла не представляют для нас интереса (например, по-


тому что вместо описаний точек и линий в них содержится другая информация).
Прежде чем считать текущую строку действительной, необходимо избавиться от
таких строк по некоторому критерию. В нашем случае, если длина строки превы-
шает 30 символов, данные считаются действительными и сохраняются в массиве
shape:
i f (elem.length > 30) {
shape[shape.length] = el em;
}
На рис. 10.13 изображены первые 10 элементов массива shape, сгенерированного
этой программой. Вскоре из массива будут отфильтрованы все элементы, не со-
держащие информации о вершинах.

а !•• о ; "Ambient itght cofor №ed= 0Л Green= S.S Bb«= O.OV*


I- t r r -mesh Vertices; 1«S Facess 200\r*
Vertex D. X--0 4 У 3.S Z:4J.iV
!г з 'Vertex is • -3.4 Yi-114 2s57^,r*
; 4 /erte> 2: - :-:.4 У;-19Л 2;4?.3\r"
!•• E |*Verts3<3: X:-0.4 Y:-I9.S 2i34,9\r*
!" 6 1 "Vertex 4: X;-0.4 Ys-1141 Z:24.3\r*
:- 7 "Vertex S: X 34 " O.S Ii21.!\r"
... g i "Verts* 6; X::-Q,4 Y;li.S Z:24,9V
;.. 9 i*Vertex7: Xi-0.4 Y:19.S Zi343\r'

Рис. 10.13. Первые 10 элементов массива shape

Разбор строк в ASC-файле


В общем случае требуется сохранить не строку, а содержащиеся в ней данные.
Учитывая, что ASC-файл описывает трехмерную фигуру, мы хотим извлечь ин-
формацию о координатах вершин.
Типичная строка с описанием трехмерной точки выглядит примерно так:
Vertex 98: Х:-27.5 Y:19.О Z:38.5
Можно сделать следующие предположения:
• все строки, содержащие информацию о вершинах, имеют длину не менее 30 сим-
волов и начинаются с префикса «Vertex»;
• внутри строки значению координаты х предшествует подстрока X: (то же для
координат у и z).
Остается реализовать эти правила на программном уровне. Чтобы узнать, содер-
жит ли текущая строка информацию о вершине, мы проверим, начинается ли она
с буквы «V»:
i f (elem.substrings, 1) == "V") {
Если условие выполняется, в оставшейся части строки ищутся смещения под-
строк X:, Y: и Z:
posX = elem.indexOfC'X:". 0);
posY = elem.indexOf("Y:". posX):
posZ = elem.indexOfC'Z:". posY);
Импортирование ASC-файлов как формата XML 383

Вообще говоря, в нашем примере эти смещения одинаковы для всех строк, начи-
нающихся со слова «Vertex», но выполнение этого условия не гарантировано,
поэтому мы ищем начальные позиции данных и не пользуемся никакими предпо-
ложениями.
По найденным смещениям из строки извлекаются координаты х, у и z. Начальное
смещение увеличивается на 2, чтобы в подстроку не вошел префикс из буквы
и двоеточия:
рХ = Number(elem.slice(posX + 2. posX + 6 ) ) :
pY = Number(elem.slice(posY + 2, posY + 6));
pZ = Number(elem.slice(posZ + 2, posZ + 6));
Наконец, точка (х, у, z) создается в виде структурированного объекта Flash. По-
зднее объект может использоваться в ActionScript для построения трехмерной
фигуры (см. трюк 37). В данном случае координаты точки добавляются в виде
свойств элемента массива shape (рис. 10.14):
shape[sPointer] = new ObjectO:
shapeCsPoi nter].x = pX;
shape[sPointer].y = pY;
shape[sPointer].z = pZ;

Рис. 10.14. Координаты трехмерных точек в свойствах элементов массива shape

Далее приводится полный код извлечения координат точек из ASC-файла, со-


зданного в 3D Studio Max:
handleIncoming = function (success) {
if (success) {
readXMLstartO;

}
readXMLstart = function О {
my3dFile = xObj.firstChild.nodeValue;
readASC();
}:
readASC = functionO {
var olndex:Number = 0;
var rlndex:Number = 0;
var elem:String = "":
var posX:Number = 0;
var posY:Number = 0:
var posZ:Number = 0;
while (rlndex != -1) {
384 Глава 10. ActionScript

rlndex = my3dFile.indexOf("\n". olndex):


elem = my3dFile.substring(oIndex. rlndex):
i f (elem.length > 30) {
i f (elem.substring^. 1) == "V") {
posX = elem.indexOfCX:". 0):
posY = elem.indexOfC'Y:". posX);
posZ = elem.indexOfC'Z:". posY);
pX = Number(elem.slice(posX + 2. posX + 6))
pY = Number(elem.slice(posY + 2. posY + 6))
pZ = Number(elem.slice(posZ + 2. posZ + 6))
shape[sPointer] = new ObjectO;
shape[sPointer].x = pX;
shape[sPointer].y = pY:
shape[sPointer].z = pZ;

}
olndex = rlndex + 1;
}
}
var xObj:XML = new XMLO:
var my3dFile:String = new StringO;
var shape:Array = new ArrayO;
var sPointer:Number = 0;
xObj.onLoad = handlelncoming;
xObj.load("torus.asc"):
Читатель может ознакомиться с полной версией этого приложения, написанной Эд-
вином Хейджменом, в разделе «Experiments» сайта http://www.poeticterror.com. Пол-
ная версия строит по точкам интерактивное трехмерное изображение (рис. 10.15).

Рис. 10.15. Описание трехмерной фигуры, импортированное из ASC-файла в Flash

Итоги
По мере того как Flash завоевывает все большую популярность как универсаль-
ная мультимедийная веб-платформа, все чаще возникает задача импортирования
данных в SWF из других приложений, в том числе и не связанных с Веб. Даже
Импортирование ASC-файлов как формата XML 385

если данные не соответствуют формату XML, для их загрузки можно воспользо-


ваться классом XML (Flash не следит за тем, чтобы файл, интерпретируемый как
XML-код, действительно был структурирован в этом формате). Этот прием хоро-
шо подходит для импортирования структурированных текстовых файлов в фор-
мате, не поддерживаемом Flash, потому что в распоряжении программиста ока-
зываются многие функциональные средства класса XML, в том числе и выдача
события onLoad после завершения загрузки.
Низкоуровневый формат ASC особенно упрощает импортирование в SWF дан-
ных, не предназначавшихся для Flash (таких, как описания трехмерных фигур
или наборы записей баз данных). Это также дает некоторые преимущества по
сравнению с преобразованием данных в формат, напрямую поддерживаемый Flash
(например, XML).
Не старайтесь всегда преобразовывать все данные в XML. Лишние преобразования
только усложнят вашу работу при обновлении данных исходным приложением.
Эдвин Хейджмен
ГЛАВА 11

Интеграция с браузером
Трюки № 86-96
С первых дней своего существования технология Flash был тесно связана с веб-
браузерами. Правда, Flash позволяет создавать специальные приложения, исполь-
зующие Standalone Player для воспроизведения SWF-файлов, и все же большая
часть Flash-контента просматривается через веб-браузеры благодаря вездесуще-
му модулю Flash Player (в Internet Explorer для Windows он реализован в форме
элемента ActiveX).
Как ни странно, отношение многих пользователей к Flash (как хорошее, так
и плохое) часто строится на неправильных представлениях. Многие веб-разра-
ботчики и пользователи толком не понимают, как Flash работает с браузерами.
В этой главе показано, как Flash интегрируется со стандартными средствами
браузера (например, кнопкой возврата - см. трюк 94) или поисковыми система-
ми вроде Google.
Кроме того, здесь рассматривается оригинальный способ проверки браузерного
модуля Flash Player (см. трюк 87). Если Flash Player установлен, он периодически
проверяет наличие обновлений на сайте macromedia.com. Как говорится в доку-
ментации Macromedia Flex «Managing Flash Player Auto-Update» (http://livedocs.
macromedia.com/flex/1/flex_docs/wwhelp/hhwimpl/common/html/wwhelp.htm?context =
=Flex_Documentation&file=38_dept42.htm#wp154069), конфигурация автоматиче-
ского обновления задается в файле mms.cfg в домашнем каталоге пользователя
или посредством настройки параметров, о которых пойдет речь далее.
Безопасность и конфиденциальность сыграли важную роль в принятии Flash
как платформы распространения контента. Большинство разработчиков знают
о контекстном меню Flash, вызываемом щелчком правой кнопки мыши (Windows)
или щелчком с кнопкой 8£ (Мае). Важнейшая команда этого меню, Settings, от-
крывает диалоговое окно параметров Macromedia Flash Player. На вкладках это-
го окна настраиваются параметры конфиденциальности, локального хранилища,
микрофона и камеры. Но лишь немногие разработчики (и еще меньше пользова-
телей) знают о существовании дополнительных параметров Flash Player, настра-
иваемых только через веб-сайт Macromedia. Пользователи могут вызвать Settings
Manager (http://www.macromedia.com/support/documentation/en/flashplayer/help/
settings_manager.html) кнопкой Advanced на вкладке Privacy. На сайте Macromedia
Интеграция с браузером 387

пользователь может настроить дополнительные параметры конфиденциальнос-


ти, хранения данных, безопасности и оповещений об обновлениях.
За последние годы с выходом новых версий браузеров для основных операцион-
ных систем стандарты браузеров и их взаимная совместимость часто изменя-
лись. Тем не менее, юридические факторы часто возобладают над технологичес-
кими. Компания EOLAS (Embedded Objects Linked Across Systems) обладает
рядом патентов на воспроизведение содержания в браузере. Возможно, вы слы-
шали о судебном иске, в результате которого Microsoft было запрещено автома-
тически запускать свою реализацию Flash Player в виде элемента ActiveX из
Internet Explorer. На момент написания книги Microsoft выиграла фазу предва-
рительных переговоров по объявлению патента недействительным, но судебный
процесс еще идет. Последние новости по этому поводу от EOLAS можно найти
по адресу http://www.eolas.com/news.htmt. Поиск по ключевому слову «EOLAS»
на сайте http://www.microsoft.com даст новую информацию о недавних слушани-
ях по поводу Internet Explorer от Microsoft. Последствия этой тяжбы для про-
граммистов Flash и других мультимедийных платформ обсуждаются по адресу
http://www.macromedia.com/devnet/activecontent.
Пока неизвестно, останется ли победа за Microsoft - вероятно, так оно и про-
изойдет. Но даже если выиграет EOLAS, мы разработали возможное обходное
решение (хотя здесь оно и не реализовано). Темой патентной заявки являются
модули, плотно интегрированные с браузером. Когда на странице обнаружива-
ются теги <object> и <embed>, требующие загрузки внешнего содержания (на-
пример, SWF), процесс загрузки Flash Player в основном прозрачен для пользо-
вателя и разработчика. Если патент EOLAS будет подтвержден, a Microsoft не
купит лицензию на него, Microsoft будет запрещено напрямую загружать мо-
дуль Flash Player в Internet Explorer. Возможное решение - загрузка внешнего
содержания с использованием немодульных технологий (например, JavaScript).
Впрочем, ради удобства и здравого смысла будем надеяться, что до этого все же
не дойдет.
Конечно, область применения Flash Player не ограничивается веб-браузерами.
Существуют версии Flash Player для PocketPC, для сотовых телефонов, а также
специализированные версии для ряда других устройств (см. http://www.macrome-
dia, com/devnet/devices). Учтите, что версия Flash Player, поддерживаемая боль-
шинством мобильных или автономных устройств, отстает от последней версии
Flash Player для веб-браузеров настольных систем. Большинство версий Flash
Player для других устройств поддерживает функциональность Flash 4, 5 или 6,
тогда как последней версией Flash Player для Macintosh и Windows является
Flash Player 7. .
Исходные тексты среды разработки Flash закрыты, но формат SWF является
открытым. Независимые разработчики могут получить бесплатную лицензию
на файловый формат Flash SWF (за дополнительной информацией обращайтесь
по адресам http://www.openswf.org и http://www.macromedia.com/software/flash/
open/licensing). Неудивительно, что многие программы сторонних разработчи-
ков воспроизводят SWF-файлы в нестандартных условиях или позволяют гене-
рировать SWF без применения среды разработки Flash (см. трюк 29).
388 Глава 11. Интеграция с браузером

ТРЮК Решение проблем совместимости


№86 Стандартный процесс построения Flash-сайта не обеспечивает макси-
мального уровня совместимости. Проблема решается внесением неболь-
ших изменений в HTML.
По данным W3Schools (http://www.w3schools.com/browsers/browsers_stats.asp),
более 80% пользователей Веб использует Internet Explorer (версии 5 и выше).
В то же время, проведенный Macromedia опрос показал, что у более 93 % поль-
зователей установлен Flash Player 6 или более поздней версии (http://www.macro-
media. com/software/player_census/flashplayer/version_penetration.html). Но несмот-
ря на это мы должны как можно корректнее обходиться с пользователями,
работающими в разных конфигурациях. Пользователи с претензиями гораздо
заметнее пользователей без претензий. А это значит, что ничтожное меньшин-
ство посетителей сайта (скажем, 5%), которым без всякой причины было отказа-
но в доступе, могут выдавать 100% отзывов о работе сайте (причем все отзывы
будут негативными). В реальной жизни один недовольный клиент редко ком-
пенсируется одним довольным клиентом, а уровень недовольства выше двух-
трех процентов отпугивает многих заказчиков.
Следите за текущей статистикой пользователей Веб. Например, W3Schools (http:/
/www.w3schools.com/browsers/browsers_stats.asp) публикует ежемесячную стати-
стику по использованию браузеров, а thecounter.com (http://www.thecounter.com/
stats) собирает аналогичную статистику по огромному количеству своих ежед-
невных посетителей (чтобы получить распределение по типам браузеров, щелк-
ните на названии месяца, а затем - на ссылке Browsers в правой части веб-
страницы).
Помните, что статистика не дает должного представления о количестве жалоб от
пользователей, не сумевших попасть на ваш сайт.

Проверка поддержки Flash


Наилучшие впечатления от использования сайта достигаются в том случае, если
сайт распознает ресурсы, доступные на компьютере пользователя, и выводит
контент, адаптированный для этой системы (или сообщает пользователю, что
необходимо для полноценного просмотра). Едва ли не каждый разработчик, за-
нимавшийся этой задачей, разработал собственный метод для проверки поддержки
Flash. Вот лишь некоторые наиболее популярные средства:
• Fpi (Flash Plugin Inspector) Колина Мука - http://moock.org/webdesign/flash/
detection/moockfpi;
• Web Monkey, «Detecting Plugins» - http://hotwired.lycos.com/webmonkey/99/
40/index3a.html?tw=programming;
• O'Reilly WebDev Center - http://www.oreillynet.eom/pub/a/javascript/2001/07/
20/plugin_detection.html.
В трюке 87 описан бесплатный анализатор модуля Flash, реализованный на
JavaScript.
Решение проблем совместимости 389

Тестирование в различных браузерах


Вопреки некоторым сообщениям, в одной системе можно установить несколько
разных браузеров и даже запускать их одновременно. Например, на моем ком-
пьютере установлены Internet Explorer, Netscape Navigator, Opera и Mozilla
(рис. 11.1).

mozilla

Рис. 1 1 . 1 . Система Windows XP с несколькими одновременно работающими


браузерами (слева направо): Internet Explorer, Netscape Navigator,
Opera (бесплатная версия) и Mozilla

Проблема, чаще всего возникающая при установке нескольких браузеров на один


компьютер, связана с борьбой за звание браузера по умолчанию. Выберите пользо-
вательский вариант установки, отключите режим использования браузера по
умолчанию - и все должно быть нормально.
Также присмотритесь к дополнительным компонентам, которые часто пытаются
устанавливать новые браузеры. Обычно при установке рекомендуется отклю-
чать все компоненты, кроме базового браузера, если только вы не хотите заодно
сменить почтовый клиент, интернет-пейджер и проигрыватель МРЗ. Netscape
Navigator особенно усердствует в этом отношении, поэтому при его установке
всегда отдавайте предпочтение выборочному варианту установки. Также остере-
гайтесь автоматизированных обновлений Internet Explorer, которые могут, ска-
жем, заодно обновить Windows Media Player.
Наличие нескольких браузеров является обязательным требованием для всех
веб-дизайнеров, но оно особенно важно для Flash-сайтов, потому что вы должны
проверить, что случится при отсутствии правильной) модуля. Лично я всегда
слежу за тем, чтобы по крайней мере в одном браузере из тестового набора мо-
дуль Flash Player отсутствовал, а в большинстве браузеров была установлена
самая распространенная версия Flash Player, которая не всегда совпадает с пос-
ледней. По этой причине на моих компьютерах чаще устанавливается Flash
Player 6, потому что на момент написания книги (июнь 2004 года) Flash Player
еще не получил повсеместного распространения.
Бесплатное приложение Flash Plugin Switcher позволяет легко и быстро сменить
версию модуля Flash Player в некоторых браузерах (см. трюк 88). В Интернете
390 Глава 11. Интеграция с браузером

также можно найти старые версии модулей Flash, позволяющие легко переклю-
читься на нужную версию Flash Player для Windows/Mac.
Версии Flash Player существуют и для других операционных систем, включая
Linux и OS/2. Их можно найти на странице http://www.macromedia.com/shockwave/
download/alternates.
Также стоит упомянуть и о таком полезном «браузере», как Any Browser. Эта
утилита эмулирует предельно упрощенный, минимальный браузер (HTML 3.2
с поддержкой таблиц, но без поддержки Flash и JavaScript). Хотя AnyBrowser не
позволяет отображать содержание Flash, это хороший инструмент для тестиро-
вания худшего случая (отсутствие поддержки Flash). Если веб-страница способ-
на сообщить пользователю о возникших проблемах и подсказать действия, кото-
рые нужно выполнить в браузере, вы идете по правильному пути!
Если вас заинтересует AnyBrowser, щелкните на ссылке Site Viewer на сайте http:/
/www.anybrowser.com и найдите ссылку.

Проверка совместимости с поисковыми системами


На сайте AnyBrowser также размещена полезная утилита, при помощи которой
можно узнать, как ваш сайт будет восприниматься автоматическими сборщика-
ми информации поисковых систем. Откройте главную страницу AnyBrowser
и щелкните на ссылке Engine View.
Простейший способ включения текста, читаемого поисковыми системами, - раз-
мещение его в поле комментария <! > тега <body> HTML-страницы. Обычно
комментарий заполняется начальным абзацем текста, описывающим содержи-
мое сайта, за которым следует список ключевых слов. Не ставьте ключевые сло-
ва на первое место, иначе на большинстве страниц с результатами поиска они
будут отображаться как описание сайта!
При использовании любого шаблона HTML, входящего в поставку Flash (вклю-
чая шаблон Flash Only), закомментированный текст автоматически включается
в HTML-страницу. К сожалению, экспортер HTML не столь умен. Он не разли-
чает текст пользовательского интерфейса и контента и поэтому обычно экспор-
тирует всякую ерунду, не подходящую для поисковых систем или создания клю-
чевых слов. В таких случаях проще всего вручную отредактировать HTML-файл,
сгенерированный Flash, и включить в него правильное описание с ключевыми
словами.

Контекстное меню Flash


Меня часто спрашивают: «Как избавиться от контекстного меню Flash при про-
смотре Flash-сайта в браузере? Я хочу использовать правую кнопку мыши для
других целей, и вообще контекстное меню выглядит непрофессионально». Кон-
текстное меню Flash, вызываемое щелчком правой кнопки мыши (Windows) или
щелчком с нажатой клавишей §€ (Мае), не может быть полностью отключено
обычным способом. Даже если присвоить переменной Stage.showMenu значение
false, даже если выполнить команду File • Publish Settings • HTML и сбросить фла-
Универсальный анализатор поддержки Flash • 391

жок Display Menu, все равно, будет отображаться контекстное меню с командами
Settings и About Macromedia Flash. В прошлом предлагалось немало способов по-
давления контекстного меню, в основном непрактичных. Например, в одном из
вариантов сцена накрывалась выделяемым текстовым полем - но тогда вместо
контекстного меню Flash отображалось контекстное меню редактирования тек-
ста, что выглядело весьма странно (к тому же пользователь не мог щелкнуть на
другом объекте сцены!)
Вопрос об отключении контекстного меню довольно часто встречается на форумах,
поэтому я не могу обойти его стороной. Контекстное меню можно полностью от-
ключить за счет умного применения HTML и JavaScript, как описано на сайте Грега
Вигоника (Gregg Wygonik) по адресу http://www.broadcast.artificialcolors.com/stories/
2003/09/21/disableFlashMovieRightClickMenu.html. Существует еще более удобный
вариант - загрузите написанный Грегом компонент gwContextKiller (http://
www.artificialcolors.com/experiments/gwContextKillerlnfo.html), отключающий вызов кон-
текстного меню в браузерах IE 6+ и Mozilla 1.3+ (также работает в IE 5, но не в IE
5.5). Просто перетащите компонент на сцену Flash, обычно - за пределы экрана,
а затем задайте параметру Window mode на вкладке File • Publish Settings • HTML зна-
чение Windowless Opaque. Но учтите, что в этом случае Flash-ролики превратятся в
черные квадраты для пользователей, запретивших плавающие рекламные окна Flash
(http://www.jessewarden.com/archives/000507.html) или отключивших автоматическое
обновление (http://livedocs.macromedia.eom/flex/1 /flex_docs/wwhelp/wwhimpl/comrnon/
html/wwhelp/htm?context=Flex_Documentation&file=38)dep42.htm#wp154069).

Итоги
Существует несколько путей улучшения совместимости Flash-сайтов с браузе-
рами. Как правило, следующие меры позволяют заметно сократить процент
пользователей, для которых ваш сайт остается недоступным:
• тестирование в разных браузерах;
• ручная правка HTML-кода, благодаря которой информация о сайте будет
отображаться в поисковых системах с осмысленными описаниями и ключе-
выми словами;
• проверка наличия модуля Flash у конечного пользователя и разумное пове-
дение сайта в зависимости от ее результатов.

ТРЮК Универсальный анализатор поддержки


№87 Flash
Анализатор поддержки Flash без применения JavaScript, который не при-
дется обновлять каждый раз, когда Macromedia выпустит новую версию
Flash Player
Анализатором поддержки Flash называется некий код, который проверяет, мо-
жет ли Flash-контент текущей страницы просматриваться в браузере. Для этого
анализатор ищет конкретную установку Flash Player. Проблема заключается в том,
392 Глава 11. Интеграция с браузером

что правильная работа анализатора может потребовать выполнения ряда пред-


варительных условий. Контент, который раньше прекрасно работал, может стать
недоступным в результате сбоя самого анализатора! В этом трюке показано, как
построить анализатор с минимальным количеством предварительных условий
(наиболее универсальный и нетребовательный).
Традиционные анализаторы обычно приходилось обновлять после выхода каж-
дой новой версии Flash Player. Что еще хуже, традиционные анализаторы писа-
лись на JavaScript и существенно зависели от специфики браузера. Как однажды
выразился Раэл Дорнфест (Rael Dornfest), «сначала мы подумывали написать
книгу о трюках JavaScript, но JavaScript состоит из сплошных трюков». Я уже не
могу без смеха смотреть ни на одно руководство по JavaScript.
Но из-за этого анализатор поддержки Flash на базе JavaScript обладает рядом
принципиальных недостатков:
• различия в поддержке JavaScript, а также способах проверки наличия задан-
ного модуля. Например, способ идентификации элемента ActiveX в Internet
Explorer для системы Windows отличается от способа идентификации под-
ключаемого модуля в Netscape и других браузерах, не поддерживающих
ActiveX;
• различия в модулях Flash. Может оказаться, что анализатор не распознает
более новые версии модуля Flash или версии для других платформ, даже
если SWF-файлы в них нормально воспроизводятся;
• пользователь может отключить поддержку JavaScript в своем браузере (впол-
не рядовое явление в коммерческих организациях, поскольку это снижает
вероятность заражения вирусом или внедрения троянских программ). В этом
случае анализатор просто перестает работать!
Итак, было бы неплохо иметь анализатор поддержки Flash, не зависящий от
JavaScript.

Пять, четыре, три, два, один...


Заголовочный тег HTML <meta> позволяет передавать информацию браузеру
или специализированным браузерным модулям (например, ридерам для пользо-
вателей с дефектами зрения). Кроме того, он используется для передачи инфор-
мации поисковым системам при индексировании. В нашем трюке будет исполь-
зоваться особая возможность тега <meta> - отложенная загрузка.
Синтаксис тега <meta> с отложенной загрузкой выглядит так:
<meta http-equiv="refresh" content="/7: URL=newdoc.html">
В сущности, это простой запрос к браузеру на загрузку нового HTML-доку-
мента, в данном примере newdoc.html (в теге также может быть указан полный
путь к новому документу - например, http://www.myDomain.com/rriycloc.html),
Универсальный анализатор поддержки Flash 393

после задержки п секунд. Выполнение тега приводит практически к тем же


последствиям, что и щелчок на гиперссылке newdoc.html с «-секундной задерж-
кой. В нашем трюке браузер попытается загрузить документ noflash.html с за-
держкой 5 с.
В исходный HTML-файл будет внедрен документ SWF, использующий функ-
цию getURL() для загрузки HTML-страницы flash.html с фактическим Flash-кон-
тентом. На рис. 11.2 показана общая схема процесса.

Отложенная загрузка 5 секунд noflash.html

Flash getURL() flash.html

Рис. 11.2. Принцип работы анализатора поддержки Flash

Сначала мы пытаемся выполнить Flash SWF с функцией getURLQ, которая за-


гружает контент Flash в веб-странице flash.html. Если попытка окажется успеш-
ной, можно сделать вывод, что Flash Player установлен и нормально работает.
Если же файл не выполнится, мы знаем, что поддержка Flash отсутствует в бра-
узере. Но беспокоиться не о чем - если Flash не изменит текущую веб-страницу
(то есть не загрузит flash.html методом getURL())( через пять секунд сработает
отложенная загрузка, вследствие чего будет загружена HTML-страница noflash.html.
Самое лучшее в данном решении - его полная независимость от JavaScript,
браузера, платформы ОС или пользовательских настроек.
Далее приводится более подробное описание:
1. Создайте новый документ Flash и включите следующий сценарий в кадр 1 глав-
ной временной диаграммы:
getURLCflash.html". "_self"):
2. Сохраните файл под именем index.fla.
3. Опубликуйте документ командой File • Publish Preview • Default (HTML).; Ко-
манда создает файлы index.html и index.swf в той же папке, в которой хранил-
ся файл index.fla.
4. Откройте файл index.html в текстовом редакторе по вашему выбору.
5. Секция <head> должна выглядеть так:
<head>
<meta http-equiv=Content-Type content="text/html"; charset=ISO-8859-l">
394 Глава 11. Интеграция с браузером

< t i t l e>index</ti tle>


</head>
6. Добавьте новый тег <meta>, выделенный далее жирным шрифтом:
<head>
<meta http-equiv=Content-Type content="text/html": charset=ISO-8859-l">
<meta http-equiv="refresh" content="5; URL=noflash.html">
<ti t l e>i ndex</ti tle>
</head>
Создайте файл noflash.html. В нем может находиться:
• версия сайта, использующая только HTML;
• HTML-страница, рекомендующая пользователю установить последнюю вер-
сию модуля Flash;
• страница с предложением щелкнуть на кнопке для перехода на сайт загрузки
модулей Macromedia Flash (http://www.macromedia.com/shockwave/download/
download. bgi?P1_Prod_Version=ShockWaveFlash).
В любом случае страница должна объяснять, что поддержка Flash не обнаруже-
на. Кроме того, на ней должна размещаться ссылка для загрузки Flash-версии
сайта на случай, если модуль все же установлен. Ничто так не раздражает пользо-
вателя, как сообщения об отсутствии поддержки Flash только из-за того, что
процедура автоматического обнаружения сработала неправильно. Не стоит бес-
церемонно отправлять пользователя на сайт Macromedia для загрузки модуля
Flash - предоставьте пользователю самостоятельно выбрать курс дальнейших
действий.
Поместите файлы flash.html и someFlashMovie.swf (Flash-сайт) в одну папку с фай-
лом index.html. Чтобы провести локальное тестирование анализатора, откройте
index.html в браузере. Если с тестированием возникнут проблемы, обращайтесь
к файлам на сайте книги.
Когда схема успешно заработает, загрузите файлы на веб-сервер и введите в бра-
узере URL загруженной HTML-страницы - например, http://www.yourdomain.com/
sniffertest/index.html.
Чтобы эмулировать простейший браузер без каких-либо модулей, посетите сайт
http://www.anybrowser.com с эмулятором браузера, совместимого с HTML 3.2, -
идеальное место для тестирования анализатора поддержки Flash.

Возможные проблемы
Иногда оказывается, что ранние версии Flash Player распознают функцию getURL(),
поддерживаемую с Flash Player 2, но не воспроизводят весь контент Flash-сайта.
Допустим, вы хотите использовать видео, поддерживаемое Flash Player версий 6
и выше, а у пользователя установлен Flash Player 5. Flash Player 5 поддерживает
метод getURLQ, но не воспроизводит видео, внедренное в SWF-файл. В подоб-
ных случаях приходится проверять минимальную версию модуля Flash Player.
Flash-ролик для проверки версии Flash Player должен быть SWF-файлом Flash
Player 4 или Flash Player 5. Он проверяет версию Flash Player, а затем загружает
Универсальный анализатор поддержки Flash 395

другой SWF-файл (вероятно, в формате Flash Player 6 или Flash Player 7)


с настоящим контентом.
Для проверки версии Flash Player используется переменная окружения Flash
$version. Эта переменная присутствует на вкладке Variables панели Debugger
(рис. 11.3) при тестировании ролика в отладочном режиме.

Ш _global

Nsme [Value
^version

Рис. 11.3. Вкладка Variables панели Debugger с информацией о версии Flash

Свойство $version поддерживается в Flash Player версии 4.0.11.0 и выше. Оно


возвращает строку в форме «платформа номер_версии», где платформа -
WIN, MAC или UNIX, а номер версии состоит из четырех чисел, разделенных
запятыми, - основной и дополнительной версий, номера сборки и исправле-
ния (например, "WIN 6,0,21,0"). Не используйте более современные средства
получения номера версии - такие, как функция getVersion(), поддерживаемая
в Flash 5 и выше, или свойство System.capabilities.version (поддерживается в Flash б
и выше), если у вас нет полной уверенности в том, что пользователь использует
более новую версию модуля. Впрочем, если у пользователя установлена хоть
какая-то версия Flash Player, скорее всего, это минимум версия 5, а по статисти-
ке (http://wvwv.macromedia.com/software/player_census/flashplayer/version_penetra-
tion.html) свыше 90 % пользователей использует Flash Player 6 и более поздние
версии.
Так или иначе, $version, getVersionQ и System.capabilities.version возвращают одну
и ту же строку (если, конечно, они поддерживаются в данной платформе).
Основной нрмер версии для Мае и Windows хранится в строке $version со сме-
щением 4 (пятый символ). Мы воспользуемся методом String.substr(), чтобы про-
верить, установлен ли у пользователя Flash Player версии 5 и выше. Если усло-
вие выполняется, текущая страница заменяется страницей flash.html. В противном
случае выводится странице с сообщением об ошибке и предложением обновить
Flash Player до версии 5 и выше:
i f (Sversion.substr(4.1) >= 5) {
getURU "flash.html", "_self");
} else {
getURK "ol d_fl ash. html". "_sel f " ) :
396 Глава 11. Интеграция с браузером

В Flash Player версий 1, 2 и 3 произойдет сбой, и сценарий просто продолжит


воспроизведение SWF, но эти версии давно устарели и представляют менее 1%
пользовательской базы. Самая замечательная особенность этого трюка состоит
в том, что схему обнаружения не придется модифицировать для пользователей
Flash Player 6, Flash Player 7 или будущих версий. Если вы хотите поддерживать
платформы, для которых в строку версии включается префикс UNIX, извлеките
основной номер версии после первого пробела в строке (не предполагая, что он
является пятым символом).

Итоги
Трюк, представленный в настоящем разделе, проверяет отсутствие Flash Player -
это проще, чем активное определение наличия Flash Player. Если Flash Player
присутствует в системе, мы проверяем его версию (если потребуется). Вместо
проверки Flash Player из JavaScript мы просто предлагаем Flash Player иденти-
фицировать себя.
Наш анализатор не зависит ни от поддержки JavaScript, ни от версии модуля
Flash Player. Минимальным требованием является поддержка тега <meta>,
обеспечиваемая браузерами версий 3.x и выше. Как максимум, требуется модуль
Flash Player, способный опознать команду if и свойство $version (а именно Flash
Player 4 и выше).
Конечно, рассмотренное решение представляет собой трюк (если на то пошло,
вся книга посвящена трюкам) и не обеспечивает абсолютной надежности. В за-
висимости от конфигурации пользователям Internet Explorer без Flash Player
может быть предложено установить соответствующий элемент ActiveX. В то же
время, в зависимости от временных характеристик (от того, сколько времени
уйдет на вывод сообщения и ответные действия) пользователь может не попасть
на страницу без Flash.
Сценарии обнаружения модулей не бывают идеальными - у любого из них най-
дутся свои недостатки. Рассматривайте этот прием как лишнюю стрелу в своем
колчане, а не как серебряную пулю. За информацией о более традиционных
методах идентификации поддержки Flash обращайтесь к ресурсам, перечислен-
ным во введении к настоящей главе.

Тестирование с разными версиями


ТРЮК

№88 Flash
Тестирование приложений с разными версиями Flash Player без перехо-
да на другой компьютер или ручной установки/удаления других версий.
Многие клиенты требуют, чтобы их сайт оставался совместимым с предыдущей
версией Flash Player (на момент написания книги - Flash Player 6) до тех пор,
пока текущая версия (Flash Player 7) не достигнет пользовательской базы при-
мерно в 90%. Столь широкое распространение обычно достигается через 18 ме-
сяцев после выхода новой версии.
Тестирование с разными версиями Flash 397

Среда разработки Flash позволяет создавать контент, рассчитанный на предыду-


щие версии Flash Player, однако в ней не предусмотрены средства тестирования
SWF в предыдущих версиях - по умолчанию предполагается, что контент будет
просматриваться в последней версии Player (сейчас это Flash 7). К счастью,
Macromedia следит за тем, чтобы старые SWF-файлы воспроизводились новыми
версиями Flash Player так же хорошо, как в предыдущих версиях Flash Player.
Хороший дизайнер тестирует свой продукт в новейшей версии Flash Player. Тем
не менее, сайт также стоит протестировать в предыдущих версиях Flash Player,
но такое тестирование создает немало проблем.
Поскольку в любом браузере в любой момент времени может быть установлена
лишь одна версия Flash Player, возможны четыре варианта:
• установите нужную версию Flash Player перед тестированием и восстановите
более новую версию после его завершения;
• проведите тестирование на нескольких компьютерах с разными версиями Flash
Player. Во многих крупных организациях создаются специальные тестовые
лаборатории, оснащенные множеством компьютеров с разными конфигура-
циями. Но если в вашей организации не хватает лишних компьютеров или
места для их размещения, такое решение становится неприемлемым;
• попросите друзей заняться тестированием. Идея отнюдь не плохая, но, ско-
рее всего, ваши друзья - Flash-разработчики с последней версией модуля
Flash, которым вряд ли захочется отягощать себя лишней работой;
• воспользуйтесь превосходной программой Flash Plugin Switcher (http://
www.kewbee.de/FlashPluginSwitcher) Алекса Блума (Alex Blum), которая изба-
вит вас от необходимости устанавливать или удалять модули Flash Player
или элементы ActiveX.
Чтобы не создавать себе лишних трудностей, в этом трюке будем использовать
Flash Plugin Switcher (FPS). Логотип этой программы изображен на рис. 11.4.
FPS заставляет браузер вернуться к предыдущей версии Flash Player. К сожале-
нию, приложение работает только в системе Windows, поэтому на платформе
Macintosh вам придется прибегнуть к другим способам.

FlashPfuginSwltcher
Рис. 11.4. Логотип Flash Plugin Switcher

На сайте Алекса используется немецкий язык, но само приложение и его спра-


вочные файлы написаны на английском.
Macromedia поддерживает на своем сайте архив старых версий Flash Player
(вплоть до Flash Player 2), предназначенный для тестирования:
http://www.macromedia.com/support/flash/ts/documents/oldplayers.htm
398 Глава 11. Интеграция с браузером

По этому адресу размещена статья 14266 «Archived Macromedia Flash Players


available for testing purposes». Если Macromedia вдруг изменит URL, просто вве-
дите номер 14266 в поисковом поле на домашней странице Macromedia.

Flash Plugin Switcher

Распакуйте архив Flash Plugin Switcher и запустите приложение. Кнопка Help


выводит информацию об установке модулей и элементов ActiveX. В окне прило-
жения (рис. 11.5) выполняются следующие действия:
1) смена браузерного модуля или элемента ActiveX (поддерживаются Netscape
и Internet Explorer);
2) смена версии Standalone Flash Player;
3) смена модуля, используемого режимом Test Movie в IDE для всех версий сре-
ды разработки Flash.

Рис. 11.5. Настройка конфигурации Flash Plugin Switcher

Общая процедура смены модуля или элемента ActiveX выглядит так:


1) убедитесь в том, что браузер, Standalone Player или среда разработки (IDE)
Flash, для которых вы хотите сменить модуль или элемент ActiveX, закрыт;
2) перейдите на соответствующую вкладку FPS (Browser, Standalone или Flash
IDE);
3) удалите существующий экземпляр Flash Player, если соответствующая воз-
можность присутствует на вкладке;
4) выделите и установите новый Flash Player. Просто, как все гениальное;
Настройка конфигурации по умолчанию 399

5) чтобы протестировать ситуацию с отсутствием модуля Flash Player, удалите


текущий модуль или элемент ActiveX на вкладке Browser (см. шаг 3), но не
устанавливайте другую версию.

Итоги
Помните, что программа Flash Plugin Switcher существует на пожертвования
пользователей. Если вы будете работать с ней, не забудьте поблагодарить Алекса
через систему PayPal.

ТРЮК Настройка конфигурации по умолчанию


№89 Изменение настроек Flash IDE по умолчанию в соответствии с текущей
конфигурацией оборудования и/или особенностями рабочего процесса.
Некоторые параметры Flash по умолчанию не изменялись с первых дней суще-
ствования пакета, хотя современное оборудование обычно обладает достаточ-
ным объемом памяти и/или производительностью, чтобы эти параметры можно
было увеличить. Кроме того, многие пользователи не знают о важных флажках
и запросчиках, спрятанных в интерфейсе Flash.

Изменение параметров по умолчанию


Выполните команду Edit • Preferences и введите новые параметры по умолчанию
в диалоговом окне Preferences.
Рассмотрим важнейшие параметры, находящиеся на разных вкладках:
• General. Для начала стоит обратить внимание на размер кэша отмены (рис. 11.6).
В Flash MX 2004 его размер равен 1000 уровням, тогда как в Flash MX кэш
ограничивается всего 100 уровнями. Если у вас свободная память (а у кого ее
нет в наше время?), увеличьте размер кэша до 100.
• Editing. Хотя обновление Flash MX 2003 (http://www.macromedia.com/support/
documentation/en/flash/mx2004/releasenotes.html#Update), выпущенное в нояб-
ре 2003 года и обновляющее среду разработки до версии 7.0.1, решает многие
проблемы исходной версии 7.0, у него есть свои недостатки. В частности, не-
которые поля группы Drawing Settings остаются пустыми (не содержат значе-
ния по умолчанию), что мешает нормальной работе режимов Smooth, Straighten
и Ink инструмента Pen. Если вы столкнетесь с этим явлением, задайте пустым
параметрам значение Normal. В конце лета 2004 года по приведенному ранее
URL должно появиться обновление до версии 7.2.
• Clipboard. Максимальный объем буфера составляет всего 250 Кбайт, чего явно
недостаточно для копирования растров из Photoshop и других графических
редакторов в Flash. Если вы часто редактируете растровые изображения
в Photoshop и импортируете их в Flash, увеличьте буфер до 5000 Кбайт (то есть
5 Мбайт). В этом случае вместо сохранения графики в Photoshop с после-
дующим импортированием командой File • Import вы можете выполнить
400 Глава 11. Интеграция с браузером

операции копирования/вставки клавишами Ctrl+C и Ctr!+V (Windows) или


SHJ+C и S€+V (Mac). При занесении вставленных растров в библиотеку Flash
присваивает им имена вида «Bitmap n».

Genera!
?>• General- - —• • - •>••- •
Undo levels: j W%k \
Printing options: f3 Disable PostScript
! Selection options: Щ Shift «feet
|3 Show tooltips
Panel options: £3 Disable panel docking
I TimeSne options: H Disable timeline docking
E ] Span based selection
If) Named anchor on Scene
Highlight color: Ф Use this color В
© Use layer color
I Font mapping default: jsans j§s

On launch: 0 show Start Page


j : . © New document
| © Last documents open

Cancel

Рис. 11.6. Вкладка General диалогового окна Preferences

• Warnings. На вкладке Warnings ничего менять не требуется. Все предупрежде-


ния лучше оставить включенными.
• ActionScript. В Flash MX 2004 и Flash MX Professional 2004 шрифт, использу-
емый для отображения ActionScript, выбирается в раскрывающемся списке
группы Text вкладки ActionScript. Ранние версии Flash такого выбора не дава-
ли - в них использовался стандартный шрифт Lucinda Console. Впрочем,
шрифт Lucinda Console идеально подходит для вывода программного кода
благодаря четкости и хорошим пропорциям, поэтому его стоит выбрать из
раскрывающегося списка шрифтов.

Изменение параметров публикации


В отличие от параметров окна Preferences, относящихся к среде разработки в це-
лом, параметры публикации задаются (и сохраняются) отдельно для каждого
Настройка конфигурации по умолчанию 401

редактируемого документа FLA. Команда File • Publish Settings вызывает диало-


говое окно Publishing Settings, в котором чаще всего используются вкладки HTML
и Flash:
• HTML. Среда разработки Flash генерирует HTML-страницу, в которую вне-
дряется SWF-файл. Вкладка HTML управляет параметрами создания этой стра-
ницы (Flash MX 2004 и Flash MX Professional 2004 генерируют код XHTML,
но файлу все равно присваивается расширение .html).
Параметры вкладки HTML позволяют создать немасштабируемый ролик SWF,
выровненный по центру окна браузера (см. трюк 90).
• Rash на этой вкладке выбирается версия компилятора ActionScript -ActionScript 1.0
или ActionScript 2.0. Компилятор ActionScript 2.0 обеспечивает жесткую типи-
зацию, учитывает регистр на стадии компиляции и поддерживает новый син-
таксис ООП (например, ключевое слово class). Также здесь можно выбрать
формат экспортирования SWF - Flash Player 6 или Flash Player 7 (рис. 11.7).

Version: [Flash Player 7


Load order: [Bottom up
ActionScrpt version: j~ArttonScrtpt 1-

Рис. 11.7. Выбор версии компилятора и формата экспортирования на вкладке Flash

Если в списке Version выбирается строка Flash Player 6, флажок Optimize for Flash
Player 6r65. Flash Player 6r65 имеет много общего с Flash Player 7, поэтому этот
выбор повышает совместимость до повсеместного распространения Flash Player 7.
Учтите, что Flash Player 6r65 поддерживает не все новые возможности Action-
Script, включенные в Flash Player 7 (см. главу 10). Дополнительная информация
о совместимости компонентов v2 с последними версиями Flash Player приведена
в блоге BIT-101 (http://www.bot-101.com/blog/archives/000047.html).

Другие панели и вкладки


Панель Output приносит пользу при отладке сценариев, но она всегда открывает-
ся с теми размерами и позицией, с которыми она в последний раз открывалась
в Flash. При первом входе в режим Test Movie после запуска среды разработки
Flash панель Output обычно закрывает сцену тестируемого SWF-ролика. Чтобы
этого не происходило, панель Output можно закрепить в правой части окна (только
в Windows). В дальнейшем, когда панель Output будет активизироваться вызова-
ми trace() в сценариях, она будет находиться справа от сцены, а не над ней.
В Flash для Mac OS закрепляемые панели не поддерживаются.
В интерфейсе Flash MX 2004 появились новые вкладки в верхней части окна среды
разработки (в стиле Dreamweaver). Эти вкладки не только позволяют легко пере-
ключаться между открытыми окнами, но и открывают доступ к весьма удобному
контекстному меню. Щелкните на вкладке правой кнопки мыши (Windows) или
щелкните с нажатой кнопкой <Н> (Мае) - на экране появляется контекстное меню
для открытия новых файлов или сохранения файла, связанного с вкладкой.
402 Глава 11. Интеграция с браузером

Выравнивание SWF по центру


ТРЮК

№90 без изменения масштаба


Выравнивание немасштабированного контента в окне браузера без при-
менения таблиц или CSS.
Всем известно, что векторная графика (в отличие от растровой) не теряет каче-
ства при масштабировании, но почти на всех коммерческих Flash-сайтах исполь-
зуются относительно небольшие, немасштабированные SWF-ролики, выровнен-
ные по центру браузера. Это объясняется следующими причинами:
• Быстродействие Flash зависит от количества пикселов, изменяющихся с каж-
дым кадром. Умеренные размеры области вывода SWF и отказ от масшта-
бирования обеспечивают быструю работу сайта с более или менее постоян-
ной частотой смены кадров. Ролики не рекомендуется масштабировать на
весь экран (особенно до размеров 1280 х 1024 и выше), потому что при
таких больших размерах области вывода Flash будет работать слишком
медленно.
• На многих коммерческих Flash-сайтах используются растровые изображе-
ния, которые плохо выглядят после масштабирования.
• Следует избегать масштабирования видео, поскольку это приводит к появле-
нию артефактов оптимизации и снижению быстродействия (иногда очень се-
рьезному), хотя применение кодека Sorenson в значительной мере решает эту
проблему.
• Уменьшение размера сцены уменьшает объем графических данных, а это,
в свою очередь, уменьшает нагрузку на канал связи.
Слушатель Stage.onResize() даже позволяет перехватывать события изменения
размеров и выполнять нестандартное масштабирование или позиционирование
отдельных элементов без применения единых правил масштабирования «на все
случаи жизни».
Начинающие пользователи Flash часто задают один и тот же вопрос: «Как по-
строить немасштабируемый SWF-ролик, который всегда выводится в центре окна
браузера?» Ни один из готовых шаблонов, вызываемых командой File • New •
Templates, не предоставляет такой возможности. Даже некоторые опытные пользо-
ватели применяют таблицы HTML или форматирование CSS. Тем не менее,
проблема решается гораздо проще. Выполните команду File • Publish Settings,
выберите в списках Horizontal и Vertical из группы Flash Alignment значение Center,
а в списке Scale - строку No scale (рис. 11.8).
К сожалению, в этом способе возможно отображение скрытого контента, нахо-
дящегося вне сцены. Проблема будет решена в следующем трюке, посвященном
форматированию CSS (см. трюк 91).
Выравнивание по центру с применением CSS 403

Current profiled Default


Foi mats Flash HTML \
Template: |Flash Only
0 Detect Flash Version
Dimensions: ;Percent
Width: Height;
X | 100 | percent
Playback: ED Paused at start Щ} Display menu
[3 Loop 0 Device font
Quality: H i g h i v j

Window Mode: W i n d o w v

HTML alignment: D e f a u l t ••;. . . . • " •

;
: ' • ' • . • •. . : .

Scale:
•: • : • • • . .

N o s c a l e
3 • • • : : - . ' :
|

:
• / ; . • • • • • • : : l

: : ; •torizontal V e r t i c a l
••:•:•••'•'• - -^: -::/Д^Г . • • • , . . : ; •: •

F l a s h a l i g n m e n t : C e n t e r v ! C e n t e r
. . i l l .

:••:•: [;.;• •;.' : : *•:;;?:


3 s h o w w a r n i ng m e s s a g e s

: | . P u b l i s h [ c a n c e l

1 1 O K

Рис, 11.8. Диалоговое окно Publish Settings

Выравнивание по центру
ТРЮК

№91 с применением CSS


Центрирование немасштабируемого SWF-ролика может привести к слу-
чайному отображению контента, находящегося вне сцены. Применение
XHTML и XSS дает отличный результат без отображения скрытого кон-
тента и нарушения стандартов.
Одна из самых распространенных проблем, с которыми сталкиваются неопытные
дизайнеры, - выравнивание SWF-ролика по центру окна браузера (см. трюк 90).
Далее описаны некоторые способы решения этой задачи и трюки, необходимые
для того, чтобы заставить их работать лучше.
404 Глава 11. Интеграция с браузером

Параметры публикации
Для примера возьмем SWF-ролик, показанный на рис. 11.9.

О : V ;. . ..•
_
• •

Рис. 11.9. Тестовая таблица

Тестовая таблица закрывает сцену, а четыре угловые фигуры (два круга с впи-
санными квадратами и два квадрата) находятся за пределами сцены. Светло-
серая рамка тоже не входит в сцену.
Если масштабировать сцену по размерам окна браузера (выполните команду
File • Publish Settings • HTML, выберите в списке Dimensions значение Percent), то
четыре внешние фигуры не будут видны.
Однако у такого решения есть серьезный недостаток. Если пользователь запус-
тит браузер в большом окне, то большой размер полученного SWF-файла суще-
ственно замедлит работу сайта. Если выбрать в списках Horizontal и Vertical стро-
ку Center, а в списке Scale - строку No Scale (см. рис. 11.8 из предыдущего
трюка), центровка будет выполнена так, как показано на рис. 11.10.
SWF-ролик выровнен по центру, но в окне также отображается контент, находя-
щийся за пределами сцены. Иногда это не создает проблем, но многие сайты
содержат скрытый контент, находящийся полностью или частично вне сцены.
При создании анимаций находящийся вне сцены контент обычно скрывается
для организации панорамирования и наплывов.
Посмотрите на рис. 11.11. Перед вами фрагмент анимации, созданной Адамом
Филипсом, с которым мы работали над некоторыми проектами
Выравнивание по центру с применением CSS 405

40°**
Рис. 11.10. Тестовая таблица, выровненная по центру без масштабирования

vjj311им
Iliili
III; |
^Ш^^^яИ HI

1
Щ HЩ
l

I
i

i 1

шШ I
1i

I

1H P

Рис. 1 1 . 1 1 . SWF с отображением контента, находящегося вне сцены


406 Глава 11. Интеграция с браузером

В принципе, SWF можно отцентровать в браузере с применением параметров


Publish Settings, но у такого решения есть серьезный недостаток: контент, нахо-
дящийся вне сцены, также будет видимым.
Наша цель - скрыть весь контент, находящийся за пределами сцены. Как видно
из рис. 11.12, на том же кадре итоговой анимации отображается только контент,
находящийся на сцене. Задача решается небольшим объемом HTML-кода.

Рис. 11.12. В итоговом варианте SWF отображается только сцена

Выравнивание по центру с использованием HTML


В Flash Player 6 и ранее для центровки SWF применялись таблицы HTML. Flash
MX генерирует HTML-код, в котором SWF внедряется в веб-страницу тегами
<object> и <embed>. Остается лишь заключить эти два тега в простой тег <table>
с атрибутами горизонтального (align="center") и вертикального (valign="middle")
выравнивания. В следующем листинге внесенные изменения выделены жирным
шрифтом:
<html>
<head> \
<title>myTitle</title>
</head>
<body bgcolor="#FFFFFF">
<!--URLs used in the movie-->
<!--text used in the movie -->
<table width="100r height=n100r border="0">
<tr align="center" valign="middle">
<td>
<object...
...</object>
Выравнивание по центру с применением CSS 407

</td>
</tr>
</table>
</body>
</html>
Добавление тега <table> не только выравнивает SWF по центру, но и скрывает
контент, находящийся вне сцены. К сожалению, этот способ не работает в Flash
MX 2004. Flash MX 2004 экспортирует код XHTML, а не HTML, а вертикальное
выравнивание таблиц HTML плохо работает в XHTML. В принципе, проблема
решается внедрением файлов Flash 7 в HTML, но лучше ограничиться XHTML
и использовать теги <div> и <span> вместо устаревших тегов <table> и атрибутов
выравнивания.

Выравнивание по центру в Flash MX 2004


с использованием CSS
Поскольку Flash MX 2004 экспортирует код XHTML, атрибут valign оказывается
под запретом. Несмотря на общую поддержку таблиц, все форматирование луч-
ше выполнять на уровне CSS.
К сожалению, в CSS не существует стандартных средств для выравнивания чего-
либо по вертикали - придется изобретать трюки.
Если опустить подробное перечисление атрибутов тегов <object>, <embed>
и <param>, типичный файл XHTML в Flash MX 2004 выглядит примерно так:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://
www.w3.org/TR/xhtml1/DTD/xhtml1-transifional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-l" />
<title>myFlash</title>
</head>
<body bgcolor-"#999999">
<!--URLs used in the movie-->
<!--text used in the movie-->
<object...
..,</object>
</body>
</html>
Чтобы выровнять Flash-контент по центру, нужно сначала вручную отредакти-
ровать XHTML и добавить определение стиля.
Для быстрого редактирования XHTML-кода SWF-ролика, просматриваемого
локально в IE, выполните команду View • Source. Конечно, для этого файловые
ассоциации должны быть настроены на запуск простого текстового редактора
типа Блокнота, а не Word!
Добавьте следующее определение стиля между тегами <head> и </head>:
<style type="text/css">
408 Глава 11. Интеграция с браузером

body
{
margin: Opx
}
#centercontent
{
text-align:center;
position: absolute:
top: Б0%;
l e f t : Ь0%:

</style>
Теоретически это должно приводить к размещению SWF на расстоянии 50% от
левого и верхнего полей браузера (а также удалению лишних промежутков вдоль
краев страницы), но есть одно неожиданное обстоятельство: CSS предполагает,
что точка регистрации находится в левом верхнем углу SWF. Чтобы увидеть
ошибку выравнивания, заключите теги <object> и <embed> в тег <div> с атрибу-
том centercontent, как показано в следующем листинге (дополнения выделены
жирным шрифтом):
<div id="centercontent">
<object...
.. .</object>

CSS выполняет центровку, но по центру выравнивается левый верхний угол


S W F ( P H C . 11.13).

>i1
Fie E •* F*v<e*ieT5o* -<e!p
- ^ ;.

Рис. 11.13. Левый верхний угол SWF выравнивается по центру окна браузера
Выравнивание по центру с применением CSS 409

В решении проблемы нам поможет одно малоизвестное обстоятельство - в CSS


допускаются отрицательные размеры полей. Если сдвинуть левое и верхнее поля
на величину, равную половине высоты и ширины сцены SWF, SWF тоже смес-
тится так, что центральная точка SWF совпадет с центральной точкой окна бра-
узера (рис. 11.14).

Рис. 11.14. Выравнивание SWF по центру с применением отрицательных полей

Добавьте следующий код в определение #centercontent файла XHTML (для сце-


ны, имеющей стандартные размеры 550 х 400 пикселов):
#centercontent
{
margin-left: -275px;
margin-top: -200px;
text-align: center;
position: absolute;
top: 50Я:
l e f t : Ь0%;

Атрибутам margin-left и margin-top задаются значения, равные половине ширины


и высоты сцены Flash в пикселах (с отрицательным знаком). Описанный прием
центрирует SWF в любом браузере, поддерживающем XHTML и CSS.
410 Глава 11. Интеграция с браузером

Окончательный результат - выравнивание SWF по центру без масштабирования


и без открытия контента, находящегося за пределами сцены, - показан на
рис. 11.15.

Рис. 11.15. SWF выравнивается по центру окна без масштабирования


и без открытия контента, находящегося за пределами сцены

Итоги
В выборе между HTML и XHTML/CSS нам, Flash-разработчикам, не пристало
отдавать предпочтение старым технологиям. Наверное, правильное центрирование
SWF с применением CSS неочевидно, но стоит узнать пару трюков, и вы без
труда добьетесь от браузера нужного поведения.

Динамическое масштабирование
ТРЮК

№92 контента
В идеале Flash-контент сохраняет свои размеры даже в том случае, если
пользователь изменил размеры окна браузера. Динамическое масшта-
бирование контента в ответ на изменение размеров браузера поможет
сохранить исходный дизайн.
Динамическое масштабирование SWF по размерам окна браузера вроде бы не
должно создавать проблем, но похоже, многие разработчики не умеют правиль-
но организовать его. Давайте разберемся, как это делается.
Хотя Flash Player поддерживает масштабирование SWF по размерам окна брау-
зера, делать этого не стоит по нескольким причинам:
• слишком большое увеличение отрицательно отразится на быстродействии
(особенно на больших экранах);
Динамическое масштабирование контента 411

• при увеличении растровых изображений на Flash-сайтах сильнее проявляют-


ся недостатки графики;
• уменьшение Flash-сайта затрудняет работу с ним с точки зрения пользова-
тельского интерфейса;
• многие части типичного Flash-сайта проектируются под конкретный размер,
а их просмотр в увеличенном виде снижает общее впечатление. Например,
растровые шрифты проектируются под малый размер и в увеличенном виде
смотрятся довольно убого. Кроме того, некоторые шрифты без засечек и мо-
ноширинные шрифты масштабируются непропорционально.
Другое, более предпочтительное решение - разрешить масштабирование отдель-
ных частей сайта или ограничить масштабный коэффициент.
Разработчик может посчитать, что масштабирование следует вообще запретить,
чтобы не нарушать графический стиль сайта, но при этом возникают две пробле-
мы. Сайт, который отлично смотрится на большом 21-дюймовом экране, может
стать совершенно невразумительным на 17-дюймовом экране. И наоборот, сце-
на, которая хорошо воспринимается на 17-дюймовом экране, на большом экране
покажется слишком мелкой. Хорошее компромиссное решение - разрешить
масштабирование сайта от 10 до 20 % в обе стороны. Тем самым обеспечивается
работа сайта на экранах разных размеров без нарушения общей эстетики.

Определение размеров сцены


Размеры сцены определяются легко - нужная информация хранится в стати-
ческих свойствах класса Stage:
trace(Stage.width);
traceCStage.height);
Хотя команды trace() не влияют на браузер, их результаты видны в режиме Test
Movie после изменения размеров сцены.
Если атрибуту HTML scale присвоено любое значение, отличное от литерала
"noScale", свойства Stage.width и Stage, height всегда возвращают внутренние раз-
меры Flash Stage (550 х 400 по умолчанию), хотя этот режим можно переопреде-
лить вручную в ActionScript:
Stage.sealeMode = "noScale";
Режим масштабирования также можно выбрать вручную в списке Scale окна
File • Publish Settings • HTML (строка No Scale). После выбора режима noScale свой-
ства Stage.width и Stage.height возвращают размеры окна браузера.
Режим noScale запрещает Flash масштабировать контент, но оставляет возмож-
ность управления масштабом из ActionScript. Обратите внимание: если задать
свойству scaleMode значение "showAH", "noBorder" или "exactFit", свойства Stage.width
и Stage.height возвращают размер сцены Flash, заданный в окне Modify • Document,
независимо от размеров окна браузера.
Следующая проблема - организовать проверку размеров сцена или окна браузера
не на каждом кадре, а только при их изменении (например, когда пользователь
412 Глава 11. Интеграция с браузером

вручную изменяет размеры окна браузера). Для этого размеры будут читаться
в обработчике события:
var stageListener - new ObjectO;
stageListener.onResize = functionO {
trace(Stage.height);
traceCStage.width);
}:
Stage.sealeMode = "noScale":
Stage.addLi stener(stageListener);
Допустим, мы работаем с двумя клипами. Первый, scaleable_mc, используется
в качестве фона и заполняет окно браузера. Второй, centered_mc, всегда остается
в центре браузера и не масштабируется.
На рис. 11.16 клип scaleablejnc представлен светло-серым градиентным фоном,
а прямоугольник с текстом «content» в центре изображает основное содержание
сайта centered me.
: • • " . : • • .

ф ;
" • " " " : ¥ 1

Рис. 11.16. Фоновая градиентная заливка с наложением контента

Заполнение сцены контентом Flash позволяет реализовать многие возможности,


отсутствующие при размещении Flash-сайта перед мозаичным GIF-фоном. В част-
ности, мы можем легко реализовать эффекты прозрачности (тени или непрямо-
угольную форму основного сайта) без использования элементов ActiveX, спе-
цифических для Internet Explorer, применить анимацию или эффекты к фону.
Использование векторного градиента вместо растровой графики также повыша-
ет плавность цветовых переходов. Хотя в данном примере SWF может иметь
большие размеры, быстродействие падает только в том случае, если большие
области экрана изменяются в каждом кадре. Градиентный фон остается неиз-
менным, поэтому его присутствие lie отражается на быстродействии.
Динамическое масштабирование контента 413

Следующий код (доступен в файле varyStage.fla на сайте книги) сохраняет ис-


ходную позицию и масштаб клипа content_mc, при этом клип scalablejnc изме-
няется в размерах и заполняет окно браузера:
function stageResizeO {
sealable_mc._width = Stage.width + 50:
scalable_mc._height = Stage.height + 50:
}
Stage.sealeMode = "noScale";
myListener = new ObjectO;
myListener.onResize = functionO {
stageResizeO:
}:
Stage.addListener(myListener);
Первыми выполняются последние шесть строк, следующие за определением
функции, поэтому давайте начнем рассмотрение с них. В этом фрагменте свой-
ству scaleMode задается значение "noScale", после чего определяется слушатель,
реагирующий на событие изменения размеров окна браузера.
Вся основная работа выполняется функцией stageResizeO, которая вызывается
каждый раз, когда пользователь изменяет размеры окна браузера. Функция
stageResizeO масштабирует фоновый клип scaleablejnc по размерам текущего
окна браузера (в пикселах) с прибавлением небольшого зазора (+50), чтобы по
возможности закрыть поля в браузере.
Чтобы эффект работал, откройте окно File • Publish Settings • HTML, задайте свой-
ству Dimensions значение Percent, а свойству Scale - значение Default(Show All).
Чтобы предотвратить отображение полей в окне браузера, вручную отредакти-
руйте тег <body> в HTML-файле и приведите его к следующему виду:
<Body marginwidth="0" marginHeight="O" topmargin="0" leftmargin="O">
Также размеры полей можно задать с использованием CSS.

Итоги
Многие Flash-сайты, эмулирующие «операционную систему в окне браузера»,
состоят из одного большого фонового SWF-ролика, всегда полностью закрыва-
ющего окно браузера. Перед ним располагается несколько SWF меньших разме-
ров и не масштабируемых. Аналогичная методика может успешно применяться
и для традиционных сайтов, с заменой векторного фона растровой графикой.
Умеренное масштабирование существенно улучшает восприятие сайта без нару-
шения стиля текстовых Flash-сайтов с мелкими шрифтами. Возможности адап-
тации интерфейса к размеру окну браузера практически не ограничиваются. По
адресу http://www.it2004.jp/index2.html приведен пример сложного интерфейса,
который автоматически изменяет свою конфигурацию в соответствии с измене-
ниями размеров окна. Повышение быстродействия за счет буферизации собы-
тий Stage.onResize с использованием интервальных таймеров описано по адресу
http://chattyfig.figleaf.eom/ezmlm/ezmlm-cgi71:msn:62581:dggpkifkacibblilcmok.
414 Глава 11. Интеграция с браузером

ТРЮК
Создание ссылок HTML в Flash
№93 Ссылки в стиле HTML обычно не включаются в Flash-контент, но, в принципе,
такая возможность существует. Настоящий трюк показывает, как создать
гиперссылку в стиле HTML для управления временной диаграммой Flash.
Средства форматирования CSS, поддерживаемые в Flash MX 2004, позволяют
создавать стандартные ссылки HTML. К сожалению, такие ссылки и работают
стандартно - они выполняют переход к обычным страницам, не входящим в SWF.
На помощь приходит конструкция asfunction, которая позволяет ссылкам управ-
лять SWF из ActionScript.
Прежде всего следует воссоздать внешний облик гиперссылки в Flash, что дела-
ется относительно несложно.
Создайте файл в своем любимом текстовом редакторе (у меня это редактор
SciTE|Flash - см. трюк 74). Введите текст, показанный на рис. 11.17. Сохраните
файл под именем flash.ess.

Pte Edit Search Ve


i w Tools Options Syntax Windows Help
F e a T y i T a 7 i £"ia к ! о"••;• i q ^

P{
color: #000000;
font-family: sans-serif;
font-size; Юрх;

color: #O0O0FF;

a:hover{
Ю h text-decoratton: underline;

Рис. 11.17. Содержимое файла .ess

Затем создайте на сцене многострочное текстовое поле с именем myHTML txt.


Добавьте следующий код для создания в поле myHTML_txt текста HTML с гипер-
ссылкой http://www.oreilly.com:
var myCss = new TextFi eld.Styl eSheet();
myCSS.load("flash.ess");
myCSS.onLoad = function(success)' {
i f (success) {
myHTML txt.styleSheet = myCSS:

myHTML_txt.html = true;
myHTML_txt.htmlText = "<p>This is a <a href =
'http://www.oreilly.com'>link</a> to my site.</p>";
myHTML_txt.htmlText += "<p>Click i t and see!</p>";
Создание ссылок HTML в Flash 415

Внешний вид гиперссылки показан на рис. 11.18.

This is a linK to my site.


ClteK it and see!

Рис. 11.18. Гиперссылка HTML в Flash

«Чистые» гиперссылки HTML в Flash SWF удобны для перехода к внешним


страницам, но использовать их для управления текущей временной диаграммой
Flash не удастся. Для решения этой задачи необходимо использовать конструк-
цию asfunction. В следующем листинге asfunction обеспечивает вызов функции
asLink() с аргументом 10 при щелчке на ссылке; в результате индикатор текущей
позиции перемещается к кадру 10 текущей временной диаграммы S.WF. Обрати-
те внимание: протокол asfunction: указывается в ссылке по аналогии с протоко-
лами http: или mailto:. Браузер передает URL, начинающийся с asfunction:, моду-
лю или элементу ActiveX Flash Player. Flash Player вызывает функцию, заданную
первым аргументом после asfunction, и передает ей остальные аргументы.
function asLink(goto) {
gotoAndPlay(goto);
}
var myCSS = new TextField.StyleSheetO:
myCSS.loadC"flash.ess"):
myCSS.onLoad = function(success) {
i f (success) {
myHTML txt.stylesheet = myCSS:

myHTML_txt.html = true:
myHTML_txt.html Text = "<p>This is a<a href =
'asfunction:asLink. 10'>1ink</a> to frame 10.</p>":
myHTML_txt.htmlText +» "<p>Click i t and see!</p>";
stopO:

Итоги
Благодаря тому, что Flash MX 2004 поддерживает HTML и подмножество средств
форматирования CSS, кнопки Flash в пользовательском интерфейсе могут ис-
пользоваться совместно с гиперссылками в стиле HTML. В этом трюке показа-
но, как использовать такие ссылки для перемещения по временной диаграмме
Flash (или просто выполнения кода ActionScript). Конечно, описанный меха-
низм также может использоваться и для построения традиционных гиперссылок
на внешние страницы.
Как известно, текстовые поля Flash теперь могут включать графику и текст в фор-
мате HTML (см. трюк 46), и это повышает практическую ценность данного трю-
ка и позволяет отображать мини-страницы HTML в Flash SWF. Текстовые поля
даже могут содержать другие SWF - довольно интересная альтернатива для
loadMovie() и /oadMovieNum()!
41В Глава 11. Интеграция с браузером

ТРЮК Интеграция Flash с кнопкой возврата


№94 Пользователи Flash издавна жаловались на отсутствие совместимости
с кнопкой возврата в окне браузера. Пора опровергнуть этот миф — кнопка
возврата может использоваться для возврата в Flash-сайтах, не связан-
ного с временной диаграммой.
Одной из целей, поставленных при проектировании Flash MX (и Flash Player 6),
было повышение удобства работы. Среди прочего, фирма Macromedia добавила
поддержку именованных якорных ссылок.
Многие веб-дизайнеры знакомы с якорными ссылками по их HTML-прототи-
пам. Якорная ссылка представляет собой ссылку из документа на другую часть
(обычно) того же документа. Якорные ссылки часто используются в длинных
текстовых документах, не помещающихся в видимой части окна браузера. Чтобы
пользователю не приходилось прокручивать страницу туда-сюда, якорная ссыл-
ка позволяет быстро перейти к нужной секции. Имена якорных ссылок имеют
префикс # - например, http://www.oreilly.com/index.htnnWfaq.
В своей реализации якорных ссылок фирма Macromedia приравняла документы
HTML к главной временной диаграмме SWF, поэтому якоря позволяют переме-
щаться вдоль _root с использованием кнопки возврата. Естественно, в Flash можно
использовать и более традиционные средства перемещения (например, кнопки
Flash, обработчики событий onRelease которых содержат операции gotoAndPlayO).
К сожалению, в большинстве Flash-сайтов кадры временной диаграммы _root не
используются как якорные точки. Щелчок на кнопке не вызывает переход к не-
которому кадру _root, потому что это затрудняет сопровождение SWF и создает
трудности при работе контентом большого объема. Вместо этого в Flash-интер-
фейсе типичного коммерческого приложения используется система на базе
ActionScript, которая вызывает loadMovieQ с вложенными клипами или связыва-
ет контент с главной временной диаграммой.
Единственное обходное решение основано на создании скрытых HTML-стра-
ниц, изменяющихся синхронно с Flash-сайтом; именно эти скрытые страницы
сохраняются в истории браузера. Когда скрытая HTML-страница изменяется
из-за нажатия в браузере кнопок перехода вперед и возврата, JavaScript передает
значения переменных Flash-сайту и информирует его о смене страницы. Flash-
сайт настроен на перехват и обработку этих изменений.
Вам не удастся использовать JavaScript для чтения истории браузера и ее пере-
дачи Flash, поскольку история недоступна для JavaScript (и чего-либо иного) по
соображениям безопасности - например, чтобы оградить информацию о посе-
щенных сайтах от рекламщиков.

Создание скрытых страниц


Несомненно, самый простой способ создания скрытых HTML-страниц - их вклю-
чение в одну страницу с Flash-сайтом с применением фреймов. С учетом того,
что у многих пользователей Flash установлен пакет Macromedia Studio MX, мы
воспользуемся Dreamweaver MX (для ввода HTML-кода вы можете использо-
вать редактор по своему выбору).
Интеграция Flash с кнопкой возврата 417

В Dreamweaver MX имеется стандартный шаблон, отдаленно похожий на нуж-


ный набор фреймов. Выполните команду File • New и выберите шаблон Fixed
Bottom (рис. 11.19).

i Page
Basc •Fixed' Botom ; \
Dynamci Page Fixed Botom, Nested Left
Template Page Fixed Bottom, f4ested Rg
ih
Other Fixed Left
CSS Styte Sheets fixed Left, Nested Botom
Framesets • Fixed Left, Nested Top
Page Desgi ns Fixed Right
Page Desgi ns (Accessible) Fixed Right, Nested Bettor
Fixed Right, Nested Top
Fixed Top
Fixed Top., Fixed Botom
fixed Top, Nested Left
fixed Top., Nested Right
Split Horizontal Description:
Split Vertical JA frameset split horizontally with a
jfixed-size botom frame.

.Help.;. J Create Cancel

Рис. 11.19. Выбор шаблона Fixed Bottom в Dreamweaver MX

Наш HTML-файл Flash будет заполнять верхний фрейм, а скрытые страницы


HTML будут реализованы в виде пустых страниц (содержащих только код
JavaScript) в нижнем фрейме.
Используя этот шаблон или его аналог, создайте приведенный ниже HTML-код.
Строки, в которых сгенерированный Dreamweaver MX код был изменен, выде-
лены жирным шрифтом. Сохраните набор фреймов под именем frame.html.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/
TR/html4/frameset.dtd">
<html>
<head>
<title>:: Flash with Browser History ::</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-l">

</head>
<frameset rows="*.80" frairieborder="NO" border="0" framespacing="O">
<frame src="flash.html" name="mainFrame">
<frame src="one.html" name="bottomFrame" scrolling="NO" noresize>
</frameset>
<noframes><body>
You should really get a more up to date browser before they phase out steam
power.
418 Глава 11. Интеграция с браузером

</body></noframes>
</html>
Переходим к построению скрытых страниц. Создайте пять пустых HTML-фай-
лов с именами one.html, two.html, three.html, four.html и five.html, сохраните их в од-
ной папке с файлом frame.html.
Отредактируйте файл one.html и приведите его к следующему виду (изменения
выделены жирным шрифтом):
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<tit1e>one</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-l">
</head>
<body bgcolor="#FFFFFF">
<script language='JavaScript'>
parent.mainFrame.flash.SetVariableChistory1, 1);
</script>
</body>
</html>
Обратите внимание: тег <title> соответствует конкретному файлу (в данном слу-
чае one), а во втором параметре строки JavaScript указывается параметр, переда-
ваемый SetVariable() - номер файла (1). Мы явно задаем цвет фона страниц
нижнего фрейма, чтобы они не были видны при выборе пользователем другого
набора фоновых цветов.
Внесите аналогичные изменения в четыре оставшихся HTML-файла. Например,
файл five.html должен выглядеть так:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>five</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-l">
</head>
<body bgcolor="#FFFFFF">
<script language='JavaScript'>
parent.mai nFrame.f1 ash.SetVari able('hi story', 5);
</script>
</body>
</html>
Чтобы набор фреймов заработал, остается создать секцию flash.html.
Создайте в Flash новый документ командой File • New. Выполните команду
File • Publish Settings, перейдите на вкладку HTML, выберите в списках Horizontal
и Vertical из группы Flash Alignment значение Center, а в списке Scale - строку No
scale, как это было сделано в трюке 90 (см. рис. 11.8).
Сохраните файл Flash под именем flash.fla в одной папке с сохраненными ранее
HTML-файлами. Выполните публикацию (File • Publish), чтобы создать файлы
flash.html и flash.swf.
Интеграция Flash с кнопкой возврата 419

Создание контента Flash


Мы создадим простую внедренную временную диаграмму, чтобы продемонстри-
ровать принципы работы трюка.
Создайте новый символ клипа с пятью ключевыми кадрами (неважно, будет ли
он именованным или нет), как показано на рис. 11.20. Каждый ключевой кадр
должен представлять отдельную страницу Flash-приложения (рис. 11.21).

Рис. 11.20. Клип с пятью ключевыми кадрами, представляющими


разные страницы Flash-приложения

content page content page

content page content page

content page

Рис. 1 1 . 2 1 . Страницы Flash-приложения

Разместите клип на сцене в кадре 1 главной временной диаграммы, присвойте


ему имя экземпляра content на панели свойств. Создайте меню из пяти кнопок
с именами экземпляров от Ы (кнопка 1) до Ь5 (кнопка 5).
Наконец, создайте над текущим слоем новый слой с именем actions. Присоеди-
ните следующий сценарий к кадру 1 нового слоя:
bl.onRelease - functionO {
fi11BottomC"one.html");
420 Глава 11. Интеграция с браузером

content.gotoAndStop(I):
}:
b2.onRelease = function О {
f ill BottomC two. html");
content.gotoAndStop(2);
}:
b3.onRelease = functionО {
fillBottomC"three.html");
content. gotoAndStopO):
}:
b4.onRelease - functionO {
fillBottomC"four.html"):
content.gotoAndStop(4);
}:
b5.onRelease = functionO {
fillBottomCfive.html");
content.gotoAndStopC5);
}:
function setHistory() {
i f (history == 1) {
hisEnabied = true:
content.onEnterframe = functionO {
i f (history !- 0) {
this.gotoAndStop(history);
history = 0:

clearlnterval(startHistory):
}
function fillBottom(doc) {
i f (hisEnabled) {
getURLCdoc. "bottomFrame"):

}
var history;
var hisEnabled = false;
startHistory = setlntervaKsetHistory, 500);
content. stopO:
Теперь при щелчке на каждой из кнопок не только Flash переходит к соответ-
ствующему кадру временной диаграммы, но и функция fillBottom() вызывает со-
ответствующую HTML-страницу в нижнем фрейме веб-страницы. Страницы не
видны пользователю, так как они не содержат видимого контента, однако брау-
зер включает их в историю.
Когда пользователь щелкает на кнопках Вперед (Forward) и Назад (Back), браузер
подгружает страницы HTML из истории, а размещенный в.них код JavaScript при-
сваивает переменной Flash history значение от 1 до 5, в зависимости от страницы.
Обработчик onEnterFrame перехватывает изменение и заставляет контент изме-
няться синхронно с изменениями HTML-страницы. Таким образом, история
браузера синхронизируется с передачей управления в Flash-ролике.
Интеграция Flash с кнопкой возврата 421

Обратите внимание: при использовании кнопок Flash для перемещения контента


клипа к нужному кадру переход фактически осуществляется дважды, из ActionScript
и из JavaScript. В принципе переходы из ActionScript можно убрать, но лучше
оставить их для надежности: они гарантируют, что система переходов будет ра-
ботать даже при отсутствии поддержки JavaScript.
Код ActionScript написан таким образом, что:
• система переходов работает даже в том случае, если текущий браузер не под-
держивает JavaScript (или SWF выполняется в Standalone Player). Flash про-
веряет работоспособность JavaScript в команде if (history==1) в функции
setHistory(). Если поддержка JavaScript отключена, переменная history не оп-
ределена; в этом случае Flash не назначает обработчик onEnterFrame, факти-
чески отменяя проверку истории браузера;
• взаимодействие ActionScript с JavaScript начинается с задержкой в 0,5 с. По-
хоже, HTML присваивает значение переменной Flash history с небольшой
паузой. По этой причине ActionScript откладывает создание обработчика
onEnterFrame на 0,5 с при помощи интервального таймера setlnterval().

Итоги
При организации передачи управления кнопками Flash в браузере активизиру-
ются кнопки Вперед (Forward) и Назад (Back). Щелчки на этих кнопках позво-
ляют перемещаться по истории посещаемых страниц.
Отсутствие функциональности возврата считалось одним из главных неудобств
Flash. Как видите, проблема успешно решается!
Конечно, опытные пользователи Flash найдут в этом решении ряд недостатков.
Например, необходимость создания (и сопровождения) пустой HTML-стра-
ницы для каждой страницы Flash выглядит довольно утомительно и противо-
речит одному из главных достоинств Flash-дизайна - отсутствию страничной
ориентации. Резонно спросить: куда должен переходить пользователь при нажа-
тии кнопки возврата в Flash-приложении? В сайтах на базе HTML каждая стра-
ница представляет состояние приложения в конкретный момент времени. Но
в приложениях Flash каждая «сцена» может состоять из нескольких кадров
и содержать анимацию или материалы, занимающие некоторый промежуток
времени. Например, когда пользователь щелкает на кнопке возврата к преды-
дущей сцене, должен ли Flash-дизайнер перемотать и воспроизвести заново ани-
мацию, аудио или видео соответствующей сцены? При выборе страниц, пред-
ставляющих фиксированные моменты времени, следует учитывать состояние
вашего приложения.
Одно из возможных усовершенствований этого трюка - динамическое построение
HTML-страниц в скрытых кадрах средствами JavaScript. В этом случае количество
страниц в истории браузера не является фиксированной величиной, что обеспе-
чивает необходимую гибкость при построении сложных Flash-сайтов.
Взаимодействие JavaScript с Flash поддерживается не всеми браузерами; эта тема
обсуждается по адресу http://www.macromeclia.com/support/flash/ts/documents/
422 Глава 11. Интеграция с браузером

java_script_comm.htm. Представленный трюк работает в Netscape и IE, но по край-


ней мере один пользователь сообщил об ошибке JavaScript в Mozilla 1.6. Для
тестирования различных браузеров можно воспользоваться страницей Macromedia
http://www.macromedia.com/support/flash/ts/docurnents/java_script_comm/
javascript_to_flash.html.

ТРЮК Передача фокуса клавиатуры SWF


№95 Flash обнаруживает нажатия клавиш и принимает текстовый ввод лишь
после того, как SWF получит фокус ввода с клавиатуры. Настоящий трюк
показывает, как передать фокус SWF, не заставляя пользователя щел-
кать на нем вручную.
Браузер передает фокус ввода с клавиатуры лишь после того, как SWF-ролик
будет выделен (обычно щелчком мышью).
А это означает, что SWF начинает реагировать на нажатия клавиш лишь после
щелчка. Во многих ситуациях такое поведение нежелательно. Допустим, вы только
что загрузили видеоигру, в которой игрок управляет своим игровым персона-
жем при помощи клавиш со стрелками. Если пользователь не щелкнет на SWF
перед началом игры, команды управления попросту не воспринимаются. Стан-
дартное обходное решение - заставить пользователя щелкнуть на SWF (обыч-
но для этой цели создается кнопка Start, которая не выполняет никаких других
функций). Существует и более удачный вариант: определить большую область
для щелчка и вывести текстовую инструкцию типа «Щелкните кнопкой мыши,
чтобы начать игру». И все же более элегантное решение - вообще не требовать
от пользователя никаких лишних действий.
К счастью, принудительная передача фокуса может быть осуществлена следую-
щей командой JavaScript (которая лучше работает при тестировании в браузере,
а не в режиме Test Movie среды разработки Flash):
getURLC"javascript:me.focus();void 0;"):
Используя метод getURLQ, эта строка вызывает метод JavaScript Window.focus()
с указанием целевого файла т е (предполагается, что SWF называется me.swf).
Фокус автоматически передается SWF-ролику с указанным именем.

Итоги
Несмотря на столь краткое описание, этот трюк станет одним из тех мелких
штрихов, которые придают профессионализм вашей Flash-презентации. Ког-
да на экране появляется форма, пользователь ожидает, что он может сразу
приступить к вводу и переключаться между текстовыми полями без предвари-
тельного щелчка. Если приложение игнорирует нажатия клавиш, это вызовет
недоумение у пользователя. Данный трюк, как и предыдущий, не работает
в браузерах, не поддерживающих обмен данными JavaScript/Flash (например,
Mozilla).
Клавиши ускоренного вызова 423

ТРЮК
Клавиши ускоренного вызова
№96 Чтобы работа с Flash-приложением стала более быстрой и удобной, свяжите
с каждой кнопкой SWF специальную клавишу или комбинацию клавиш.
Клавиши ускоренного вызова делают сайт более удобным. В настоящем трюке
показано, как реализовать клавиатурные сокращения с минимальным объемом
программного кода. Стоит заметить, что идентификация ввода с клавиатуры не
сводится к простой проверке нажатой клавиши. Необходимо предусмотреть об-
работку комбинаций клавиш (например, Ctrl+Q) и обнаруживать как нажатия,
так и отпускания клавиш.

Обнаружение нажатий клавиш


Чтоб проверить состояние клавиатуры, необходимо предварительно создать
объект-слушатель для класса Key. Следующий фрагмент выводит сообщение каж-
дый раз, когда обнаруживает нажатие клавиши:
function down О {
trace("detected!");
}
var KeyListener:Object = new ObjectO:
KeyListener.onKeyDown = down; i
Key.addLi stener(keyLi stener);
При анализе клавиатурного ввода класс Key не различает символы верхнего и ниж-
него регистров. Например, класс Key возвращает один и тот же код клавиши
независимо от того, была ли в момент нажатия клавиши А нажата клавиша Shift
или активизирован режим Caps Lock.
Недостаток приведенного кода заключается в том, что функция выполняется
в течение всего времени, пока клавиша остается нажатой; из-за этого код не под-
ходит для обнаружения комбинаций клавиш, поскольку нажатие клавиши и ее
удерживание приводит к многократному генерированию событий. Чтобы решить
проблему, следует организовать такую обработку событий, чтобы для каждого цик-
ла нажатия/отпускания клавиши выдавалось только одно сообщение «detected!».
Задача решается следующим кодом:
function downO {
trace("detected!");
delete this.onKeyDown;
this.onKeyUp = up:
}
function up() {
this.onKeyUp = undefined;
this.onKeyDown = down;
}
var keyListener:Object = new ObjectO;
keyListener.onKeyDown = down;
key.addListener(keyListener);
424 Глава 11. Интеграция с браузером

Обнаружив событие onKeyDown, программа переключается в режим поиска парно-


го события onKeyUp. По событию onKeyUp цикл запускается заново. Таким обра-
зом организуется обработка нажатия и отпускания клавиш.
Обратите внимание: этот код работает даже при вводе комбинации клавиш (на-
пример, Ctrl+A). В этом случае сообщение «detected!» выводится для каждой
клавиши.

Преобразование нажатий клавиш


во входные символы
Итак, мы получили возможность обнаруживать нажатия клавиш. Но на самом
деле мы хотим узнать, какие именно клавиши были при этом нажаты. Для решения
этой задачи применяются методы Key.isDown() и Key.getCode(). Первый метод
проверяет, была ли нажата заданная клавиша, а второй возвращает код послед-
ней клавиши, инициировавшей событие (то есть последней клавиши, изменив-
шей свое состояние; эта клавиша не всегда совпадает с той, которая нажата в на-
стоящий момент). Например, если одновременно нажать клавиши А и S, а затем
отпустить клавишу А, то метод getCode() вернет код клавиши А, хотя клавиша
S остается нажатой.
Учтите, что класс Key возвращает коды физических клавиш и не учитывает со-
стояние модификаторов. Например, при нажатии клавиши X всегда возвращает-
ся один и тот же код независимо от состояния клавиш Shift и Ctrl.
В электронной документации приведена таблица кодов алфавитно-цифровых
кодов клавиш. Чтобы найти ее, выполните поиск по фразе «Keyboard keys and
keycode values». Для клавиш, не являющихся алфавитно-цифровыми (напри-
мер, клавиш управления курсором и пробела), можно воспользоваться констант-
ными свойствами класса Key). Например, константа Key.SPACE содержит код
пробела, а константа Key.CONTROL содержит код клавиши Ctrl.
Пример:
х = Key.isDown(65); // х = true, если нажата клавиша А
х = Key.getCodeO: // у = 65. если событие инициировано клавишей А
Зная код клавиши, мы можем легко написать сценарий ActionScript для обнару-
жения нажатий отдельных клавиш. Допустим, на сцене размещены три кнопки
с именами экземпляров buttonA, buttonB и buttonC. Следующий листинг выпол-
няет обработчик onRelease каждой из кнопок А, В или С. Кроме того, фокус
передается кнопке, связанной с нажатой клавишей, вследствие чего кнопка (сре-
ди прочего) выделяется желтым прямоугольником:
function аНапсПегО {
traceC'you clicked A"):
}
function bHandlerO {
traceC'you clicked В");
}
function cHandlerO {
traceC'you clicked C"):
Клавиши ускоренного вызова 425

function down О {
i f (keys [Key. getCodeO] !- undefined) {
keys[Key.getCode()].onRelease();
Selecti on.setFocus(keys[Key.getCodC)]);
}
this.onKeyDown = undefined;
this.onKeyUp = up:
}
function up() {
this.onKeyUp = undefined;
this.onKeyDown = down;

var keys:Array - new ArrayO;


var keyl_istener:Object = new ObjectO:
keys[65] = buttonA;
keys[66] = buttonB;
keys[67] = buttonC;
buttonA.onRelease = aHandler:
buttonB.onRelease = bHandler;
buttonC.onRelease = cHandler;
keyListener.onKeyDown = down;
Key.addListener(keyListener);
Программа создает массив keys, индексы которого ассоциируются с кнопками
Flash. Например, кеу[65] содержит ссылку на кнопку buttonA, поэтому при нажа-
тии клавиши А (код 65) выполняется обработчик события buttonA.onRelease().
На рис. 11.22 изображены кнопки buttonA, buttonB и buttonC до (слева) и после
(справа) нажатия клавиши А. При нажатии клавиши А на панели Output появля-
ется сообщение «You clicked A».

«.А • А
# В • В
• С • С
Рис. 11.22. Кнопки без выделения (слева); кнопка А выделена (справа)

Чтобы Flash Player регистрировал нажатия клавиш, необходимо передать SWF


фокус (см. трюк 65). Фокус сохраняется до тех пор, пока пользователь не щелк-
нет мышью на контенте за пределами SWF. Простое перемещение указателя
мыши приводит к потере фокуса кнопкой, поэтому, если во время нажатия кла-
виши А перемещается мышь, желтый прямоугольник выделения может и не по-
явиться.
Чтобы протестировать SWF-ролик, распознающий нажатия клавиш, выполните
команду Control • Disable Shortcuts в режиме Test Movie. Flash перестает обраба-
тывать нажатия клавиш, искать собственные служебные комбинации и скры-
вать их от тестируемого ролика.
426 Глава 11. Интеграция с браузером

Преобразование комбинаций клавиш


во входные данные
Во многих приложениях одиночными клавишами ускоренного вызова поддер-
живаются также управляющие комбинации (например, Ctrl+F1). Было бы разум-
но организовать обработку таких комбинаций.
Тем не менее, при использовании комбинаций клавиш для управления Flash
необходимо действовать осторожно, потому что Flash редко оказывается в нача-
ле очереди обработки. Большинство стандартных комбинаций перехватывается
операционной системой или браузером, и до Flash такие комбинации не дохо-
дят.
В нашей программе комбинация будет задаваться массивом объектов с описани-
ем клавиш, которые должны одновременно удерживаться для формирования
входной комбинации.
Допустим, мы хотим использовать:
• клавишу А для кнопки buttonA;
• комбинацию Ctrl+B для кнопки buttonB;
• комбинацию Ctrl+D для кнопки buttonN.
Эта информация кодируется следующим массивом объектов:
keys[0] = {btn:buttonA. combo:[65]};
keys[l] = {btn:buttonB. combo:[Key.CONTROL. 66]};
keys[2] = {btn:buttonC. combo:[Key.CONTROL. 68]}:
Каждый элемент массива keys представляет собой объект с двумя свойствами:
• свойство keys[].btn определяет кнопку Flash, с которой связывается комбина-
ция;
• свойство keys[].combo содержит массив с перечислением клавиш, входящих
в комбинацию.
В следующем листинге структура данных keys[] используется для определения
клавиатурных эквивалентов трех кнопок: buttonA, buttonB и buttonC. Нетривиа-
лен разве что способ, которым мы проверяем нажатие полной комбинации. Для
каждой комбинации программа:
• присваивает логической переменной allKeys значение true;
• проверяет, нажата ли каждая клавиша, входящая в комбинацию, при помощи
метода Key.isDown(keys[j].combo[i]). Выражение истинно, если клавиша нажа-
та, и ложно в противном случае. Полученный результат объединяется опера-
цией && со значением allKeys. Если хотя бы одна клавиша не нажата, пере-
менная allKeys становится равной false и сохраняет это значение до конца
цикла;
• если в конце цикла переменная allKeys все еще равна true, мы знаем, что на-
жаты все клавиши, входящие в комбинацию.
Для формирования переменной allKeys не важны порядок нажатия клавиш или
их количество, именно поэтому так удобен логический оператор &&. Если пере-
менная allKeys равна true, дальнейшая процедура почти не отличается от обра-
Клавиши ускоренного вызова 427

ботки одиночных клавиш. В следующем листинге изменения выделены жирным


шрифтом:
function aHandlerO {
trace("you clicked A");
}
function bHandlerO {
traceCyou clicked B");
}
function cHandlerO {
traceC'you clicked C");
}
function down О {
var all Keys;
//tracer "):
for (var j = 0; j<keys.length; j++) {
all Keys = true;
for (var i = 0; i<keys[j].combo.length: i++) {
allKeys = allKeys && Key.isDown(keys[j].combo[i]):
}
if (allKeys) {
Selection.setFocus(keys[j]):
//trace("combo detected");
this.onKeyDown = undefined;
this.onKeyUp = up;
keys[j].btn.onRelease();
break;

}
function up() {
//traceCup"):
this.onKeyUp = undefined;
this.onKeyDown = down;
}
//
var keys:Array = new ArrayO:
var keyListener:Object = new ObjectO;
keys[0] = {btn:buttonA. combo:[65]};
keys[l] = {btn:buttonB. combo:[Key.CONTROL. 66]};// Ctrl-В
keys[2] = {btn:buttonC. combo:[Key.CONTROL. 68]};// Ctrl-D
buttonA.onRelease = aHandler;
buttonB.onRelease = bHandler;
buttonC.onRelease = cHandler;
keyListener.onKeyDown = down;
Key. addLi stener(keyLi stener);
Я оставил некоторые полезные вызовы trace(), использовавшиеся в процессе
разработки. Если вы хотите увидеть, как и в каком порядке программа обнару-
живает и сбрасывает обработчики событий onKeyDown, onKeyUp и onRelease, убе-
рите комментарии в вызовах traceQ и проанализируйте порядок возникновения
событий на панели Output. Логика программы мгновенно прояснится.
428 Глава 11. Интеграция с браузером

Комбинация клавиш Ctrl+В не будет работать при тестировании ролика в Flash,


если вы забудете отключить клавиши ускоренного вызова, потому что комбина-
ция Ctrl+B в Flash открывает Bandwidth Profiler. Комбинация Ctrl+C не работает,
потому что она перехватывается другими приложениями (скорее всего, сред-
ствами копирования в буфер операционной системы), поэтому для кнопки С была
выбрана комбинация Ctrl+D.
Впрочем, при тестировании SWF в браузере комбинация Ctrl+B тоже может
вызвать проблемы, поскольку в Internet Explorer она используется для упорядо-
чения «избранного». Мораль: всегда убеждайтесь в том, что выбранные вами
комбинации клавиш не используются для других целей другими приложениями,
работающими одновременно с Flash SWF, иначе Flash их попросту не увидит!

Итоги
Поддержка клавиатурных комбинаций наряду с управлением мышью сделает
сайт более доступным как для пользователей с дефектами зрения, так и для
опытных пользователей с навыками слепой печати. Комбинации клавиш на удив-
ление редко поддерживаются Flash-сайтами - может быть, из-за того, что их
программная реализация относительно нетривиальна. Что же, теперь вы знаете,
как это делается!
ГЛАВА 12

Безопасность
Трюки № 97-100
Пользователь может быстро загрузить исходные файлы сайта иа базе HTML
и просмотреть их без разрешения разработчика. HTML-страница по определе-
нию представляет собой текстовый файл, передаваемый браузеру пользователя
или любому клиенту, от которого поступил запрос. Браузер или программа «за-
качки сайтов» легко загружает любой текст и графику, отображаемые на страни-
це. К сожалению, законы об авторских правах не предоставляют сколько-нибудь
серьезной защиты, особенно за пределами США и Европы, поэтому большин-
ство владельцев сайтов либо допускает возможность копирования контента, либо
пытается принять технологические меры защиты. В простейшем случае разра-
ботчик может включить в изображение визуальную информацию об авторских
правах; пиратам придется по крайней мере стереть этот знак, чтобы замести
следы. Если автор настроен более радикально, он может включить в изображе-
ние невидимый «водяной знак», предотвращающий несанкционированное вос-
произведение. Конечно, все меры «цифровой защиты» могут быть вскрыты, но
здесь мы не будем обсуждать все технические и политические аспекты этой темы.
Двоичный файловый формат SWF не удастся прочитать с такой же легкостью, как
текстовый файл, но особой дополнительной защиты он не обеспечивает. Для его
расшифровки достаточно воспользоваться программой чтения формата SWF, опи-
сание которого находится в открытом доступе по адресу http://www.macromedia.com/
software/flash/open/licensing/fileformat (лицензия выдается бесплатно, но формат
SWF является интеллектуальной собственностью Macromedia, а не обществен-
ным достоянием). Разработчикам, собирающимся писать программы для созда-
ния SWF-файлов, достаточно посетить OpenSWF.org (http://www.openswf.org) - сайт
ресурсов для разработчиков, работающих с форматом SWF.
В настоящее время существует немало декомпиляторов Flash SWF и программ
извлечения контента, включая ActionScript Viewer (http://buraks.com/asv) - пер-
вую программу такого рода, появившуюся на рынке несколько лет назад.
Итак, SWF-файлы уязвимы в той же степени, что и традиционные веб-ресурсы.
Ничто не помешает изобретательному хакеру просмотреть ваши ресурсы и код,
поэтому в файлах SWF не следует хранить конфиденциальную информацию
(например, пароли). И все же задачу хакера стоит по крайней мере усложнить,
потому что многие злоумышленники быстро сдаются, столкнувшись с трудно-
стями, или подыскивают более доступный сайт.
430 Глава 12. Безопасность

Впрочем, кража контента - не самая серьезная проблема. Большее внимание


приходится уделять вопросам общей безопасности. В традиционном веб-дизай-
не конфиденциальная информация ни в коем случае не должна храниться в за-
гружаемых файлах или в любых файлах, которые могут быть легко открыты или
скопированы. Вместо этого защищенные данные передаются напрямую между
клиентским браузером и веб-сервером. Такие данные не сохраняются браузе-
ром, однако и они могут быть перехвачены.
Flash не содержит собственной реализации протокола безопасности, а исполь-
зует поддержку шифрования, предоставленную браузером. Таким образом, при
вводе URL с префиксом протокола https: Flash использует для передачи данных
сервис HTTPS браузера (если он поддерживается). Следовательно, вы долж-
ны убедиться в том, что браузер пользователя поддерживает HTTPS, и вос-
пользоваться сервером HTTPS для шифрования всей передаваемой информации.
Например, так называемое поле ввода пароля, активизируемое как разновидность
текстовых полей с панели свойств, не обеспечивает безопасности. Оно про-
сто заменяет вводимые символы звездочками, но допускает пересылку пароля
на сервер в виде простого текста. Даже если читатель не знаком с безопасно-
стью пересылки данных, он должен понимать, что пересылка конфиденциаль-
ных данных (паролей, данных кредитных карт и т. д.) в виде простого текста по
открытому каналу создает огромный риск. Анализатор пакетов может легко
перехватить весь трафик между клиентом и сервером. Зашифрованная инфор-
мация тоже перехватывается, но ее не удастся прочитать с такой же легкостью,
как простой текст, поэтому перехват не принесет особой пользы злоумышлен-
нику.
Использование надстроек Flash (например, Flash Communication Server MX, или
FlashCom) также создает некоторые проблемы безопасности. Поток данных
FlashCom (аудио или видео) не может считаться безопасным, потому что небе-
зопасен протокол передачи данных (RTMP, или Real Time Messaging Protocol).
Тем не менее, приложения FlashCom могут использовать защищенный сервер
для обычной пересылки данных HTTPS. Безопасность FLashCom рассматривается
в статье «Macromedia Flash Communication Server MX Security Overview» по адре-
су http://wvvw.macromedia.com/devnet/mx/flashcom/articles/security_overview.html.
Недостаточная защита кода, работающего на стороне сервера, также создает уг-
розу для безопасности. При использовании технологии Flash Remoting разра-
ботчик пишет серверный код на различных языках, включая SSAS (Server-Side
ActionScript), поддерживаемый ColdFusion и JRun. Код SSAS, как и код многих
серверных сценарных языков, хранится на сервере в простых текстовых файлах;
файлы ActionScript Remote имеют расширение .asr. Но в конфигурации по умол-
чанию многие веб-серверы, в том числе Apache и Microsoft IIS, не включают
расширение .asr в список типов файлов, запрещенных к просмотру. Следова-
тельно, если пользователь введет URL файла с расширением .asr, он сможет
загрузить его и просмотреть код в виде простого текста! Это создает серьезную
брешь в системе безопасности, потому что некоторые разработчики ColdFusion
и JRun используют SSAS для запросов к базам данных или операций с файловой
системой на сервере. Прочитав содержимое файла .asr, хакер получит информа-
цию о структуре базы данных или файловой системы, которая упростит поиск
уязвимых мест вашей системы.
Безопасность 431

ПРИМЕЧАНИЕ
Разработчик Server-Side ActionScript должен настроить конфигурацию веб-сер-
вера так, чтобы файлы .asr не считались простыми текстовыми файлами.

Безопасность Flash - слишком обширная тема, чтобы ее можно было полностью


изложить на страницах книги, однако она неплохо документирована. На страни-
це Macromedia Flash Developer Center no адресу http://www.macromedia.com/devnet/
mx/flash/security.html находятся ссылки на дополнительные статьи, посвященные
безопасности Flash MX и Flash MX 2004 (Flash Player 6 и 7) и изолированной
зоне, в которой они работают (для предотвращения заражения вирусами, атак
типа «отказ в обслуживании» и т. д.).
Многие проблемы безопасности Flash присущи и другим веб-технологиям, од-
нако у Flash также имеются специфические аспекты:
• Flash Player 6 и 7 поддерживают загрузку данных с локально подключенного
микрофона или видеокамеры. Flash также может сохранять информацию на
локальном жестком диске, но объем такой информации может существенно
превосходить объем типичных браузерных файлов cookie. Параметры кон-
фиденциальности Flash позволяют ограничить доступ Flash Player к микро-
фону, камере и жесткому диску;
• для управления доступом из контента, принадлежащего одному домену, к кон-
тенту другого домена фирма Macromedia использует междоменные политики;
ш Flash может работать независимо от браузера в Standalone Player (см. раздел
«Локальные исполняемые файлы»).

Параметры конфиденциальности
Flash может получать доступ к потокам данных на локальном (клиентском) ком-
пьютере, в том числе и к данным с подключенного микрофона и видеокамеры.
Кроме того, Flash позволяет организовать локальное хранение информации
(см. трюк 44) с использованием класса SharedObject в так называемых объектах
LSO (Local Shared Objects).
Однако возможности получения ввода с микрофона или камеры, подключенной
к компьютеру, а также сохранения данных на жестком диске создают целый ряд
проблем из области конфиденциальности и безопасности. По этой причине Flash
Player должен иметь разрешение пользователя на выполнение любых действий,
способных повредить конфиденциальности. Такие разрешения предоставляются
на доменном уровне в окне Macromedia Flash Player Settings, показанном на рис. 12.1.

Macromedia Flash Player Settings


1 Privacy %
I Alow Iccel to access you? camera «rsrf
| mter-ophima'r'
# О Al lew Q ф Deny
! El Rememba* I Aavar c&d, . I

Рис. 1 2 . 1 . Диалоговое окно Flash Player Settings


432 Глава 12. Безопасность

Это окно появляется над воспроизводимым SWF-роликом в нескольких ситуа-


циях:
• взаимодействие с пользователем. Пользователь щелкает на SWF правой кноп-
кой мыши (Windows) или с нажатой клавишей §§ (Мае) и выбирает в контек-
стном меню команду Settings;
• по требованию контента. Flash Player отображает окно в том случае, если
работающий SWF-ролик пытается использовать любые средства, создающие
потенциальную угрозу для конфиденциальности пользователя (если ранее
пользователь не предоставил соответствующее разрешение для домена с ус-
тановкой флажка Remember);
• по вызову из ActionScript. Вызов System.showSettings(n), где п = О, 1,2 или 3,
открывает панель Settings на соответствующей вкладке: Privacy (0), Local Storage
(1), Microphone (2) или Camera (3). Если аргумент не указан, окно открывает-
ся на последней открытой вкладке. Например, окно может вызываться из
обработчика кнопки или перед попыткой сохранения локальных данных.
Диалоговое окно Settings содержит вкладки для управления параметрами конфи-
денциальности, локального хранения данных, микрофона и камеры. Дополнитель-
ные параметры Player настраиваются только на странице Settings Manager веб-сай-
та Macromedia (http://www.macromedia.com/support/documentation/en/flashpiayer/
help/settings_manager.html).
ПРИМЕЧАНИЕ
Settings Manager вызывается кнопкой Advanced на вкладке Privacy диалогового
окна Settings. На сайте Macromedia пользователь может задать глобальные и
доменные параметры, относящиеся к конфиденциальности, безопасности, хра-
нению данных и оповещениям об обновлениях.
В следующем листинге приводится базовый код для управления разрешениями
локального микрофона. Другие возможности Flash, в работе которых задейство-
ваны разрешения, реализуются несколько иначе, но общий принцип остается
тем же.
Предполагается, что на сцене размещено динамическое многострочное тексто-
вое поле с именем экземпляра myStatus. Для получения оптимального результа-
та проведите тестирование в браузере (команда File • Publish Preview • Default(HTML)
или клавиша F12).
1 function micPermissionO {
2 i f (myMic.muted) {
3 myStatus.text = "User denied permission.";
4 } else {
5 myStatus.text = "User gave permission.";
6}
7}
8 // Создание объекта Microphone и связывание его
9 // с текущей временной диаграммой.
10 var myMi с; Microphone = Microphone, get О;
11 this.attachAudio(myMic);
12 // Проверка свойства muted текущего микрофона
13 if (myMic.muted) {
Безопасность 433

14 myMic.onStatus = micPermission:
15 myStatus.text = "Either user will always deny access to the " +
16 "microphone, or user is looking at the Microphone Settings panel " +
17 "and function micPermissionО will soon run.";
18 } else {
19 myStatus.text = "User has already given permission.";
20 }
В строках 10 и 11 создается экземпляр Microphone (хотя Flash позволяет выб-
рать микрофон из списка, лучше воспользоваться приведенным кодом, который
выбирает микрофон по умолчанию).
Flash считает, что микрофон подключен к любому оборудованию, к которому
его можно подключить; в эту категорию входят все звуковые платы, обнаружен-
ные в системе. На большинстве компьютеров микрофон по умолчанию является
единственным подключенным микрофоном!
При обращении к микрофону методом Microphone.get() Flash автоматически от-
крывает окно Settings, если соответствующее разрешение ранее не было предос-
тавлено пользователем. При желании используйте вызов System.showSettings(2)
и откройте окно «вручную» (например, если вы предпочитаете выдать запрос к
пользователю в начале работы приложения, не дожидаясь, пока приложение по-
пытается обратиться к микрофону). Если пользователь ранее разрешил исполь-
зовать микрофон на вашем сайте, то свойство myMic.muted равно false, сценарий
выводит текст «User has already given permission», и микрофон оказывается дос-
тупным для Flash. Если же свойство myMic.muted равно true, то пользователь
либо еще не разрешил использовать микрофон, либо задал параметры конфи-
денциальности таким образом, чтобы доступ к нему с вашего сайта стал невоз-
можным. Если потребуется, Flash вызывает окно Settings, и программа ждет сме-
ны разрешения пользователем.
После закрытия окна Settings вызывается функция micPermission, и дальнейшая
работа программы зависит от значения свойства muted (true или false). Но если
пользователь уже запретил доступ к микрофону при предыдущем посещении
вашего сайта, то разрешение не дается и функция micPermission() не выполняется,
поскольку состояние остается неизменным. Программа завершается с выводом
сообщения в строках 15-17. В принципе, вы можете потребовать у пользователя
необходимое разрешение, вызвав окно Settings методом System.showSettings(2),
но лучше кратко объяснить, почему ничего не происходит, и затем предоставить
пользователю самому выбрать курс дальнейших действий.

Междоменная политика
Фирма Macromedia определила систему жестких правил (в терминологии Macro-
media - изолированная среда), управляющих взаимодействием SWF-файлов друг
с другом, а также исполняемыми файлами в Веб или на локальном жестком дис-
ке. Многие из этих правил в Flash Player 7 были ужесточены по сравнению
с предыдущими версиями (и многими другими веб-технологиями). Некоторые
сайты, нормально работающие в Flash Player 6, отказываются работать в Flash
Player 7 из-за дополнительных ограничений безопасности; за дополнительной
434 Глава 12. Безопасность

информацией обращайтесь к статье по адресу http://www.macromedia.com/devnet/


mx/flash/articles/fplayer_security.html.
Междоменная политика Macromedia определяет, может ли SWF загружать дан-
ные или обмениваться ими с другими SWF или контентом из других доменов.
В частности, для Flash Player 7 по умолчанию используется следующая политика:
• SWF не разрешается загружать другие SWF, не принадлежащие к тому же
домену;
• SWF не разрешается обмениваться данными с другими SWF (то есть исполь-
зовать класс LocalConnection), не принадлежащими к тому же домену;
• SWF не разрешается загружать ресурсы из других доменов.
Вы можете изменить политику по умолчанию и разрешить SWF взаимодействие
с другими доменами:
• В технической статье «Cross-Domain Policy» (http://moock.org/asdg/technotes/
crossDomainPolicyFiles) обсуждаются условия, приводящие к выдаче диалогово-
го окна с предупреждением при воспроизведении SWF формата Flash Player 6
в Flash Player 7 и сбоям при загрузке данных в SWF формата Flash Player 7.
• Техническая статья «Macromedia Flash Security Sandbox» (http://www.macro-
media.com/support/flash/ts/documents/security_sandbox.htm) посвящена изоли-
рованной зоне Flash Player 7 - «оболочке» Flash Player, которая ограничива-
ет доступ к приватным данным и предотвращает выполнение потенциально
небезопасных приложений.
• Техническая статья 16520 «Loading Data Across Domains» (http://www.macro-
media.com/support/flash/ts/documents/load_xdomain.htm) объясняет, какие опе-
рации разрешены или запрещены при попытках загрузки ресурсов из доме-
нов, отличных от того, в котором выполняется SWF.
• В технической статье 14213 «External data not accessible outside a Macromedia
Flash movie's domain» (http://www.macromedia.com/support/flash/ts/documents/
loadvars_security.html) рассматриваются ограничения на загрузку данных (обыч-
но с использованием класса LoadVars) из доменов, отличных от того, в кото-
ром выполняется SWF.
• Обработчик события LocalConnection.allowDomain() позволяет задавать другие
домены, из которых SWF может создавать локальные подключения к теку-
щему SWF.
• Метод System.Security.allowDomain() позволяет задать домены, которым раз-
решена загрузка вашего SWF-файла.
• Если Flash-ролик, передаваемый по протоколу HTTP, пытается обратиться
к защищенному контенту HTTPS, по умолчанию операция «тихо» заверша-
ется сбоем. В Flash MX 2004 появился метод System.Security.allowlnsecureDomain(),
при помощи которого SWF-файлы, опубликованные в формате Flash Player 7,
могут разрешать доступ HTTP/HTTPS (делать это не рекомендуется из-за
угрозы для безопасности HTTPS, но такая возможность может оказаться не-
обходимой для предоставления доступна к HTTPS-файлам, опубликованным
для Flash Player 7 и выше, из HTTP-файлов, опубликованных для Flash
Player 6).
Восстановление контента по SWF 435

• Веб-программа настройки Settings Manager вызывается кнопкой Advanced на


вкладке Privacy диалогового окна Settings. После перехода на сайт Macromedia
пользователь настраивает глобальные и доменные параметры, связанные с меж-
доменными политиками.

Локальные исполняемые файлы


Легкомысленное отношение к исполняемым файлам, принятым через Веб, быс-
тро приводит к нарушениям в работе системы. Чтобы Flash Player не мог выпол-
нить код, зараженный вирусом, среда ActionScript.находится под жестким конт-
ролем. SWF-файлу, выполняемому в модуле или элементе ActiveX Flash Player,
не разрешается запускать исполняемые файлы на компьютере пользователя (на-
пример, вызовом fscommand("exec")).
Тем не менее, SWF-файл, выполняемый в Standalone Flash Player, может запус-
кать внешние приложения вызовом fscommand("exec"), как описано по адресу
http://www. macromedia. com/support/flash/ts/documents/fscommand_projectors. htm.
Standalone Flash Player, как и любое настольное приложение, создает потенци-
альную угрозу для безопасности. Для снижения этого риска^ Macromedia разре-
шает выполнять функцией fscommand("exec") только те файлы, которые хранят-
ся в подкаталоге FSCOMMAND (с произвольным регистром символов) каталога,
содержащего Standalone Flash Player.
Теперь, когда вы получили представление о проблемах безопасности при ис-
пользовании Flash, мы переходим к трюкам, которые помогут защитить контент
(см. трюк 98) от наиболее вероятных видов атак (см. трюк 97).

ТРЮК Восстановление контента по SWF


№97 SWF-файлы могут быть «взломаны» специальными программами, назы-
ваемыми декомпиляторами SWF. Используйте эти программы для вос-
становления контента при утрате исходного документа FLA.
Представьте, что вам поручено обновить Flash-сайт. Если вы занимались его раз-
работкой и своевременно позаботились об архивации, все исходные файлы ока-
жутся в вашем распоряжении. К сожалению, на практике такое бывает нечасто.
Прежде чем переходить к методам защиты SWF от кражи контента (см. трюк
98), рассмотрим несколько ситуаций, в которых декомпиляция SWF оправдана
законными целями.
Возможно, вы не располагаете последними версиями исходных файлов, потому что:
• клиент внес свои изменения в предоставленную версию. В этом случае вам
нужна последняя версия как отправная точка для дальнейшей работы;
• разработкой занимался другой специалист, который покинул мультимедий-
ное программирование и отправился делать карьеру в Голливуде;
• клиент предусмотрительно затребовал FLA-файлы по условиям контракта,
но системный администратор посчитал, что эти файлы все равно лежат где-
нибудь на сервере, и удалил все, что ему показалось лишним. Теперь он
436 Глава 12. Безопасность

говорит: «Подумаешь, ведь вы все равно можете загрузить исходные тексты


с сервера, верно?» К сожалению, нет;
• вы занимались исходной разработкой сайта, но с тех пор успели дважды пе-
реехать в новый офис, а последний компакт-диск с архивом, который вам
удалось найти, содержит неполную или старую версию сайта. Или вы запако-
вали все файлы, включая JPEG и МРЗ, в ZIP-файл, но весь архив был испорчен,
а его содержимое не подлежит восстановлению.
Так что на практике нередко приходится работать, располагая только имеющи-
мися на сервере файлами SWF и HTML. Восстановить полный файл FLA уже
не получится, поскольку в процессе компиляции в SWF Flash удаляет суще-
ственные части содержимого FLA. И все же не исключено, что восстановить
проект на базе декомпилированных данных будет проще, чем начинать все с са-
мого начала.

П
ПРИМЕЧАНИЕ
Если при сохранении SWF-файла не был установлен флажок Protect from Import
(File • Publish Settings • Flash), файл можно открыть прямо в среде Flash. Это
хорошо для тех, кто пытается восстановить потерянный контент, и плохо для
тех, кто пытается скрыть свой контент от других (см. трюк 98).

Хотя ничто не мешает вам написать собственную версию декомпилятора на базе


описания формата SWF, в настоящее время существует несколько декомпилято-
ров (как бесплатных, так и коммерческих). Вот лишь некоторые из них:
• ActionScript Viewer (http://buraks.com/asv) - самый первый, весьма уважае-
мый декомпилятор;
• Flash Decompiler (http://www.flash-decompiler.cpm) - как утверждается в опи-
сании, быстр и прост в использовании;
• Sothink Decompiler (http://www.srctek.com/flashdecompiler) - обеспечивает под-
держку ActionScript 2.0 и инструмент SWF Catcher для извлечения файлов
из кэша браузера;
• Flare (http://www.nowrap.de/flare.html) - бесплатный декомпилятор, работаю-
щий в системах Windows, Linux и Mac OS (также доступны версии режима
командной строки). Версия для Windows поддерживает декомпиляцию из
контекстного меню, вызываемого правой кнопкой мыши.
Декомпилятор анализирует байт-код SWF-файла и извлекает фрагменты про-
граммного кода в исходные файлы или переводит их в форму, которая снова
сделает возможным их редактирование.
Работа с декомпилятором будет рассматриваться на примере ActionScript Viewer
(ASV). Бесплатная пробная версия ASV 3.0 загружается с сайта http://buraks.com/
asv. Пробная версия ограничена по функциональности: она декомпилирует толь-
ко первые 5 кадров каждой временной диаграммы и первые 25 строк каждого
сценария и не поддерживает Flash 7 (в последней полной версии, ASV 4.0, такая
поддержка присутствует). Тем не менее, она позволяет составить представление
Восстановление контента по SWF 437

о процессе декомпиляции и о том, что вы можете (и не можете) сделать. Даже


если SWF-файл был защищен от импортирования, ActionScript Viewer позволя-
ет сбросить флаг защиты (вкладка Special Tags), что дает возможность импорти-
ровать файл в Flash.

Интерфейс ASV 3.0


Если открыть SWF-файл в ASV, вы увидите окно, примерный вид которого по-
казан на рис. 12.2. Впрочем, вкладок может быть меньше, потому что некоторые
вкладки оказываются не подходящими для текущего SWF.

\Docunwnts and

;ripU Special Tags}


sMoi J,JU:<™L •: Wo
T Symbol 25 Text : "Demo Level to.
C5 31 fjjja Symbol 24 Button ! ! [starLbtn]
i f Symbol 22 EditableText : (gameScore) "0..
gameLoop C?28 111 Symbol 20 MovieClip . [lifeO3] 5 frames
BM Я Symbol 18 MovieClip [back] 1 frames

function soundtrack () {
soundtrack_snd. attachS ound(nextLoop); Property [Value
soundtrack snd.start(0,1);
} Timeisec.) 0.00
start_btn.onFielease = function () { | Has frame actions; yes
playQ; I Has clip actions no
Has start sound i no
soundtrack_snd = new Sound (this); Has sound strea... yes
nextLoop = "tracki"; Has sound strea... no
soundtrackQ;
soundtrack_snd.onSoundComplete = soundtrack;
gameScore = 0;
flash = new Color (back);

Рис. 12.2. Интерфейс ActionScript Vjewer 3.0

Выбор настроек чрезвычайно широк, но для получения FLA необходимо выпол-


нить всего три операции:
• извлечь листинги ActionScript;
• просмотреть временную диаграмму вместе с содержимым каждого ключевого
кадра. Вы также должны знать все имена экземпляров;
• извлечь содержимое библиотеки вместе со всеми идентификаторами компо-
новки.
Все три операции кратко описаны в следующих разделах.
438 Глава 12. Безопасность

Извлечение ActionScript
Чтобы просмотреть весь код ActionScript, содержащийся в SWF, перейдите на
вкладку ActionScripts (рис. 12.3) и выделите любой из сценариев, перечисленных
на панели. Код отображается в левом нижнем углу. Чтобы сохранить сценарий
в виде текстового файла, выполните команду Utility • Save ActionScript (as Text).
Если окно Flash открыто в настоящий момент, код ActionScript также можно
скопировать из ASV в буфер и вставить в открытый документ FLA.

n l M M J L J

Jjmeline | Fj;ames j L'brary ] instance names j


Type I Location Е ' а т е N o ! Instance of
I:.frame action P;.Timeline::
*' Frame action £3 Timeline
Щ} Frame action Щ Timeline
Ф) Frame action Symbol 16 MovieCI..

function soundtrack () {
soundtrack_snd. attachS ound(nextLoop);
souridtrack_snd.r.^""'""'*A
} i Щ\ Copy Actionscript (as Text) FS
start_btn.onReleasi
у ' UFj Change Actionsaript Font
soundtrack_snd - ij |jp show Long Actronscripts Ctrl-КЗ
»un*acku- ' a C i I I W o r d w a * > Actionscripts Ctrl +W
soundtrack_snd.orH||j Colorize Actionscripte Ctrl+Alt+Z
fff^JtshowA^ons.a.P-code FH
1- Force Flash 5 Mode FS

Рис. 12.3. Вкладка ActionScripts в окне ActionScript Viewer 3.0

Просмотр исходной временной диаграммы


Перейдите на вкладку Timeline и просмотрите реконструированную временную
диаграмму (рис. 12.4).
На первом слое временной диаграммы показаны все метки кадров и код Action
Script, связанный с кадрами. ASV воссоздает остальные слои так, как в его пред-
ставлении выглядят слои контента, необходимые для реконструкции работаю-
щего FLA. Временную диаграмму можно экспортировать в виде серии SWF-ро-
ликов (по одному на каждый реконструированный слой). Простые слои, не
содержащие кадрированной анимации или большого количества ключевых кад-
ров, разумнее всего просто воспроизвести в новом документе FLA. В этом слу-
чае необходимо знать имена всех экземпляров на временной диаграмме. Список
имен можно просмотреть на вкладке Instance Names (если списка нет, это зна-
Восстановление контента по SWF 439

чит, что имена экземпляров не использовались, - ситуация типична для SWF,


не содержащих сценарного кода).
ASV не может восстановить исходные слои временной диаграммы и имена сим-
волов библиотеки, существующие в FLA только в процессе разработки. Деком-
пилятор пытается реконструировать недостающую информацию и использует
имена вида Symbol 23 или Layer 6. Слои, не содержащие контента в исходном
документе FLA (в том числе опорные слои и папки), не экспортируются в SWF,
поэтому декомпилятор не сможет их восстановить.
• • • • • • • • • • • • • . : . • : . • . • • • • : • • - , : • • : . . • . . : • • : , . : . •

s \ S h e u n B V

Jimeline: I Frames j library J Instance names j Frame Labels j Actionscripts. j ^


. £ -

3-е 4J

Щм

A3

Proper^ value
Swf version 6
Width 480
Heg i ht : 300
Fiarnerate : 18
Frame count 1 5

atwwwwwwwww^
Рис. 12.4. Вкладка Timeline в окне ActionScript Viewer 3.0

Экспортирование библиотеки
Чтобы экспортировать библиотеку, перейдите в ASV на вкладку Library (рис. 12.5),
щелкните правой кнопкой мыши (Windows) или щелкните с нажатой клавишей
J§ (Mac) на любом символе и выберите в контекстном меню команду Save all
Library Symbols as SWF.
Символы SWF импортируются в Flash командой File • Import • Import to Library.
После импортирования символам следует присвоить осмысленные имена и вруч-
ную определить для них идентификаторы компоновки (которые не экспортиру-
ются из ASV, хотя и отображаются в квадратных скобках на вкладке ASV Library
рядом с каждым именем символа).
440 Глава 12. Безопасность

\Щ zJiffife JLF Mil] MMJM


Faimes Lb
irary ; l^tance names ] Frame Labe?l j ado
imcnph | speca
il Tags ]
г Wra - - Й Uses
1 frames 48
T
TSSyym
mb
bo
oll 4
46
7TTeenxtt
Щ Open in Slew Window Special
^ Open in New Window
Ctrl+й
Shift+Ctrl +N
e
Й Symbol 48 MovieClip \ Trace in Timdine 0 3... \ Timetin
T | Symbol 49 E ditableTj (\ Trace in Frames
j Save as Swf
Hex View

TaglD DefineShape (2)


Data Size 50 bytes
Defined in frame 5 ;;.„..
Shape record c... G !*•

Рис. 12.5. Вкладка Library в окне ActionScript Viewer 3.0

Итоги
Хотя для больших или сложных SWF процесс декомпиляции занимает много
времени, это все равно быстрее, чем начинать нуля. Вам удастся восстановить из
SWF два самых важных ресурса: ActionScript и символы библиотеки. Даже если
ничего больше извлечь не удастся, все равно достигается существенная эконо-
мия времени.
Также декомпиляция SWF применяется для определения точной структуры SWF
и проверки оптимальности размера файла. Более того, декомпиляция поможет
лучше понять общие принципы работы контента Flash и осознать, какие именно
данные использует Flash Player.
Конечно, декомпиляция также позволяет красть ваш контент или (что более
вероятно) тайком заимствовать творческие идеи.
Открытие SWF в декомпиляторе или редакторе кода (таком, как URL Action
Editor - http://buraks.com/uae) дает злоумышленнику еще больше шансов для
похищения вашей работы, чем при использовании обычных технологий HTML:
• Flash SWF содержат большую часть контента вашего сайта в минимальном
количестве файлов, а это упрощает поиски;
• создание мультимедийных ресурсов обычно обходится дороже, чем создание
статических веб-страниц. Для создания аудио/видео, графики и сценари-
ев, содержащихся в вашем Flash-творении, необходимы более богатые спо-
собности, чем для создания HTML-страниц, состоящих из простой графики
и текста;
Защита и шифрование файлов Flash 441

• Flash-сайты обычно предоставляют больше возможностей для настройки, чем


стандартные HTML-страницы. Немного изменив код, содержащийся в SWF,
похититель контента может быстро изменить внешний вид краденого сайта.
Я видел немало подозрительных сайтов, которые выглядели так, словно ди-
зайнер просто скопировал символы и сценарии из двух или трех хорошо из-
вестных Flash-сайтов, а затем объединил их для создания чего-то «нового»!
Наличие инструментария и возможностей для декомпиляции SWF-файлов час-
то ставит дизайнера перед моральным выбором. Если разработчик не выложил
FLA-файлы для открытого доступа, скорее всего, он не захочет, чтобы вы деком-
пилировали его код, хотя для чисто исследовательских целей это может оказать-
ся не запрещено. Если вы знакомитесь с работой других разработчиков в поис-
ках вдохновения (как во многих трюках этой книги!), достаточно воспроизвести
SWF в Flash Player. Воспроизведите исходную работу вместо того, чтобы при-
своить чужой труд без разрешения автора.
Помните: если клиент присылает вам SWF-файлы и говорит, что ему не удалось
получить FLA от разработчика, вы вправе запросить дополнительную информа-
цию. Возможно, в контракте разработчика было сказано, что исходные файлы
FLA не входят в поставку. Присвоение труда исходного разработчика может
кончиться судебным иском за нарушение авторских прав. Как минимум, поста-
райтесь убедиться в том, что клиент обладает правами на FLA-файлы, особенно
если он не располагает их копиями. Также проследите за тем, чтобы в контракте
на разработку вся ответственность за нарушения авторских прав в передавае-
мых материалах была возложена на заказчика.

ТРЮК Защита и шифрованиефайлов Flash


№98 Если кражу или декомпиляцию Flash-контента нельзя предотвратить пол-
ностью, ее можно по крайней мере затруднить.
К сожалению, дизайн сайта, в который разработчик вложил столько труда, не
защищен от кражи (см. трюк 97). Например, URL Action Editor (http://buraks.com/
uae) позволяет изменить аргументы любых операций с URL, используемых в SWF.
Злоумышленник может взять SWF-файл, загружающий ваш контент, и перера-
ботать его так, чтобы он загружал его контент - или, что еще хуже, выдать за
собственную разработку.
Известен по крайней мере один доказанный случай, когда известный дизайнер
декомпилировал код другого известного дизайнера и выдал его за свой собствен-
ный (совет вору: в следующий раз изменяйте имена переменных!).

Защита SWF
Среда разработки Flash позволяет любому желающему загрузить незащищен-
ный SWF-файл. Вообще говоря, SWF можно защитить от импортирования в Flash,
установив флажок Protect from Import (File • Publish Settings • Flash). Тем не менее,
файл может быть открыт в другом приложении (например, в текстовом редакторе),
442 Глава 12. Безопасность

а программы-декомпиляторы типа ActionScript Viewer (http://buraks.com/asv) мо-


гут сбросить флаг защиты и сделать возможным импортирование в Flash. Сжа-
тие SWF (File • Publish Settings • Flash • Compress Movie) помогает скрыть работу
от посторонних, поскольку сжатые данные труднее декодировать, чем обычный
формат SWF.
Технологическая защита никогда не бывает абсолютной. Умный взломщик спо-
собен вскрыть любую схему, если у него будет достаточно времени. Следова-
тельно, мы должны поставить на его пути столько препятствий (каждое из кото-
рых запутает решение и потребует лишнего времени), чтобы злоумышленник
просто отказался от своей затеи.
В играх и коммерческих приложениях часто используются схемы защиты, кото-
рые считаются неуязвимыми, но, похоже, это лишь разжигает азарт взломщи-
ков. С другой стороны, браузерный модуль Flash Player в конечном счете дол-
жен отображать контент SWF. Следовательно, опубликованные SWF окажутся
на компьютере пользователя в незашифрованном виде, даже если они были по-
лучены с защищенного сервера HTTPS. Даже если бы браузеры поддерживали
воспроизведение шифрованных данных, изобретательный взломщик мог бы пе-
рехватить графику, передаваемую видеоадаптеру, или аудиопоток, передавае-
мый на звуковую карту.
Итак, первый прием - маскировка. Мы постараемся отбить у хакера желание за-
ниматься взломом или продлить его работу, скрывая схему защиты, вместо исполь-
зования очевидного механизма, претендующего на стопроцентную надежность.

Маскировка типов файлов


Все файлы нашего сайта в конечном счете окажутся в кэше браузера на компьюте-
ре взломщика. Если хакеру потребуется найти SWF- или МРЗ-файл, ему доста-
точно провести поиск файла с нужным именем. Чтобы затруднить взлом даже
на этом начальном этапе, измените расширения и имена критических файлов.
Для примера возьмем загрузку ресурсного файла МРЗ во время выполнения
программы:
my_sound = new Sound(this);
my_sound.loadSound ("song.mp3". true);
Допустим, мы пишем музыкальный проигрыватель на базе Flash для студии зву-
козаписи. Чтобы хакер не мог найти файл МРЗ и сразу выложить его в каталог
обмена файлами Napster/WinMX, просто задайте файлу какое-нибудь невразу-
мительное имя (например, top_header_02.gif) и приведите код к следующему виду:
my_sound = new Sound(this):
my_sound.loadSound ("top_header_02.gif". true):
Flash игнорирует расширения при загрузке внешних файлов (предполагается,
что загружается именно звуковой файл независимо от имени и расширения, пе-
реданных методу Sound.loadSound()). Если операционная система взломщика не
проверяет соответствие между содержимым файла и его расширением (а послед-
ним из моих компьютеров, поддерживавших такую возможность, был Commodore
Amiga!), на определение истинного типа файла потребуется время.
Защита и шифрование файлов Flash 443

Вероятно, читатели с опытом традиционного веб-дизайна уже ухмыляются, осо-


знав'всю гнусность этого трюка, но на всякий случай я объясню подробнее.
Просматривая содержимое кэша браузера, хакер видит файл top_header_02.gif.
Дальше происходит следующее:
• вполне вероятно, что он даже не станет заглядывать в этот файл, потому что
его имя подразумевает банальный срез GIF для таблицы HTML;
• если он все же решит открыть файл, программа просмотра GIF сообщит, что
содержимое файла испорчено. На этой стадии многие отказываются от даль-
нейших разбирательств.
Если хакер начнет просматривать доменные и временные характеристики каждого
файла в кэше или сохранит всю веб-страницу вместе с внедренными материала-
ми (в IE это делается командой Файл • Сохранить как (File • Save As)), он может
заподозрить, что дело неладно. Но даже после того как трюк будет раскрыт,
злоумышленник не сразу поймет, что под псевдо-GIF-файлом спрятан замаски-
рованный МРЗ-файл. Смена расширения собьет с толку хакера и его операцион-
ную систему. Чтобы найти контент для похищения, ему придется открывать
каждый файл на сайте или декомпилировать SWF и искать команды loadSound().
Если вы не стесняетесь в средствах, воспользуйтесь трюком «с темной стороны» -
превратите маскируемые файлы в файлы системных типов, которые при двой-
ном щелчке могут нарушить работу операционной системы хакера. Система
Windows обычно предупреждает пользователей, изучающих содержимое кэша
браузера, что двойной щелчок на файле может привести к печальным послед-
ствиям, поэтому можно считать, что ваша жертва была честно предупреждена.
Естественно, некоторые приемы не работают в Mac OS, но смена расширения
файла запутает хакеров, работающих на обеих платформах.

ПРИМЕЧАНИЕ
При использовании этого трюка храните информацию о настоящем типе каждо-
го файла. Храните «фальшивые» файлы для размещения на сайте отдельно от
файлов, задействованных в разработке. Не забудьте выработать политику ар-
хивирования, потому что однажды защита может обернуться против вас, если
вам потребуется декомпилировать SWF.

Итоги
Нет ничего плохого в том, что кто-то будет черпать вдохновение в вашей работе.
Даже если вас это не устраивает, у вас нет никаких юридических и практических
средств помешать этому. Вы можете запатентовать свое выражение идеи, но не
саму идею. Большинство идей имеет слишком общий характер, чтобы стать объек-
тном патентной защиты, а оформление патента требует слишком больших зат-
рат времени и средств. Наконец, во многих случаях даже патент не обеспечит
реальной защиты. Малоизвестная разновидность патентов (так называемые ди-
зайнерские патенты) защищают дизайнерские решения - скажем, форму и по-
лупрозрачность корпуса исходного варианта iMacs. Но даже юридический отдел
Apple не смог помешать производителям PC имитировать дизайн продукта.
444 Глава 12. Безопасность

Теоретически, контент пользуется юридической защитой с момента его перево-


да в материальную форму, и вы можете зарегистрировать свое авторское право
ради дополнительной прибыли; но обеспечить соблюдение авторских прав в та-
кой международной среде, как Веб, практически невозможно. К тому же в боль-
шинстве случаев злоупотребления Flash-дизайном отсутствует доказанный эко-
номический ущерб от нарушения авторских прав, поэтому не стоит кричать:
«Караул, грабят!» - и надеяться на возмещение убытков.
Более правильный путь - технологический с небольшой долей социотехники.
Если хакер хочет сэкономить время за счет использования ваших ресурсов, за-
трудните кражу контента до такой степени, чтобы она стала экономически невы-
годной.

ТРЮК Привязка к сайту


№99 Защитите свой контент так, чтобы он отображался только на вашем сай-
те, — привяжите его к конкретному местоположению.
Если хакер найдет ваш SWF-файл (см. трюк 98), то перед декомпиляцией
(см. трюк 97) он наверняка попытается запустить его на локальном компьютере
и посмотрит, что при этом произойдет. Запрет на загрузку контента из других
доменов в Flash Player всего лишь заставит хакера изменить все URL в SWF-
файле (а это и так первое, что он сделает в процессе переработки вашего сайта).
Если запуск SWF будет возможен только из конкретного места (то есть с вашего
сервера), хакеру по крайней мере придется потратить время на взлом защиты.
Свойство MovieClip._url сообщает SWF-ролику, откуда он был запущен. По его
значению программа может узнать, был ли ролик запущен из положенного мес-
та, то есть из вашего домена, или же он запускается локально (Это может свиде-
тельствовать о том, что кто-то пытается полностью или частично модифициро-
вать SWF). Так, после выполнения команды
var myLocation = this._ur1:
в переменной myLocation хранится URL, если SWF запускается из Веб (например,
http://www.futuremedia.org.uk/test/test.swf), или локальный путь к файлу в случае
локального запуска (например, file://C:\Documents and Settings\Sham B\Desktop\
test.swf). Если содержимое myLocation отличается от предполагаемого, выполня-
ются соответствующие защитные действия.

Сбой при загрузке SWF


При обнаружении цикла, выполняющего большое количество итераций в тече-
ние более 15 с, Flash Player прерывает выполнения сценария (или выдает пре-
дупреждение и предлагает завершение при тестировании ролика в среде раз-
работки Flash). Следующий фрагмент переводит SWF в бесконечный цикл при
запуске из другого места:
myLocation = this._url;
i f (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {
do {
Привязка к сайту 445

// Бесконечный цикл
} while (true);
}
При такой защите хакеру будет труднее разобраться в том, что делает SWF.
Чтобы происходящее стало еще более непонятным, добавьте длинные задержки,
при которых диалоговое окно с предупреждением не выдается, но создастся ил-
люзия «зависания» SWF. В следующем листинге функция задержки будет вы-
полняться каждую миллисекунду:
myLocation = this._url:
i f (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {
II Вызывать функцию задержки каждую миллисекунду
setlnterval (delayMe. 1);
}
function delayMeО {
// Выполнить 10 000 итераций просто для замедления работы Player
for (var i = 0; i < 10000: i++) {
x = Math.randomO;

Переход на другой сайт


Если SWF выполняется из недопустимого места, также можно воспользоваться
функцией getURL() для перехода на домашний сайт. Заметив это, хакер, вероят-
но, поймет, что переход осуществляется функцией getURL(), и начнет искать строку
URL в какой-нибудь специализированной программе вроде-URL Action Editor
(http://buraks.com/uae). Впрочем, на это понадобится время. Чтобы затруднить
работу хакера, напишите код так, чтобы переход происходил только в отдельных
случаях по принципу: «Если SWF запускается из незнакомого места и сегодня
четверг, перейди на домашний сайт функцией getURL()». Хакер будет считать,
что его злодеяние прошло успешно... пока не наступит четверг. Для пущего эф-
фекта можно перейти на какой-нибудь порнографический сайт, чтобы вору при-
шлось объясняться с заказчиком.
В следующей программе переход по адресу http://www.futuremedia.org.uk/test/test.swf
(нет, это не порнографический сайт!) выполняется в случае, если текущий SWF
находится не на этом сайте, а текущим днем недели является четверг (4 - код
четверга в возвращаемых значениях метода Date.getDayO). Обратите внимание
на малопонятные имена переменных. В идеальном случае переменные р, q, r и s
должны определяться в другом месте, чтобы происходящее стало еще туманнее:
var p:String = this._url;
var q:String = "http://www.futuremedia.org.uk/test/test.swf";
var г-.Date = new DateO;
var s:Number = 4:
i f (r.getDayO == s) {
i f (p != q) {
getURL(q):
44В Глава 12. Безопасность

Перекрестная защита
Хакеру гораздо проще работать с одним файлом, чем разбираться с сайтом, раз-
деленным на несколько SWF, - особенно если вы также присвоите фиктивные
имена некоторым из SWF (см. трюк 98) и привяжете их к конкретному серверу.
Также попробуйте разместить код защиты в другом SWF, отличном от защища-
емого (я называю это перекрестной защитой). Например, включите следующий
код в SWF, загружаемый главным SWF:
myLocation = levelO._url;
i f (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {
do {
} while (true):
}
Попробуйте разместить логику защиты в постороннем SWF, не представляю-
щем интереса для хакера. Например, включите ее в SWF-файл с контентом вме-
сто основного SWF-файла с фирменным пользовательским интерфейсом, чтобы
защиту было труднее найти.
Запускайте код защиты по интервальному таймеру, установленному функцией
setlntervalQ (вместо того чтобы запускать его сразу же после загрузки SWF).
Хакеру будет труднее найти этот код, потому что он не сразу поймет, какой из
загруженных SWF содержит код защиты. Пример:
function test О {
clearlnterval(m);
var myLocation:String = JevelO._url;
i f (myLocation != "http://www.futuremedia.org.uk/test/test.swf") {
do {
} while (true):

var m:Number = setlnterval(test. 30000):


Схема защиты обычно реализуется на последней стадии цикла разработки, чтобы
программист мог спокойно работать над основным SWF без хлопот с защитой.

Итоги
Сразу же после появления декомпиляторов SWF появился целый поток сайтов-
двойников и примеров FLA, подозрительно напоминавших ранее не публико-
вавшийся код. Примите необходимые меры, чтобы ваша работа не попала в по-
сторонние руки!
Разработчики Flash часто спрашивают, как защититься от клиентов, которые
«забывают» заплатить после получения всех материалов по контракту. Один из
стандартных способов - удержание исходных FLA-файлов до получения опла-
ты (клиент получает SWF для размещения на сайте, но и разработчик получает
частичную страховку). Обычный трюк с проверкой местоположения в таких си-
туациях не применим, потому что SWF будет запускаться с клиентского сайта,
но вы можете разместить XML-файл на удаленном сервере, находящемся иод
Просмотр откомпилированного кода ActionScript 447

вашим контролем. Flash-ролик (на сервере клиента) проверяет удаленный XML-


файл при каждой инициализации. Это дает возможность разработчику «отклю-
чить» приложение сбросом флага в XML-файле, если клиент не заплатит в срок.
Тем не менее, такие схемы проверки могут противоречить контракту на разра-
ботку, а в случае их нарушения у вас могут быть крупные неприятности. Напри-
мер, если SWF не сможет получить доступ к удаленному серверу с XML-фай-
лом из-за обычного сбоя на сервере, сделайте так, чтобы SWF по умолчанию
работал без файла. Применяйте подобные «бомбы замедленного действия» крайне
осторожны, и обязательно передайте «чистую» версию SWF и/или FLA сразу
же после того, как клиент с вами рассчитается.

Просмотр откомпилированного кода


ТРЮК

№100 ActionScript
Анализ откомпилированного кода способствует низкоуровневой оптими-
зации и разработке общего стиля кодирования, направленного на опти-
мизацию.
Декомпилятор SWF восстанавливает исходный код ActionScript (см. трюк 97)
на основании байт-кода в SWF.
Декомпиляторы SWF помогают восстановить (или украсть!) исходный код
ActionScript, но в некоторых ситуациях - например, при оптимизации кода по
скорости или размеру - требуется просмотреть откомпилированный байт-код.
Утилита Flasm, распространяемая с открытыми исходными текстами (http://
flasm.sourceforge.net), предназначена для просмотра байт-кода, полученного в ре-
зультате компиляции ActionScript.
Не путайте Flasm с декомпиляторами, это совершенно разные программы. Flash
предназначается для настоящего эксперта ActionScript, желающего оптимизиро-
вать свой код. Кроме того, эта программа поможет узнать, как выглядит ваш код
к тому моменту, когда он попадает в Flash Player. В документации Flasm доста-
точно подробно описан процесс обработки откомпилированного кода ActionScript
виртуальной машиной Flash в Flash Player; полагаю, читатель найдет этот мате-
риал как интересным, так и поучительным.
Последняя версия Flasm (версия 1.51) поддерживает формат Flash MX 2004.
Полезно сравнить методику оптимизации кода Flash Player 7 по сравнению с Flash
Player 6 (если, конечно, этот код работает быстрее предыдущей версии) - это
поможет вам писать хорошо оптимизируемый код. Flasm - не экзотическая ди-
ковинка для хакеров, а действительно полезный инструмент.

Flasm

Flasm (FLash ASseMbler) - бесплатный компилятор и декомпилятор SWF. Его


исходная версия была написана Дэйвом Хейденом (Dave Hayden) (http://www.opa-
que.net) и Дэмианом Мортоном (Damian Morton), а в настоящее время разработ-
ку и сопровождение ведет Игорь Коган (Igor Kogan).
448 Глава 12. Безопасность

Flasm работает в режиме командной строки, поэтому вам придется либо исполь-
зовать режим командной строки (Windows), либо открыть окно терминала (Мае).
Шариф Айна (Shariff Aina) написал пользовательский интерфейс для Windows,
который называется WinFlasm; его текущий URL можно найти в документации
Flasm или на сайте http://flasm.sourceforge.net. Для простоты мы будем исполь-
зовать его в данном трюке.
Чтобы установить Flasm, загрузите ZIP-файл и распакуйте его в каталог по сво-
ему выбору. WinFlasm распаковывается из архива в один каталог с Flasm. К со-
жалению, пользователям Мае придется работать в режиме командной строки.
Документация Flasm содержит более подробные инструкции об интеграции Flasm
в среду разработки Flash. Эта информация пригодится разработчикам, интере-
сующимся созданием высокооптимизированного кода.
После компиляции SWF-файла в среде разработки Flash запустите WinFlasm и
откройте SWF-файл для просмотра Командой Open.
Выберите операцию при помощи переключателей на нижней панели (рис. 12.6).

Open About

SWF File |c,«ve01.swf

;;:: :;Г;: -и;-; ШЙаШЬе SWF;; replaeella|m;roacros ;•§

j Execute .;

• Grig.;filesize =:-:523 Bytes

Рис. 12.6. Интерфейс WinFlasm

Я обычно выбираю операцию декомпиляции с прямым редактированием (Decompile


and Edit Directly), которая, несмотря на свое название, отображает откомпилиро-
ванный SWF. Щелкните на кнопке Execute, чтобы открыть откомпилированный
SWF-ролик в WordPad (рис. 12.7).
Просмотр откомпилированного кода ActionScript' 449

secMensbsr
push riS, "сп£.е1еазе'
function2 () (ril^'this1)
push 0.0, r:this, 'stcpDrag'
callMethod
pop
pasis r:tfcis, ' oisHouaeMove •
delete
pop
end // of function
secMensber
push r:2
return ii
end // of function drawPip
functicn2 drawCurve (r:3='pointi', r:2»'point2', r:4=•curvePoinc'
push 0.0> r:thia, 'clear*
callMethod
pep
push 102, 14530253, 1, 3, r:chia, 'lineStyle'
callKetfcod
pep
push r:poi nt1, " у'
gecMensber
push rrpointl, "jt1
geeMeraber
push 2, r:this, 'rooveTo'
cellMethod

ж
Рис. 12.7. Откомпилированный файл ActionScript в WordPad

Работа с откомпилированным кодом


Листинг откомпилированного кода - самый надежный источник информации
об итоговом коде, используемом Flash Player на стадии выполнения. Код Action
Script в документе FLA преобразуется в поток байтов, называемый байт-кодом.
Преобразование уменьшает объем программного кода за счет замены методов
более короткими лексемами, а также раскладывает сложные операции на более
простые, понятные для Flash Player.
Любой программист с опытом программирования на ассемблере заметит, что
внутренняя архитектура виртуальной машины Flash Player сильно напоминает
архитектуру старых 8-разрядных процессоров. Она включает стек, в который
обрабатываемые значения (используемые при сложении, вычитании и т. д.) за-
носятся перед обработкой, с последующим извлечением результата из стека.
Таким образом, Flash Player использует стековые операции вместо обращений
к абсолютным адресам памяти. Промежуточные значения хранятся в регистрах.
450 Глава 12. Безопасность

Использование регистровых данных существенно ускоряет сложные или итера-


тивные вычисления.

Работа с Flasm
Рассмотрим пример использования Flasm для получения эффективного кода с мо-
дульной структурой. Однажды мне захотелось узнать, как применение функций
отражается на общем быстродействии. Хотя вызовы функций улучшают струк-
туру программы, у меня были некоторые сомнения относительно целесообраз-
ности их применения в участках кода, критических по быстродействию, - здра-
вый смысл подсказывал, что вызов функции сам по себе требует дополнительного
времени. Так или иначе, я решил, что эту тему стоит поподробнее исследовать
в Flasm.
Возьмем фрагмент кода без вызова функций:
var х = 5:
var у = 6:
var z = х*у;
trace(z);
Flasm выдает следующий байт-код Flash Player 7:
frame 0
constants 'x', 'у', 'z'
push 'x', 5
varEquals
push 'y'. 6
varEquals
push 'z', 'x'
getVariable
push 'y'
getVariable
multiply
varEquals
push 'z'
getVariable
trace
end //of frame 0
При использовании системы типизации ActionScript 2.0:
var x:Number = 5;
var у:Number = 6:
var z:Number = x*y;
trace(z):
результат был бы точно таким же. Из этого можно сделать вывод, что типизация
не приводит к снижению быстродействия или увеличению размера файла (и это
вполне логично, поскольку проверка типов осуществляется на стадии компиля-
ции, а не во время выполнения). На моем компьютере обе версии, типизирован-
ная и нетипизированная, выполнялись примерно в течение 0,06 мс (без команды
trace(), поскольку операции вывода обычно выполняются довольно медленно).
Просмотр откомпилированного кода ActionScript • 451

Хронометраж осуществлялся кодом следующего вида (мы проводим 1000 итера-


ций для получения средней скорости):
// Измерение продолжительности самого цикла
startTime = getTimerO;
for (var i = 0; i < 1000; i++) {}
endTime = getTimerO;
measureTime = endTime - startTime;

// Измерение продолжительности цикла с простым кодом


startTime = getTimerO;
for (var i = 0; i < 1000; 1++) {
// Тестируемый код
}
endTime = getTimerO:
codeTime = endTime - startTime - measureTime;
trace(codeTime/1000):
В следующей версии та же операция выполняется с использованием функции:
function multiplyO {
return x * у;
}
var x:Number ='5;
var у .-Number = 6;
var z:Number = m u l t i p l y O ;
trace(z);
Далее следует байт-код, выданный Flasm. Как и ожидалось, код увеличился в объ-
еме, а его выполнение занимает больше времени (0,16 мс - почти вдвое больше,
чем в версии без применения функций). Нехорошо получается.
frame О
constants ' х ' , ' у ' , ' z ' . 'multiply'
function multiplyO
push 'x'
getVariable
push 'y'
getVariable
multiply
return
end // of function multiply

push ' x ' . 5


varEquals
push ' у ' . б
varEquals
push ' z ' . 0.0. 'multiply'
call Function
varEquals
push 'z'
getVariable
trace
end // of frame-0
452 Глава 12. Безопасность

Затем я попытался вызвать функцию с аргументами, полагая, что в этом случае


будет сгенерирован самый длинный байт-код:
function multiply(a. b) {
return a * b:
}
var x:Number = 5;
var у:Number =6;
var z:Number = multiply(x. y);
trace(z);
Но оказалось, что новая версия работает гораздо быстрее старой! (0,12 мс)! Ана-
лиз байт-кода поможет понять, почему это происходит. При вызове функции
с аргументами сгенерированный байт-код обращается к данным напрямую, вме-
сто того чтобы обращаться к переменным с их значениями. Это приводит к умень-
шению объема байт-кода и ускорению выполнения.
frame О
constants 'x'. 'у', 'i'. 'multiply'
function multiply(r:2='a'. r : T = 'b') О
push г:а. г:Ь
multiply
return
end / / o f function multiply

push 'x'. 5
varEquals
push 'y'. 6
varEquals
push 'z'. 'y'
getVariable
push 'x'. 5
getVariable
push 2. 'multiply'
call Function
push 'z'
getVariable
trace
end / / o f frame 0
Если в программе применяется функция с аргументами, Flash Player использует
более эффективные прямые обращения к регистрам вместо ячеек памяти (со-
держимое которых перед использованием все равно приходится заносить в реги-
стры или в стек). Это весьма интересное открытие наводит на мысль, что
Macromedia развивает ActionScript в направлении более структурированного
стиля программирования, для которого характерны функции, ссылки и парамет-
ры, а не отдельные переменные.
Эксперименты показывают, что время вызова функции компенсируется увели-
чением объема кода в каждой функции; написание логичного, модульного кода
способствует повышению быстродействия во многих приложениях.
Итак, оптимизации Flash Player 7, о которых говорит Macromedia, в наибольшей
степени проявляются при использовании объектно-ориентированного стиля про-
граммирования, элементы которого появились в ActionScript 2.O.
Просмотр откомпилированного кода ActionScript 453

Если попробовать повторить эти примеры в Flash Player 6 (Flash MX), результат
будет иным. Исключение составляет разве что Flash Player 6r65 (флажок Optimize
for Flash Player 6r65 на вкладке File • Publish Settings • Flash), который ведет себя
почти так же, как Flash Player 7 (наверное, потому что он, фактически, представ-
ляет собой Flash Player 7 без новых классов ActionScript, добавленных в Flash
MX 2004). При просмотре в Flasm кода старых версий Flash Player становится
очевидно, что оптимизации Flash Player 7 и Flash Player 6r65 связаны в основ-
ном с эффективным использованием регистров и стека.
Но чтобы извлечь пользу из этих оптимизаций, необходимо активно применять
такие возможности, как передача аргументов функциям, объявление локальных
переменных и передача целевого объекта в аргументе вместо обращения к нему
через свойство this.
Также стоит провести серию тестов для выявления различий между объявлениями
классов ActionScript 2.0 и наследованием на базе прототипов в ActionScript 1.0.
Небольшая подсказка: жесткая типизация ActionScript 2.0 реализуется на ста-
дии компиляции и не влияет на быстродействие, а в ООП с применением клас-
сов используются четко определенные функции и локальные данные (что спо-
собствует оптимизацию байт-кода за счет использования регистров вместо
памяти). Это означает, что для кода ActionScript 2.0, использующего классы,
генерируется высокооптимизированный байт-код; то же можно сказать о любом
структурном стиле программирования, использующем функции и локализацию
данных в функциях и аргументах.

Итоги
Программа Flasm полезна прежде всего тем, что она показывает, во что превра-
щается код ActionScript в итоговом SWF. На первый взгляд разобраться в лис-
тингах непросто, но вы довольно быстро освоите псевдоассемблер Flash Player,
если начнете с коротких простых сценариев, как это было сделано в предыду-
щих примерах.
Кроме того, Flasm помогает выявлять узкие места ActionScript. Учтите, что в гра-
фических приложениях критическим для быстродействия фактором часто явля-
ется механизм визуализации (см. трюк 68), а не байт-код.
Конечно, столь краткое описание дает крайне поверхностное представление
о Flasm и оптимизации кода. Если вы принадлежите к числу опытных програм-
мистов ActionScript, с Flasm определенно стоит познакомиться поближе - по-
лученная вами бесценная информация о среде Flash Player поможет выжать еще
немного быстродействия из ваших SWF.
Алфавитный указатель

АСО, формат, 77 class, ключевое слово, 74, 342


ACT, формат, 77 CLR, файлы, 76
ActionScript, 338 Color Mixer, панель, 99
2.0, 342 CSS, 225
байт-код, 436
безопасность, 435
быстродействие, 307 Drawing API, 87
встроенные классы, 289 duplicateMovieClip(), метод, 354
клонирование объектов, 352
E
определения классов, 342
оптимизация, 307 Envelope, инструмент, 248
отладка, 365 EOLAS, 387
преимущества, 340 Equation Editor, 219
регистр, 341
F
Adobe Audition, 271
Anim-FX, 237 Fire Works, 39
AnyBrowser, 390 FLA, сжатие, 309
ASC, формат, 379 Flash
ASnative(), функция, 296, 372 альтернативы, 145
Audacity, 272 временная диаграмма, 134
расширения файлов, 442
В среда разработки, 290
Bandwidth Profiler, 310 Flash Exchange, 336
Banja, 291 Flash MX 2004
Button, класс, 298 v2, компоненты, 318
Алфавитный указатель 455

Flash MX 2004 (продолжение)


изменения, 339
м
компоненты, 336
Macromedia
Flash Player
Flash Player, 387
безопасность, 434
Pocket PC CDK, 337
безопасность, 432
версия 6, 125
Magic Flare, 237
версия 7, 307, 340
Math.abs(), метод, 375
компоненты, 401
Math.atan2(), метод, 200
настройка обновлений, 386
Math.max(), метод, 377
совместимость, 396
Math.min(), метод, 377
Flash Plugin Switcher, 397
Media Lab, 49
Flasm, 447
meta, тег, 392
Flax, 237
Microsoft
Word, 219
против EOLAS, 387
getTextExtent(), метод, 206
MMExecute(), функция, 291
getVersion(), функция, 395
MovieClip._alpha, свойство, 107
GIF
MovieClip.attachMovie(), метод, 29
анимация, 45
MovieClip.attachSound(), метод, 267
копирование и сохранение, 46
MovieClip.createTextField(),
преобразование в SWF, 46
метод, 238
Gliftic, утилита, 81
MovieClip.duplicateMovieClipO,

н метод, 354
MovieClip.setMask(), метод, 28
HTML MP3, 266
импортирование формул, 219
HTTPS, протокол, 430
onEnterFrame, обработчик, 48, 139, 172
J
onMouseMove, обработчик, 139,
JSFL (Flash JavaScript), 290 173, 190
onPress, обработчик, 191
onRelease, обработчик, 191
KoolMoves, пакет, 146 onReleaseOutside, обработчик, 191
onSoundComplete, метод, 253
L
OpenSWF.org, 429
LiveDocs, 342 Output, панель, 401
456 Алфавитный указатель

Paint Bucket, инструмент, 99 vl, компоненты, 337


PDF, формат, 221 v2, компоненты, 302, 336
Photoshop, 39, 47, 78
w
PNG-24, формат, 46
Poser, 154 W3Schools, 388
PrimalScript, 346 WebSpeed Simulator, 311
PSD, файлы WinFlasm, 448
анимация, 49
импортирование, 49
XML, импортирование, 379

RAW, формат, 266


RIA (Rich Internet Applications), 289 z-lib, сжатие, 332

s A

SciTE и SciTE|Flash, 343 аллофоны, 253


SE|PY, 346 альфа-канал, 71
setlnterval(), функция, 30, 75, 138 анимация, 27, 35
setTransform(), метод, 286 v2, компоненты, 318
SSAS (Server-Side ActionScript), 430 ключевые кадры, 134
Stage.onResizer(), обработчик, 402 морфинг, 164
SWF-файлы панорамная, 174
восстановление контента, 435 слои, 134
декомпиляция, 447 трехмерная, имитация, 169
создание на базе GIF, 46 цикл ходьбы, 142
Swift 3D, 155 эффекты частиц, 161
SWiSH, 237
System.capabilities, свойство, 205
байт-код, 449
безопасность, 429
TextFormat.getTextExtent(), метод, 206 блокировка слоя, 363
trace(), 365
В
и векторная графика, 29, 313
updateAfterEventQ, обработчик, 136 визуальные эффекты, 27
Алфавитный указатель 457

визуальные эффекты (продолжение) vl, 337


генератор деревьев, 55 v2, 302
маски, 27 копирование по значению, 352
внедрение шрифтов, 238 копирование по ссылке, 353
внешние редакторы сценариев, 342 коэффициент трения, 187
временная диаграмма, 136
м
д маски, 28
декомпиляторы, 429 непрерывность контура, 115
создание, 28
Е сценарные, 28
естественные цветовые схемы, 79 эффект интерференции, 117
массивы
Ж эффективный поиск, 360
жесткая типизация масштабируемость, 326
ActionScript 2.0, 341 междоменная политика, 431
ограничения, 349 мозаичные узоры, 96
преимущества, 347 морфинг, 164

н
зернистость, эффект, 39 Найквиста, теорема, 280
недействительные экземпляры, 366

имитация
броска, 190 объекты, клонирование, 352
гравитация и трение, 186 ООП
зернистости, 39 ActionScript 2.0, 75
интеграция с браузером, 386 имена переменных, 75
интерактивное тестирование, 291 оптимизация, 306
время загрузки, 308
К интервальная проверка, 375
кадрированная анимация, 149 поразрядный сдвиг, 377
ключевые кадры, 151 размер файла, 306
кнопочные клипы, 298 субъективная, 308
колоризация, 39 хронометраж, 320
компоненты, 335 остаток, оператор, 374
458 Алфавитный указатель

отладка
trace(), 365 тайм-аут, 357
детализация вывода, 367 твипы, 377
оцифровка, 275 текст, 203
ошибка дискретизации, 275 HTML,

п форматирование, 221
разбиение, 248
панорамирование, 174 сглаживание, 316
потоковый звук, 264 тестирование сайта
браузеры, 389
модули Flash, 397
разбиение текста, 248 трассировка, 365
растровая графика трение, имитация, 186
размывка краев, 119 трехмерная анимация
растровые шрифты, 316 имитация, 169
расширяемость, 290 поддержка, 168
регистр символов
ActionScript 2.0, 341
рекурсия, 96 ускорение, 187

X
свойства экземпляра, 74 хронометраж, 320
сглаживание, 119, 313
сепия, 81 ц
Flash и Photoshop, 81 цветовые схемы, 76
сжатие FLA, 309 цветовые эффекты, 62
симметрия, 129 альфа-канал, 71
синхронизация речи, 259 сепия, 81
системные шрифты, 204 цикл ходьбы, 142
сложные маски, 112 циклы, эффективность, 362
слои, 159
статические свойства, 74 ч
стек, 449 частицы, эффект, 161
Алфавитный указатель 459

ш э
шрифты, 204 Эшер, М. К., 103
анимация текста, 204
внедрение, 238
повороты, 204 якорные ссылки, 416
системные, 238
шум дискретизации, 275
Шам Бхангал
Flash. Трюки
100 советов и рекомендаций профессионала
Перевел с английского Е. Матвеев
Главный редактор Е. Строганова
Заведующий редакцией А. Кривцов
Руководитель проекта А. Пасечник
Научный редактор Е. Матвеев
Технический редактор В. Шендерова
Литературный редактор А. Пасечник
Художник Е. Дьяченко
Корректор А. Моносов, Н. Рощина
Верстка Л. Родионова

Лицензия ИД № 05784 от 07.09.01.


Подписано в печать 25.04.05. Формат 70ХЮ0/16. Усл. п. л. 37,41. Тираж 3500 экз. Заказ № 1472.
ООО «Питер Принт». 194044, Санкт-Петербург, пр. Б. Сампсониевский, 29а.
Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 953005 — литература учебная.
Отпечатано с готовых диапозитивов в ФГУП «Печатный двор» им. А. М. Горького
Министерства РФ по делам печати, телерадиовещания и средств массовых коммуникаций.
197110, Санкт-Петербург, Чкаловский пр., 15.
КЛУБ П РСОХ/.Е С С И О Н А Л

В1997 году по инициативе генерального директора Издательского дома «Питер»


Валерия Степанова и при поддержке деловых кругов города в Санкт-Петербурге
был основан «Книжный клуб Профессионал». Он собрал под флагом клуба про-
фессионалов своего дела, которых объединяет постоянная тяга к знаниям и любовь
к книгам. Членами клуба являются лучшие студенты и известные практики из раз-
ных сфер деятельности, которые хотят стать или уже стали профессионалами в той
или иной области.
Как и все развивающиеся проекты, с течением времени книжный клуб вырос
в «Клуб Профессионал». Идею клуба сегодня формируют три основные «клубные»
функции:
• неформальное общение и совместный досуг интересных людей;
• участие в подготовке специалистов высокого класса
(семинары, пакеты книг по специальной литературе);
• формирование и высказывание мнений современного профессионала
(при встречах и на страницах журнала).
КАК ВСТУПИТЬ В КЛУБ?
Для вступления в «Клуб Профессионал» вам необходимо:
• ознакомиться с правилами вступления в «Клуб Профессионал»
на страницах журнала или на сайте www.piter.com;
• выразить свое желание вступить в «Клуб Профессионал»
по электронной почте postbook@piter.com или по тел. (812) 103-73-74;
• заказать книги на сумму не менее 500 рублей в течение любого времени
или приобрести комплект «Библиотека профессионала».
«БИБЛИОТЕКА ПРОФЕССИОНАЛА»
Мы предлагаем вам получить все необходимые знания, подписавшись на «Библио-
теку профессионала». Она для тех, кто экономит не только время, но и деньги.
Покупая комплект - книжную полку «Библиотека профессионала», вы получаете:
• скидку 15% от розничной цены издания, без учета почтовых расходов;
• при покупке двух или более комплектов - дополнительную скидку 3%;
• членство в «Клубе Профессионал»;
• подарок - журнал «Клуб Профессионал».
ивалтшаьскп^ нам
Закажите бесплатный журнал [уЦ^* ПИТЕР
«Клуб Профессионал». * ^ J ^w w w P tт Е я со м
ЗАКАЗАТЬ КНИГИ ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР»
МОЖНО ЛЮБЫМ УДОБНЫМ ДЛЯ ВАС СПОСОБОМ:
• по телефону: (812) 103-73-74;.
• по электронному адресу: postbook@piter.com;
• на нашем сервере: www.piter.com;
• по почте: 197198, Санкт-Петербург, а/я 619,
ЗАО «Питер Пост».

ВЫ МОЖЕТЕ ВЫБРАТЬ ОДИН ИЗ ДВУХ СПОСОБОВ ДОСТАВКИ


И ОПЛАТЫ ИЗДАНИЙ:
t|g Наложенным платежом с оплатой заказа при получении посылки на
ближайшем почтовом отделении. Цены на издания приведены ориентиро-
вочно и включают в себя стоимость пересылки по почте (но без учета
авиатарифа). Книги будут высланы нашей службой «Книга-почтой»
в течение двух недель после получения заказа или выхода книги из печати.
^g> Оплата наличными при курьерской доставке (для жителей Москвы
и Санкт-Петербурга). Курьер доставит заказ по указанному адресу
в удобное для вас время в течение трех дней.

ПРИ ОФОРМЛЕНИИ ЗАКАЗА УКАЖИТЕ:


• фамилию, имя, отчество, телефон, факс, e-mail;
• почтовый индекс, регион, район, населенный пункт,
улицу, дом, корпус, квартиру;
• название книги, автора, код, количество заказываемых
экземпляров.

НЗПЛТЕПЬСКПП ПОМ
Вы можете заказать бесплатный
журнал «Клуб Профессионал»
VtfWW-PITER.
'JO® СПЕЦИАЛИСТАМ
КНИЖНОГО БИЗНЕСА!
WWW.PITER.COM

ПРЕДСТАВИТЕЛЬСТВА ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР»


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

РОССИЯ
Москва м. «Калужская», ул. Бутлерова, д. 176, офис 207, 240; тел./факс (095) 777-54-67;
e-mail: sales@piter.msk.ru
Санкт-Петербург м. «Выборгская», Б. Сампсониевский пр., д. 29а;
тел. (812) 103-73-73, факс (812) 103-73-83; e-mail: sales@piter.com
Воронеж ул. 25 января, д. 4; тел. (0732) 39-61 -70;
e-mail: piter-vrn@vmail.ru; piterv@comch.ru
Екатеринбург ул. 8 Марта, д. 2676; тел./факс (343) 225-39-94, 225-40-20;
e-mail: piter-ural@isnet.ru
Нижний Новгород ул. Совхозная, д. 13; тел. (8312) 41 -27-31;
e-mail: piter@infonet.nnov.ru
Новосибирск ул. Немировича-Данченко, д. 104, офис 502;
тел./факс (3832) 54-13-09,47-92-93,11-27-18,11-93-18; e-mail: piter-sib@risp.ru
Ростов-на-Дону ул. Ульяновская, д. 26; тел. (8632) 69-91 -22;
e-mail: jupiter@rost.ru
Самара ул. Новосадовая, д. 4; тел. (8462) 37-06-07; e-mail: piter-volga@sama.ru
УКРАИНА
Харьков ул. Суздальские ряды, д. 12, офис 10-11; тел. (057) 751 -10-02, (0572) 58-41 -45,
тел./факс (057) 712-27-05; e-mail: piter@kharkov.piter.com
Киев пр. Красных Казаков, д. 6, корп. 1; тел./факс (044) 490-35-68,490-35-69;
e-mail: office@piter-press.kiev.ua
БЕЛАРУСЬ
Минск ул. Бобруйская, д. 21, офис 3; тел./факс (37517) 226-19-53;
e-mail: office@minsk.piter.com

Ищем зарубежных партнеров или посредников, имеющих выход на зарубежный рынок.


Телефон для связи: (812) 103-73-73.
E-mail: grigorjan@piter.com

Издательский дом «Питер» приглашает к сотрудничеству авторов.


Обращайтесь по телефонам: Санкт-Петербург - (812) 327-13-11,
Москва - (095) 777-54-67.

Заказ книг для вузов и библиотек: (812) 103-73-73.


Специальное предложение - e-mail: kozin@piter.com
УВАЖАЕМЫЕ ГОСПОДА!
КНИГИ ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР»
ВЫ МОЖЕТЕ ПРИОБРЕСТИ
ОПТОМ И В РОЗНИЦУ
У НАШИХ РЕГИОНАЛЬНЫХ ПАРТНЕРОВ.

Башкортостан
Уфа, «Азия», ул. Зенцова, д. 70 (оптовая продажа),
маг. «Оазис», ул. Чернышевского, д. 88,
тел./факс (3472) 50-39-00. Красноярск, «Книжный мир»,
E-mail: asiaufa@ufanet.ru тел./факс (3912) 27-39-71.
E-mail: book-world@public.krasnet.ru
Дальний Восток
Владивосток, «Приморский торговый дом книги», Нижневартовск, «Дом книги»,
тел./факс (4232) 23-82-12. тел. (3466) 23-27-14, факс 23-59-50.
E-mail: bookbase@mail.primorye.ru E-mail: book@nvartovsk.wsnet.ru

Хабаровск, «Мире», Новосибирск, «Топ-книга»,


тел. (4212) 30-54-47, факс 22-73-30. тел. (3832) 36-10-26, факс 36-10-27.
E-mail: sale_book@bookmirs. khv.ru E-mail: office@top-kniga.ru
http://www.top-kniga.ru
Хабаровск, «Книжный мир»,
тел. (4212) 32-85-51, факс 32-82-50. Тюмень, «Друг»,
E-mail: postmaster@worldbooks.kht.ru тел./факс (3452) 21-34-82.
E-mail: drug@tyumen.ru
Европейские регионы России
Архангельск, «Дом книги», Тюмень, «Фолиант»,
тел. (8182) 65-41 -34, факс 65-41 -34. тел. (3452) 27-36-06, факс 27-36-11.
E-mail: book@atnet.ru E-mail: foliant@tyumen.ru

Калининград, «Вестер», Челябинск, ТД «Эврика», ул. Барбюса, д. 61,


тел./факс (0112) 21 -56-28, 21 -62-07, тел./факс (3512) 52-49-23.
E-mail: nshibkova@vester.ru E-mail:evrika@chel.surnet.ru
http://www.vester.ru
Татарстан
Северный Кавказ Казань, «Таис»,
Ессентуки, «Россы», ул. Октябрьская, 424, тел. (8432) 72-34-55, факс 72-27-82.
тел./факс (87934) 6-93-09. E-mail: tais@bancorp.ru
E-mail: rossy@kmw.ru
Урал
Сибирь Екатеринбург, магазин № 14,
Иркутск, «ПродаЛитЪ», ул. Челюскинцев, д. 23,
тел. (3952) 59-13-70, факс 51 -30-70. тел./факс (3432) 53-24-90.
E-mail: prodalit@irk.ru E-mail: gvardia@mail.ur.ru
http://www.prodalit.irk.ru
Екатеринбург, «Валео-книга»,
Иркутск, «Антей-книга», ул. Ключевская, д. 5,
тел./факс (3952) 33-42-47. тел./факс (3432) 42-56-00.
E-mail: antey@irk.ru E-mail: valeo@etel.ru

You might also like