Issuu on Google+

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

ISBN 0596006454 (англ.) ISBN 5-469-00763-4

© 2004 O'Reilly Media, Inc. © Перевод на русский язык, ЗАО Издательский дом «Питер», 2005 © Издание на русском языке, оформление, ЗАО Издательский дом «Питер», 2005


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

Предисловие

13

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

16

Введение

19

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

26

Глава

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

27

Глава

2. Цветовые эффекты

62

Глава

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

87

Глава

4. Анимация

134

Глава

5. Трехмерная графика и физика

168

Глава

6. Текст

203

Глава

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

252


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

Глава

8. Элементы пользовательского интерфейса

Глава

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

289 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. Поворот к заданной точке

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

198

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. Быстрое создание звукового сопровождения для пользовательского интерфейса Трюк № 58. Оптимизация звука

270 275

Трюк № 59. Служебная информация для синхронизации . . . . 283 Трюк № 60. Пользовательский класс звуковых преобразований 286

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

289

Трюк № 61. Интерактивное тестирование

291

Трюк № 62. Правая и средняя кнопки мыши

296

Трюк № 63. Кнопочные клипы

298

Трюк № 64. Полосы прокрутки

302

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

306

Трюк № 65. Борьба с разрастанием файлов Flash

308

Трюк № 66. Тестирование загрузки канала связи для сложных сайтов

310

Трюк № 67. Маскировка последствий снижения качества Трюк № 68. Оптимизация графики

,

. . . 313 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. Интеграция с браузером Трюк № 86. Решение проблем совместимости

386 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. В свободное время увлекается созданием причудливых и странных эффектов на ActionScript. С примерами его работ можно ознакомиться на сайте 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) за разрешение воспроизвести некоторые изображения, созданные в Processing. Я также благодарен многочисленным разработчикам, проектировщикам и мечтателям, чья работа прямо или косвенно вдохновляла меня при работе над разными частями книги. Среди них стоит упомянуть Джоша Дэвиса (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.brianmolko.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 или 2.0 и...

...воспроизводится в Flash Player 6

Файл .swf формата Flash Player 6 Файл .swf формата Flash Player 7

Без учета регистра

1

2

1

Не поддерживается2

...воспроизводится в Flash Player 7 Без учета регистра С учетом регистра

В идентификаторах (то есть именах переменных и свойств), именах функций, метках кадров и экспортных идентификаторах символических имен в файлах .swf формата Flash Player 7 регистр символов не учитывается. С другой стороны, в зарезервированных словах вроде if регистр символов учитывается даже в 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 и используется исключительно для хранения сценариев).


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

34

Добавьте к первому кадру слоя 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

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

;S .


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

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, поскольку разбиение текста на пикселы является одной из составляющих эффекта.


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

Hi! 1-0

37

: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. Выберите размеры изображения такими, чтобы длина превышала ширину.


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

40

Я создал для демонстрационных целей файл 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

:'.••••"••

OK

h

Сфосип-ients and SettjngsAgham 1S;39;2O

Compression; ; Photo (JPEG)

Cancel Update

Teat

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

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

Перетащите растровое изображение на сцену, нажмите клавишу F8 (команда Modify • Convert to Symbol) и преобразуйте растр в символ анимационного клипа с именем grain. Далее остается лишь наложить подвижную версию нашего клипа на видео, растровое изображение или векторную анимацию. На рис. 1.15 она наложена на статическое изображение; рисунок выглядит так, словно перед вами кадр из старого фильма.


Глава 1. Визуальные эффекты , v.-;\w-i:*»TT-n >-п—г—-* '

_^J . •'.•-•'

v

. • .• 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 mcconcepta i rT i Jte l mcgreenLeaf me .over Ap l ha me. spn ie

Movie dip Movie dip Movie Qip Movie dip 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 - максимальное количество ростков (дочерних ветвей) для любой ветви;


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

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

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

angle

trunkThickness

Масштабирование с коэффициентом 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

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

ив

в

•• -

:

k 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

Применение цветовых эффектов к видео Мо-леОр ::::-.::.::':.,. •Л:

3~ 5

М;;| 37.5

у

C_i«y: И ancec

О

),: 69.0 Advanced Effect

[yv 123.0

Га

!; • Rei - ; 1004, vj xR} +

ga—^ufeer,-{ :oo«. v лс>+ о Ьа

Рис.

vj

•rb ^ 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};


Пользовательский класс цветового преобразования 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.

73


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 \

ш I

щ ,„]„.]

ш щ

:

П

.: •>-. WfiB"-'-

Ш

Ш 1

:

ш

1

щящ

: •- si ;: | 1 .1

Щ 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

No Transpar»,. V j

Dithtr I ООН

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. Цвета становятся более однородными, но проблемы с точным выбором цвета из естественного изображения все равно остаются. К счастью, существует фильтр, обеспечивающий нужный результат. Выполните команду


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

80

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. В этом разделе будет рассмотрен более общий технологический процесс в Photoshop, не ограничиваемый сепийными тонами. Откройте изображение в 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

M i l y*!ii

гv

RGB

50% В 75% Alphati 100%

Add Swatch Help Close Panel

J

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

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


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

84

поэтому не стоит рассчитывать на то, что изменение цветов будет выполнено так же точно, как в 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 передается один аргумент - временная диаграмма (то есть главная временная диаграмма или анимационный клип), на которой будут создаваться кнопки. После создания экземпляра CreateButton кнопки на целевой диаграмме создаются вызовами метода CreateButton.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. Случайный узор, сгенерированный из базовых фигур


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

96

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

ТРЮК

№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. Следующий фрагмент генерирует мозаичный прямоугольный узор из одинаковых плиток:


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

100

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


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

104

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

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

1

Рис. 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 относительно линий, проходящих через центр матрицы.


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

106

Рис. 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. Градиент


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

114

На слое 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): backCp il.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.


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

116

У

Urn tool

•Ы-ihairtne-

Рис. 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. Неровности контура, заметные при увеличении

Один из способов избавиться от неровностей основан на размывке краев в Photoshop перед импортированием графики в Flash. Загрузите изображение в Photoshop. Если потребуется, «сплющите» изображение, чтобы все пикселы находились на одном слое Photoshop с именем Background. Photoshop не обладает простыми средствами задания альфа-уровня для пикселов этого слоя. Щелкните правой кнопкой мыши (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


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

122

Если потребуется, повторите размывку с интервалом в 1 пиксел. Наконец, сохраните изображение в формате PNG командой File • Save As. Photoshop предложит выбрать сохранение файла в чересстрочном (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. Многие дизайнеры, с которыми я знаком, при виде уравнений начинают пятиться к двери, потому что они предпочитают мыслить на визуальном уровне. Конечно, они забывают о том, что приведенные выше уравнения просто отражают визуальную концепцию симметрии.


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

130

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

Листание страниц Недавно арсенал классических трюков Flash пополнился эффектом листания страниц (один из ранних примеров можно найти по адресу http://welcome.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 (видимая область новой страницы) симметрична рассматриваемой области. Открываемый клип остается неподвижным, но его маска ведет себя почти так же, как maskReverse_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), анимация, содержащая первые два клипа, не будет повторяться на промежутке максимальной длины, определяемой произведением длин двух исходных клипов. Повторение происходит только один раз


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

150

каждые 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).

j

щ

п|

• .

«

1

т ж т з|

\ы \4\

: я&я.

\п\ h ] ж№\

d

s |э| am w и * 1*1*1

Ж

Рис. 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 . Библиотека с символами клипов, длины которых выражаются простыми числами


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

154

Рис.

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 позволяет проектировать персонажей и анимационные последовательности, возможности этой программы будут продемонстрированы на примере экспортирования анимации, использующей готовую модель.


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

156

При запуске 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 (слева): трехмерная модель Минни изображает первый кадр позы в главном окне (справа)


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

158

Возможно, фигуру Минни стоит немного сдвинуть назад на сцене 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> Ж-! •

4.fiiSlijtton.: |Жй;:Ш^ .-. . :

:

•:,. w]

.-•...:•

• ' •

U

:•'

s

: .

e

t

h

i

s

;

f

' Quality

R

a

s

h

S

e

t

t

i

n

g

s

: i ^l •

a

m

e

r

a

t

e

:

- Tiroe Sp-an: SUrt

111 Ш

r

0

anrr

C

B

E

0 00 01 00

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 for

Глава 4. Анимация (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. Выравнивание количества замкнутых контуров в крайних точках анимации существенно повысило качество морфинга


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

166

Проблема несовпадения количества замкнутых областей объясняет, почему 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 в реальном времени, но не переступает ее.


Имитация трехмерной графики

ТРЮК

№35

.

169

Имитация трехмерной графики 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).


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

176

Хотя на стадии выполнения отображается только область, выделенная на рис. 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

ТРЮК

№39

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

Имитация броска Чтобы сделать интерфейс более реальным, попробуйте реализовать эффект броска: объект перетаскивается мышью, а при отпускании кнопки продолжает двигаться в прежнем направлении.

Как было показано ранее, воздействие ускорения (см. трюк 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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67

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

clipMove = setlnterval(mover, 1. clip);

} function mover(clip):Void { i f (Math.abs(clip._x) > 265)' { clip.dirX = -clip.dirX; } i f (clip._y > 190) { clip.dirY = -clip.dirY: clip._y = 190: } clip.dirX = clip.dirX * FRICTION: clip.dirY = (clip.dirY * FRICTION) + GRAVITY: clip._x += clip.dirX; clip._y += clip.dirY; // ** Диагностика ** // clip.line = clip.createEmptyMovieClipC'line". 0): // clip.line.lineStyle(4. 0x0. 100); // clip.line.lineTo(5 * clip.dirX, 5 * clip.dirY): // ** Диагностика ** updateAfterEvent(): } var MOMENTUM:Number * 0.8; var GRAVITY:Number =0.5: var FRICTION:Number = 0.99: this._x = 275: this._y = 200: this.lineStyle(20. 0x0. 100); this.moveTo(-275. -200): this.lineTo(-275. 200); this.lineTo(275. 200); this.lineTo(275. -200); var ball :MovieCl.ip = drawPipCthis. "ball". this.getNextDepthO. 0, 190); 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;


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

206 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 cocontributors 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).

;

entered text Ij? complete text::

« 3 D illllQ * • 5 . . •• i

Рис. 6.З. Создание слоев для реализации автоматического завершения текста

На слое entered text создайте многострочное текстовое поле без бордюра и присвойте ему имя myText_txt (см. рис. 6.4).

ж

rayText_txt 309 0

х:

И: 170.8

у;

s.ens iiifcl;^ 67. 3 ш

ты

А

!V|

! M ;|vl

:

И|;

* | Normal

|Ми1Шпе

v|

;

| <> D

Var:

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 A b £

v ' .A ;|

_sans

vl

14

V

completejxt jj 309.0 :

Hti 1*3.3

Ш67.0 Щ

|!;1А|,::|Ми1Шпе

v ; A0 <Ь П

Van

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 9 10 11 12

// Новое слово отсутствует в словаре. // Добавить его и отсортировать словарь заново. myText += " "+newWords[i]; dictionary.push(newWords[i]): dictionary.sort О:

} }

В строках 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

4

Micros

Microsoft Office XP Professional with FrontPage Choose instaiiafon opoons for air Office applications and toois

Features to install:

ш

Office Shared Features Office Tools

*ш i •щ^| :

^р| -г X -

'

H

T

M

L

a

n

*

L

g

-

-

S o u r c e

u

a

g

e

M i c r o s o f t

M i c r o s o f t

E d i t i n g

S e t t i n g s

D

r

G

a

r

w

a

T o o l

C o n v e r t e r

p

h

M i c r o s o f t

O f f i c e

S

n

d

e

r

M i c r o s o f t

O f f i c e

D

o

c

u

m

M i c r o s o f t

O f f i c e

S h o r t c u t

e

S

u

n

t

p

p

o

r

t

I m a g i n g

B a r

Description Inserts mathematical symbols and equations into documents. Space Required on С:

Hep

1696 KB

„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. Отформатированная математическая формула на веб-странице


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

222

На рис. 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 могут возникнуть проблемы.

ТРЮК

№46

Использование HTML и CSS в Flash 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 задаются числовыми литералами - например, #444444. Использование имен цветовых констант, поддерживаемых браузерами, не допускается.

По аналогии с внешним определением 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

\

- Name:! Button A Description::;

. Shortcut: : A Tab index:: -:

Рис.

'

Г ] Make child objects a xessible •'.'.

'

' •••••••'

^ i

Щ ''11 ш"!шштА

6.20. Ввод специальных свойств на панели Accessibility


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

232

Если экспортировать клип для 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, потому что на панели свойств отсутствуют элементы для их ручного задания.


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

234

Программа Следующий код получает вспомогательный текст и использует его для построения всплывающей подсказки. Предполагается, что на сцене размещены три кнопки с именами buttonA, buttonB и buttonC. Если щелкнуть на кнопке или нажать определенную комбинацию Клавиш, выполняются соответствующие обработчики событий. За кнопками закреплены следующие комбинации клавиш: •

ButtonA - A;

ButtonB - Control+B;

ButtonC - Control+D.

Обратите внимание: в поле Shortcut слово «Control» должно вводиться полностью, хотя в книге эта клавиша обычно обозначается сокращением «Ctrl». Кроме того, для каждой кнопки должны быть определены свойства, содержащие вспомогательную информацию. Откройте панель Accessibility (Window • Other Panels • Accessibility) и введите для каждой кнопки имя и комбинацию клавиш, как показано на рис. 6.24. В нашем примере заполняются поля Name и Shortcut, но вы можете самостоятельно изменить программу, чтобы в подсказке отображалось содержимое поля Description. • - • . • • • • • •

тлссе* sibrfrty

г\

0 Make 01sjectAccesable ;::Owske:d-|fd objects;.3ccesSbie

и;' ';•,•}

Name: | Button A

Description: i

С

; Shortcut: j A Tab: infer:

Рис. 6.24. Ввод свойств кнопок на панели Accessibility

Следующий фрагмент использует заданные свойства для создания справочного текста и реализации ускоренного вызова комбинациями клавиш. Подробные комментарии помогут разобраться в происходящем: function addHelp(target) { target.onRollOver = functionO { // Отображение подсказки задерживается на 1.2 секунды. helplnterval = setlnterval(createHelpText. 1200. target); }: target.onRollOut = target.onDragOut=function 0 {

// Когда указатель мыши выходит за пределы клипа. // подсказка скрывается. clear-Interval (helplnterval);


Всплывающие подсказки

235

removeHelpTextO ; function createHelpText(target) { // Создание клипа с текстом подсказки. var helpClip:MovieClip = attachMovieC'helpText". t h i s.getNextHi ghestDepth()); clearlnterval(helplnterval): // Задание атрибутов текста подсказки. var helpText:TextField = helpClip.helpText; helpText.background = true; helpText.backgrounded or = OxFFFFCC; // Форматирование текста подсказки. var helpFormat:TextFormat = new TextFormatO; helpFormat.leftMargin = 2; helpFormat.rightMargin = 2; helpFormat.indent = 0: helpFormat.size = 15; helpFormat.font = "_sans"; //

"helpText".

// Если у целевого клипа задано вспомогательное свойство name. // оно отображается в подсказке. if (target._accProps.name != undefined) { helpText.text = target._accProps.name; } if (target._accProps.shortcut !•= undefined) { // Если у целевого клипа задано вспомогательное свойство // shortcut, оно включается в подсказку. helpText.text += "\n"+target._accProps.shortcut; }

// Задание размеров подсказки. var fieldSize;Object = helpFormat.getTextExtent(helpText.text) helpText._height = fieldSize.textFieldHeight; helpText._width = fieldSize.textFieldWidth; helpClip._x = _xmouse-helpClip._width/2: helpClip._y = _ymouse-helpClip._height-10; } • • function removeHelpTextO { helpText.removeMovi eCli p ( ) : } function aHandlerO {

// Обработчик события кнопки А traceC'You clicked A");

} function bHandlerO { // Обработчик события кнопки В traceC'You clicked В"); } function cHandlerO {

// Обработчик события кнопки С traceC'You clicked С"):


236

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

function down() { // Функция обнаруживает комбинацию клавиш // и выполняет соответствующий сценарий, var all Keys; // Проверить, нажаты ли все клавиши в комбинации, for (var j - 0: j<keys.length; j++) { all Keys = true; for (var i = 0; i<keys[j].combo.length; i++) { allKeys = al1 Keys && Key.isDown(keys[j].combo[i]); } if (allKeys) { // Если все клавиши комбинации нажаты, передать фокус // кнопке и выполнить ее обработчик события. Дальнейшие // события блокируются до момента отпускания нажатых клавиш. Selecti on.setFocus(keys[j]): this.onKeyDown = undefined: this.onKeyUp = up: keys[j].btn.onRelease(); break; } function upO {

// Функция выполняется при отпускании комбинации клавиш. this.onKeyUp = undefined: this.onKeyDown = down:

var keys:Array = new ArrayO: var keyListener:Object = new ObjectO: keys[0] = {btn:buttonA. combo:[65]}; keys[l] = {btn:buttonB. combo:С Key.CONTROL. 66]}: keys[2] = {btn:buttonC. combo:[Key.CONTROL. 68]}: buttonA.onRelease = aHandler: buttonB.onRelease = bHandler; buttonC.onRelease = cHandler; addHelp(buttonA); addHelp(buttonB); addHelp(buttonC); keyListener.onKeyDown = down; Key.addListener(keyListener): На рис. 6.25 показан пример выполнения кода. Кнопке В назначено вспомогательное имя «Button В», а в поле Shortcut введена комбинация клавиш Control+B; если задержать указатель мыши над кнопкой, на экране появляется подсказка с этой информацией. Если пользователь нажмет Control+B, выполняется обработчик события bHandler(). Учтите: программа не проверяет, находится ли подсказка полностью на сцене и не закрыта ли указателем мыши. Код всего лишь демонстрирует базовую концепцию, которую при необходимости можно легко дополнить новыми возможностями.


Текстовые эффекты

237 Button 8 Control+B

Рис.

6.25. Текст подсказки для кнопки В

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

ТРЮК

№48

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

Многие читатели знакомы с текстовыми эффектами по программам для создания презентаций (таким, как Microsoft PowerPoint), в которых текст перемещается или анимируется по несложным правилам. Спектр возможных анимационных текстовых эффектов в Flash куда более разнообразен. Текстовыми эффектами часто злоупотребляют, но они позволяют эффективно и наглядно донести до читателя основную мысль или добавить анимацию к кнопкам и баннерам. Существует немало генераторов текстовых эффектов Flash, написанных сторонними разр��ботчиками. Для примера можно упомянуть SWiSH (http://www.swishzone.com), Flax (http://www.flaxfx.com), Magic Flare (http://magicflare.com) и Anim-FX (http:// www.flashtexteffects.com). Хорошие дизайнеры относительно редко применяют текстовые эффекты, поэтому расходы на покупку генератора ради создания нескольких эффектов могут оказаться неоправданными. С учетом этого обстоятельства я написал следующую программу, позволяющую быстро и легко создавать текстовые эффекты. Программа основана на следующих принципах: • каждая буква в тексте анимируется отдельно от других; • анимация букв происходит с небольшой задержкой. Например, если мы хотим анимировать буквы слова «c-a-t», сначала должна появляться буква «с», затем буква «а» и в последнюю очередь - буква «t». Любые другие варианты затрудняют чтение, и применять их не рекомендуется (если, конечно, они не являются частью задуманного эффекта). Одновременное появление всех букв при большом объеме текста замедлит эффект; • в конце эффекта текст имеет «нормальную» позицию и ориентацию. Хотя в некоторых случаях это может оказаться нежелательным (например, если


238

Глава 6. Текст вы хотите, чтобы текст сначала проступил, некоторое время оставался на экране, а потом растворился), такое предположение удобно для разработки исходного обобщенного решения.

Создание текста Хотя пустые текстовые поля можно создавать динамически методом MovieClip.create TextField(), прежде чем анимировать текстовое поле, его необходимо создать в пустом анимационном клипе (поскольку класс TextField не поддерживает события onEnterFrame для покадрового обновления). Кроме того, необходимо проследить за тем, чтобы шрифт, используемый текстовым полем, был правильно внедрен в итоговый SWF-ролик. Самый простой и безопасный способ - создать текстовое поле внутри клипа и вручную внедрить шрифт на стадии разработки. Далее остается лишь воспользоваться ActionScript для размещения символа, созданного вручную, на сцене во время выполнения. Создайте на сцене динамическое текстовое поле при помощи инструмента Text. Введите в нем текст «mm», чтобы быть уверенными в том, что поле вместит один произвольный символ выбранного шрифта. Выберите на панели свойств тип текста Dynamic Text (рис. 6.26), выберите простой шрифт без засечек (например, Arial или Helvetica) размером 24 пункта. Наконец, задайте текстовому полю имя экземпляра field. Dynamc i Text "field'

j^J Jill Arial

ШШФ \ %:•' f Ш;1

imrn \ Single Line Рис.

v; <0 ° .U EH

6.26. Задание свойств текстового поля

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

Внедрение шрифта Чтобы внедрить шрифт в SWF, не снимайте выделения с текстового поля и щелкните на кнопке Character в правой части панели свойств (если кнопка Character не отображается, значит, вы забыли выбрать тип текста Dynamic Text). В открывшемся диалоговом окне Character Options (рис. 6.27) установите переключатель Select Ranges и выделите первые 4 строки списка, щелкая на них с нажатой клавишей Shift.


Текстовые эффекты

239

Embed font outlines for:

Basic Latin (95 glyphs)

Japanese Капа {318 glyphs) Japanese Kanji -Level l{3174glv|i Japanese (АИ) (7517glyphs) Basic HangiJ (3454 glyphs) : Hangul (All) (11772 glyphs) t~:~ Traditional .Chinese -Level 1C5609JV Indude these characters:

!

Рис.

!

6.27. Диалоговое окно Character Options

Инкапсуляция поля в клипе Не снимая выделения с текстового поля, нажмите клавишу F8, чтобы преобразовать его в символ анимационного клипа (а точнее, инкапсулировать текстовое поле в клипе). Задайте символу клипа имя letter. Дважды щелкните на нем, чтобы войти в режим редактирования, и переместите текстовое поле (при помощи инструмента Selection) так, чтобы его левый нижний угол был совмещен с точкой регистрации клипа (рис. 6.28). Выйдите из режима редактирования, щелкнув на строке Scene 1 в области навигации панели Timeline, и удалите экземпляр letter со сцены.

Рис.

6.28. Совмещение левого нижнего угла текстового поля с точкой регистрации клипа

Остается задать клипу идентификатор символа компоновки, чтобы его можно было динамически размещать на сцене средствами ActionScript. Выделите символ letter в библиотеке, щелкните на нем правой кнопкой мыши (Windows) или щелкните с нажатой клавишей Н ! > (Мае) и выберите в контекстном меню команду Linkage. Установите флажки Export for ActionScript и Export in First Frame. Убедитесь в том, что в поле Identifier выбран символ letter, и щелкните на кнопке ОК.


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

240

Динамическое размещение текста Чтобы разместить текст на сцене с соразмерным распределением пробелов, свяжите следующий сценарий с кадром 1 временной диаграммы: // Код ActionScript 2.0 function placeTextCtarget:MovieClip. x:Number. y:Number. banner:String. tFormat:TextFormat):Void { // Для каждого знака... for (var i = 0; i<banner.length: i++) { // Создать клип и поместить текущий символ в текстовое поле. var char:MovieClip = target.attachMovie("letter". "char"+i. target.getNextHi ghestDepth()); char.field.text = banner.substr(i, 1): char._x = x: char._y = y: // Прибавить ширину текущего знака к позиции х следующего знака, х += tFormat.getTextExtent(char.field.text).width; } var format:TextFormat = new TextFormatO; format.font = "Arial": format.size = 24; placeText(this, 100. 100. "This is a text effect", format); Функция placeText() создает надпись, текст которой задается аргументом banner, в позиции (х, у) временной диаграммы timeline. Межсимвольные интервалы определяются объектом tFormat класса TextFormat. Если вместо Arial используется другой шрифт или размер шрифта отличен от 24, внесите соответствующие изменения в две строки, выделенные жирным шрифтом. Чтобы использовать шрифт другого размера, измените размеры текстового поля - выделите его инструментом Text и перетащите ограничивающий прямоугольник до нужных размеров. При использовании значений, заданных в последней строке листинга, текст выводится с правильными межсимвольными интервалами, как показано на рис. 6.29. T h i s is a t e x t e f f e c t Рис. 6.29. Выходные данные генератора с пропорциональными

интервалами

Если экземпляр TextFormat не используется, а знаки текста выводятся на фиксированных расстояниях, результат будет выглядеть примерно так, как показано на рис. 6.30.

ТЫ s j s a text effect • Рис. 6.30. Текст, выведенный без пропорциональных интервалов

Пропорциональные интервалы обеспечиваются следующей строкой: х += tFormat.getTextExtent(char.field.text).width;


Эффект пишущей машинки

241

Если заменить выражение в правой части константой, (например, х+=12;), вы получите текст с непропорциональными интервалами, наподобие изображенного на рис. 6.30. Хотя надпись внешне выглядит как обычная строка Flash, в действительности она состоит из серии клипов, каждый из которых содержит всего один символ. Методику создания анимированных эффектов на этой основе проще всего пояснить на конкретных примерах. Далее мы рассмотрим несколько примеров таких эффектов, в том числе эффект пишущей машинки (см. трюк 49).

Итоги В настоящее время существует целый ряд генераторов текстовых эффектов, разработанных независимыми фирмами, но базовый код текстового эффекта всегда остается одним и тем же. Стоит разобраться в основополагающих принципах, и вы сможете легко создавать собственные эффекты. Возможности написания текстовых переходов ограничены только вашим воображением. Хотя некоторые знаменитые текстовые эффекты (см. трюк 31) можно реализовать разными способами, универсальная основа, приведенная в этом трюке, поможет вам генерировать собственные текстовые эффекты (см. трюк 50). Если вам нужен исходный творческий импульс, посмотрите на начальные титры в таких фильмах, как «Звездные войны», «Семь» или любой фильм Хичкока.

ТРЮК

№49

Эффект пишущей машинки Создание классического текстового эффекта пишущей машинки без применения ручной анимации.

Эксперименты с заготовкой для создания текстовых эффектов обычно начинаются с классического эффекта пишущей машинки. Этот эффект прекрасно подходит для оформления начальных титров в триллерах, криминальных драмах и фильмах о писателях (таких, как «Адаптация»). Мы реализуем эффект пишущей машинки вместе со звуковым сопровождением. Программа предполагает, что Flash-ролик содержит звуковые данные с идентификатором компоновки typeClick (импортируйте звуковой файл в Flash и задайте идентификатор компоновки в диалоговом окне Linkage Properties, вызываемом из раскрывающегося меню Options панели Library). Естественно, в файле typewriter.fla, находящемся на сайте книги, используется звук нажатия клавиш механической пишущей машинки.

Программа Приведенный далее код написан на базе заготовки для построения текстовых эффектов (см. трюк 48). Изменения выделены жирным шрифтом. Предполагается, что динамическое текстовое поле letter находится в клипе с именем экземпляра field, а в библиотеке существует звуковой клип typeClick.


242

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

function typewriter(target:MovieClip, del ay:Number):Void { target.interval = functionO { . target._visible = true: keyHit.start(0, 1); clearlnterval(target.interval ID); }: target.interval ID = setlnterval(target, "interval", delay): target._visible = false; } function placeText(target:MovieClip. x:Number, у:Number, banner:String. tFormat:TextFormat):Void { // Для каждого знака... for (var i = 0; i<banner.length; i++) { // Создать клип и поместить текущий символ в текстовое поле. var char:MovieClip = target.attachMovie("letter". "char"+i. • target.getNextHi ghestDepth()); char.field.text = banner.substr(i. 1); char._x = x; char._y = y; // Прибавить ширину текущего знака к позиции х следующего знака. х += tFormat.getTextExtent(char.field.text).width: // // Вызов эффекта. var timer = i*200+Math.round(Math.random()*200); typewriter(char, timer); } var keyHit = new Sound(this); keyHit. attachSoundf typeCl i ck"); var format:TextFormat = new TextFormatO; format.font = "Aria!": format.size = 24; placeTexttthis. 100, 100. "This is a text effect.", format); В конце функции placeTextQ задается задержка timer от 200 до 300 мс на каждый знак. Указанный интервал должен пройти перед выводом текста (и воспроизведением соответствующего звука) функцией typewriter(). Тем самым имитируется задержка между нажатиями клавиш в процессе ввода текста. Любой текстовый эффект строится по тому же принципу: • определяется задержка на вывод одного знака и изменяются одного или несколько свойств каждой буквы; • в конце задержки измененному свойству присваивается окончательное значение, завершающее эффект; • происходит переход к следующей букве. Для создания эффекта пишущей машинки свойству visible задается значение false, в результате чего все буквы изначально невидимы. При истечении задержки код typewriter) делает текст снова видимым. На рис. 6.31 показан эффект пишущей машинки в действии. Программа с небольшой задержкой открывает каждую букву в последовательности.


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

Рис.

This

is

a

This

is

a

text

ef

This

is

a

text

effect.

243

6 . 3 1 . Эффект пишущей машинки в действии

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

Текстовые эффекты, контролируемые №50 по времени ТРЮК

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

Эффект поднимающихся букв В этом эффекте текст постепенно «поднимается» из горизонтального положения. Как и в других текстовых эффектах, задача решается постепенным изменением свойств клипа. В данном случае изменяется свойство _yscale (масштаб по вертикальной оси). Изначально свойство равно 0, то есть текст остается невидимым (не имеет высоты). Вместо немедленного изменения свойства, как это делалось при реализации эффекта пишущей машинки (см. трюк 49), переход осуществляется постепенно с применением обработчика onEnterFrame(). Когда свойство _yscale достигает окончательного значения (100%), обработчик onEnterFrame удаляет себя.


244

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

Программа Следующий листинг показывает, как реализовать плавный эффект «вырастания» букв посредством постепенного изменения их свойств в обработчике onEnterFrame. Функция placeText() тоже была модифицирована по сравнению с предыдущим трюком (см. трюк 49): в новом варианте ей передается имя выполняемой функции и величина задержки, что упрощает ее повторное использование для- других эффектов. Предполагается, что динамическое текстовое поле letter находится в клипе с именем экземпляра field. Итоговая версия находится в файле standup.fla на сайте книги. Важные фрагменты выделены жирным шрифтом, function standUpCtarget :Movi eCl ip. del ay: Number)-.Void { target.interval = functionO { clearInterval(target.interval ID); this.onEnterFrame = functionO { target._yscale += 10; if (target._yscale > 95) { delete this.onEnterFrame; } target.interval ID = setlnterval(target, "interval", delay); target._yscale = 0; } function placeText(target:MovieClip, x:Number, y:Number. banner:String. tFormat:TextFormat. effectFunction:Function, del ay:Number):Void { II Для каждого знака... for (var i = 0: i<banner.length; i++) { // Создать клип и поместить текущий символ в текстовое поле, var chanMovi eCl ip = target.attachMovieC'letter", "char"+i. target.getNextHighestDepthО); char.field.text = banner.substr(i. 1); char._x = x; char._y = y; // Прибавить ширину текущего знака к позиции х следующего знака. х += tFormat.getTextExtent(char.field.text).width; // // Вызов функции эффекта, передаваемой в виде параметра. effectFunction(char, i*delay); узг format:TextFormat = new TextFormatO; format.font = "Aria!": format.size = 24; placeTextUhis. 100. 100. "This is a text effect", format. standUp. 100); На рис. 6.32 показан эффект поднимающихся букв в действии. Эффект изменяет высоту каждого символа от 0 до 100 % от исходного размера.


Текстовые эффекты, контролируемые по времени This

245

is T h i s is

a

text e f f _ T h i s is

Рис.

a

text effect

6.32. Эффект поднимающихся букв в действии

Эффект падения Изменяя другие свойства (и/или сразу несколько свойств одновременно), можно создавать переходы, визуально отличающиеся друг от друга, но работающие на сходном коде. Чтобы создать эффект падения, мы постепенно изменяем свойство _у - создается впечатление, что буквы падают на свое место в последовательности. Также в начале падения каждой буквы свойство visible задается равным true, чтобы буква была видна на экране. Чтобы падение выглядело более естественно, выделенная жирным шрифтом строка создает иллюзию инерции. Функция placeTextQ в листинге не приводится она не изменилась по сравнению с предыдущим примером. Как и прежде, предполагается, что динамическое текстовое поле letter находится в клипе с именем экземпляра field. Итоговая версия находится в файле drop.fla на сайте книги. // Код ActionScript 2.0 function dropCtarget :MovieCl i p . del ay: Number)-.Void { target.interval = functionO { target._vi sible = true: clearInterval(target.interval ID); target.onEnterFrame = functionO { target._y -= (target._y-target.startY)/3: i f (Math.abs(target._y-target.startY)<l) { target._y = target.startY: delete target.onEnterFrame:

} target.interval ID = setlnterval(target, "interval", delay): target.startY = target._y: target._y = 0; target._visible = false: } var format:TextFormat = new TextFormatO; format.font = "Arial": format.size = 24; placeText(this. 100. 100. "This is a text effect", format, drop. 100); На рис. 6.33 показан эффект падения в действии. Буквы поочередно появляются с небольшой задержкой, а затем «падают» на положенное место.


24G

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

X T h i s is a

t

e

T h i s is a t e x t T h i s is a t e x t e f f e c t Рис. 6.33. Эффект падения в действии

Проявление с масштабированием Вероятно, наибольшую известность из всех текстовых эффектов получил эффект постепенного проявления с масштабированием. Он прославились благодаря сайту theVoid (http://www.thevoid.co.uk). Этот эффект основан на постепенном изменении свойств _xscale, _yscale и _alpha, но программная реализация остается практически такой же, как прежде. При изменении всех свойств имитируется эффект инерции (соответствующий фрагмент листинга выделен жирным шрифтом). Функция placeTextO в листинге не приводится - она не изменилась по сравнению с предыдущим примером. Как и прежде, предполагается, что динамическое текстовое поле letter находится в клипе с именем экземпляра field. Итоговая версия находится в файле fadein.fla на сайте книги. function fadeZoom(target:MovieClip. del ay:Number):Void { target .interval = functionO { target._visible = true; clearlnterval(target.interval ID); target.onEnterFrame = functionO { target._xscale -= (target._xscale-100)/3; target._yscale -= (target._yscale-100)/3; target._alpha -= (target._alpha-100)/3: i f (Math.abs(target._xscale-100)<l) { target._xscale = 100; target._yscale = 100; target.alpha = 100: delete target.onEnterFrame: } target.interval ID = setlnterval(target, "interval", delay); target._xscale = 2000: target._yscale = 2000; target.„alpha = 0;


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

247

var format:TextFormat = new TextFormatO; format.font = "Arial"; format.size = 24; placeText(this. 100. 200. "This is a text effect", format. fadeZoom. 100); На рис. 6.34 показан эффект проявления с масштабированием в действии. Хотя эффект выглядит более сложным, чем в предыдущих примерах, базовый принцип не изменился - мы изменяем сразу несколько свойств со временем.

Thisj

This is a text

T h i s is a t e x t e f f e c t Рис. 6.34. Эффект проявления с масштабированием в действии

Чтобы эффект был симметричным, переместите текстовое поле в клипе letter (при помощи инструмента Selection) так, чтобы точка регистрации клипа находилась в середине левой стороны текстового поля, как показано на рис. 6.35.

m

m

Рис. 6.35. Перемещение точки регистрации делает эффект проявления симметричным

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


248

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

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

Текстовые эффекты с применением №81 морфинга ТРЮК

Некоторые текстовые эффекты реализуются только с применением морфинга. Для создания эффектов такого рода применяется редко используемый, но очень полезный инструмент Envelope. Ранее уже рассматривались способы создания сценарных текстовых эффектов (см. трюк 50). Тем не менее, текстовые эффекты ActionScript ограничиваются созданием анимации за счет изменения свойств клипа со временем. Данная разновидность анимации позволяет изменять позицию, прозрачность, цвет, ориентацию и масштаб текста, но ActionScript не способен создавать сложные анимации с изменением геометрической формы текста. Чтобы решить эту задачу, необходимо преобразовать текст в низкоуровневые векторные фигуры и работать с ними, как с графическими примитивами. Перспектива выполнения низкоуровневых операций с множеством фигур выглядит устрашающе, но в этой ситуации нам пригодится очень полезный инструмент Envelope. Большинство дизайнеров забывает о нем, однако этот инструмент позволяет быстро применять эффекты к набору букв способом, который не удастся легко реализовать на сценарном уровне.

Разбиение текста Прежде чем приступать к редактированию текста в виде векторных фигур, его необходимо преобразовать в векторную форму - в Flash этот процесс называется разбиением (breaking apart). Создайте текст при помощи инструмента Text, a затем, не снимая выделения с текста, дважды выполните команду Modify • Break Apart. Первая команда Break Apart разбивает текстовое поле на несколько текстовых полей (по одному на каждую букву), а вторая разбивает буквы на векторные контуры.

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

Инструмент Envelope Выделите все буквы в тексте инструментом Selection, активизируйте инструмент Free Transform. В области параметров этого инструмента (в нижней части панели Tools) выберите значок Envelope. Примерный вид текста показан на


Текстовые эффекты с применением морфинга

249

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

Рис. 6.36. Разбитый текст выделен при помощи инструмента Envelope

Возможно, вы не сразу разберетесь в том, как работать с ограничивающим прямоугольником, потому что по его периметру расположено множество непонятных маркеров. В действительности маркеры делятся на два типа: квадратные представляют контрольные точки, а круглые - концы управляющих векторов, определяющих угол входа огибающей в контрольную точку. Получается, что каждому квадратному маркеру соответствуют два круглых. Чтобы лучше разглядеть контрольные точки, попробуйте временно затемнить фон (рис. 6.37). Цвет фона задается командой Modify • Document (выделение с огибающей при этом не снимается).

Рис. 6.37. Затемнение фона помогает различить два типа маркеров на огибающей

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

Рис. 6.38. Перемещение контрольной точки

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


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

250

точек, форма текста автоматически подгоняется под форму огибающей, как показано на рис. 6.39.

Рис. 6.39. Перемещение управляющего вектора

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

Рис. 6.40. Изменение формы и/или ориентации текста применением инструмента Envelope

Пара замечаний о работе с инструментом Envelope: •

если щелкнуть в любой месте, кроме контрольной точки или управляющего вектора, выделение огибающей снимается;

при снятии выделения форма огибающей не запоминается. Например, если снять выделение с огибающей, показанной на рис. 6.40, то повторное выделение не вернет ее к прежней криволинейной форме. Вместо этого огибающая будет выглядеть как прямоугольник, ограничивающий изогнутый текст. Иногда это сильно раздражает, потому что даже отмена операции (Ctrl+Z или §€+Z) не восстанавливает исходную форму огибающей.

Несмотря на эти недочеты, инструмент Envelope позволяет очень быстро реализовать морфинг текста (см. трюк 34), как показывает серия изображений на рис. 6.41. Определяя в ключевых кадрах измененные формы текста, мы почти мгновенно создаем естественную «пульсирующую» анимацию.


Текстовые эффекты с применением морфинга

251

10

]J

S • IS

Г ЪШШ

1;

;

13

:!

23 •-••:• '.:

2S

Ш$

Рис. 6 . 4 1 . Создание морфинга с использованием инструмента Envelope

Итоги Некоторые анимации не удается легко создать.средствами ActionScript - в таких случаях лучше всего прибегнуть к редактированию текста в векторной форме. Если править форму каждой буквы по отдельности, задача окажется весьма трудоемкой. Мощный (хотя и не прощающий ошибок пользователя) инструмент Envelope позволяет работать с несколькими буквами, как с единым целым. В этом трюке показано, как организовать постепенное изменение формы текста. Если вам потребуется создать более сложный морфинг, попробуйте отредактировать текст во внешнем векторном редакторе (таком, как Freehand или Illustrator или даже в одной из последних версий Photoshop) и импортировать графику в Flash командой File • Import.


Г Л А В А

Работа со звуком Трюки № 52-60 На собственном опыте знаю, что многие веб-дизайнеры разделяют распространенное заблуждение по поводу звука. Это заблуждение можно сформулировать примерно так:«Я не профессиональный художник, но это не мешает мне рисовать картинки и строить симпатичные веб-сайты. Я не музыкант, и это мешает мне создавать звуки и музыку для моих сайтов». Такой подход годится для дизайнера HTML-сайта, которому практически не приходится работать со звуком, но когда вы имеете дело с анимацией в Веб, отсутствие звукового сопровождения оборачивается крупным недостатком. Звук является одним из важнейших аспектов анимации и интерактивности. Попробуйте поработать на Flash-сайте с отключенным звуком или поиграть в Quake на 20% громкости. Получается совсем не то! Помимо создания собственных звуковых файлов есть и другой путь - приобрести компакт-диск с готовыми звуковыми материалами. Однако содержимое таких дисков обычно делится на две категории: «используется повсеместно и всем надоело» или «настолько дико, что никто не захочет слушать». К сожалению, поддержке звука в области веб-дизайна еще не уделяется должного внимания. Все мы знаем, как оптимизировать растровое изображение для Веб без создания лишних неровностей контуров или нежелательной зернистости/ цветового шума, но оптимизация звука редко выходит за пределы назначения частоты оцифровки МРЗ при экспортировании с целью уменьшения размеров файла. Однако в технологии оптимизации звука тоже присутствуют свои «неровности» и «шумовые эффекты» (шум оцифровки). Вы должны знать о них, чтобы добиться оптимального соотношения «размер файла/качество».

ПРИМЕЧАНИЕ Звуковые данные загружают канал связи интенсивнее, чем остальные составляющие ролика (за исключением разве что видеоданных), поэтому очень важно, чтобы звук был как можно лучше оптимизирован в любом веб-содержании;

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


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

253

Также мы рассмотрим некоторые проблемы, из-за которых звук в Flash работает не так, как описано в документации (в прошлом эти проблемы отбили у многих дизайнеров всякое желание экспериментировать со звуком). Заодно будут представлены некоторые трюки из области работы со звуком. Собственно, эти приемы названы «трюками» только из-за своей нестандартности например, методика голосового ввода и вывода на базе Flash. Во многих функциях создания сложных звуковых эффектов задействованы последние усовершенствования Flash (например, класс Microphone и более тонкие возможности вроде повышения точности хронометража и общей стабильности Flash Player). А это означает, что некоторые из представленных звуковых трюков будут работать только в последних версиях Flash.

ТРЮК

№52

Создание синтезатора речи Синтез речи повышает гибкость реализации без увеличения объема передаваемых данных — отпадает необходимость в предварительной записи или приеме заранее записанных звуков.

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

Проблема лазера В основу многих трюков заложено нестандартное применение стандартных приемов и технологий. История науки полна примеров неожиданного применения технологий - например, лазеров. Мало кто мог предположить, что лазеры будут использоваться во всех областях, от военного дела до хирургии, от прослушивания музыки и просмотра фильмов до ведения международных телефонных переговоров. Давайте посмотрим, как использовать тривиальное на первый взгляд событие onSoundComplete для построения синтезатора речи в Flash.

Событие Sound.onSoundComplete Как только в Flash MX появился метод Sound.onSoundComplete(), я сразу же подумал: «Здорово! Теперь звуки можно легко и точно синхронизировать, и я смогу создать виртуальный микшерный пульт». И это действительно так - точность события onSoundComplete на порядок превышает частоту смены кадров, поэтому оно гораздо точнее решения с ключевыми кадрами и onEnterFrame, примен