Вы находитесь на странице: 1из 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, но вы можете