[ предыдущая страница ] [ следующая страница ] [ содержание ]

7. Язык ActionScript в действии

7.1. Планирование структуры ролика

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

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

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

В предыдущих версиях Flash кнопки были чуть ли не единственными элементами, рассчитанными на интерактивность (не считая динамических текстовых полей). Теперь, с появлением оператора onClipEvent они уже не имеют такой исключительности.

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

Если же все объекты разместить прямо в основном ролике, это затрудняет управление. С каждым объектом приходится работать отдельно, что увеличивает объем кода и, соответственно, время исполнения сценария.

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

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

Такие управляющие сценарии обычно являются основой программной анимации. Некоторые приемы программной анимации мы еще рассмотрим ниже в этой главе.

7.2. Трехкадровые циклы

Одним из основных приемов структурирования сценариев ролика Flash является использование так называемых трехкадровых циклов. Трехкадровые циклы в программе Flash являются, можно сказать, некоторой альтернативой традиционным циклам, используемым в других технологиях. Как мы уже неоднократно упоминали, в ролике Flash содержимое кадра прорисовывается только после завершения сценария этого кадра, а если в конце сценария осуществляется переход в другой кадр с помощью операторов gotoAndPlay или gotoAndStop, то содержимое текущего кадра вообще не прорисовывается.

7.2.1. Структура трехкадрового цикла

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

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

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

gotoAndPlay (2);

7.2.2. Пример трехкадрового цикла

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

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


Рис. 7.1. "Центр" стрелки часов нужно сместить к ее нижнему краю

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

Создание программной анимации

Теперь создадим программную анимацию с помощью трехкадрового цикла. Движение стрелок зададим с помощью изменения свойства _rotation. Экземпляры мувиков-стрелок назовем sec, min и hour, а переменные, в которых хранится угол поворота, - соответственно, s, m и h. Поскольку полный круг циферблата содержит 60 секунд, за каждую секунду стрелка должна поворачиваться на угол в 360 : 60 = 6 градусов.

Создадим новый слой для сценариев, назовем его Actions. В первом кадре присвоим первоначальные нулевые значения переменным s, m и h:

s=0;
m=0;
h=0;
mold=0;

Нам потребуется еще одна переменная (mold) для сохранения старого значения m. Оно нужно для того, чтобы определить, изменилось только что положение минутной стрелки или нет.

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

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

а = getTimer();
while (getTimer()-a<1000);

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

Корректнее было бы, например, ввести еще одну переменную, aold, в надо которой хранить значение getTimer() при предыдущем входе во второй кадр:

aold = a;
а = getTimer();
while (getTimer()-aold<1000);

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

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

s += 6;

Теперь, чтобы избежать появления слишком больших чисел, обнулим величину s при достижении значения 360:

if (s>=360) s = 0;

Установим новый угол поворота секундной стрелки:

sec._rotation = s;

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

mold = m;
if ((s==180)||(s==0)) m += 3;
if (m>=360) m = 0;
min._rotation = m;

С часовой стрелкой поступим так же, как с минутной. В полном круге циферблата 12 часов, значит каждый час стрелка должна поворачиваться на 360 : 12 = 30 градусов. Чтобы она шла плавно, заставим ее поворачиваться каждые 5 минут на 1/12 часового деления, или 1/144 полного круга (2,5 градуса):

if ((m%30==0)&&(m!=mold)) h += 2.5;
if (h>=360) h = 0;
hour._rotation = h;

При этом мы дополнительно сравниваем текущее положение минутной стрелки с предыдущим положением, сохраненным в переменной mold. "Подталкивать" часовую стрелку надо только в том случае, если минутная только что передвинулась на 5-минутную отметку. Если не сделать такую проверку, то, пока минутная стрелка стоит на 5-минутном делении, каждую секунду часовая стрелка продвигается вперед.

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

gotoAndPlay (2);

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

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

7.2.3. Другие примеры трехкадровых циклов

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

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

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

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

7.3. Организация перетаскивания флэш-символов

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

Мы уже видели, как можно заставить ролик реагировать на нажатие кнопки мыши, на движение мыши, нажатие клавиш на клавиатуре и так далее. Однако есть еще одна технология, очень любимая большинством пользователей, - так называемая технология drag-and-drop (перетаскивание экранных объектов с помощью мыши). С тех пор как с помощью drag-and-drop стали работать целые операционные системы и оболочки, возможность перетаскивания объектов стала особенно популярной среди широкого круга пользователей (так как стала, помимо всего прочего, привычной).

7.3.1. Технология перетаскивания в ролике Flash

В роликах Flash также можно использовать технологию drag-and-drop, предлагая пользователю перетаскивать объекты мышью. Для облегчения работы флэшера в языке ActionScript предусмотрен оператор startDrag, который заставляет указанный объект следовать за указателем мыши. Обратный оператор, stopDrag, выключает этот режим, "освобождая" объект.

Приведем простейший пример - создадим ролик, в котором имеется перетаскиваемый объект.

Организация перетаскивания

Как организовать перетаскивание объекта? Поскольку все задачи, связанные с отслеживанием положения указателя мыши и соответственным перемещением объекта, возложены на оператор startDrag, нам остается только правильно его применить. В технологии drag-and-drop принято, чтобы перемещение объекта вслед за мышью начиналось после нажатия на нем кнопки мыши и прекращалось после ее отпускания. Поэтому для отслеживания событий мыши на объекте удобно применить оператор on. Однако этот оператор допустим только в сценариях кнопки, следовательно, наш объект нужно сделать кнопкой.

Но в операторе startDrag необходимо указать имя экземпляра, который необходимо перетаскивать, а кнопке "напрямую" имя дать нельзя. К счастью, мы можем в качестве имени использовать ключевое слово this, означающее текущий объект.

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

on (press) {
   startDrag (this);
}
on (release) {
   stopDrag ();
}

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

Центрирование указателя

Несколько более сложен случай, когда необходимо, чтобы указатель мыши находился точно в центре перетаскиваемого объекта. Для этого у оператора startDrag предусмотрен второй, необязательный аргумент. Если его значение равно true, то в момент начала перетаскивания объекта к указателю мыши "приклеивается" его центр.

Но если просто изменить код предыдущего примера следующим образом

on (press) {
   startDrag (this,true);
}
on (release) {
   stopDrag ();
}

то случится нечто, на первый взгляд непонятное: при нажатии кнопки мыши на объекте он отпрыгнет куда-то в сторону и начнет перемещаться в месте с указателем мыши, находясь на почтительном расстоянии от него. Более того, объект уже невозможно "освободить", поскольку для этого нужно отпустить кнопку мыши над объектом, а он находится в стороне!

На самом деле в этом нет ничего удивительного. Поскольку наша кнопка расположена в основном ролике, то "центром" своим она считает начало координат основного ролика, то есть левый верхний угол. Поскольку первоначально объект находится, как правило, где-то в середине рабочей области, получается, что при выполнении оператора

startDrag (this,true);

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

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

Теперь мы можем спокойно написать

on (press) (
   startDrag (this,true);
}
on (release) {
   stopDrag ();
}

и просмотреть ролик. Теперь объект можно перетаскивать мышью, причем при нажатии кнопки мыши центр объекта совмещается с указателем мыши.

Задание области перетаскивания

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

on (press) {
   startDrag (this,true,60,60,200,400);
}
on (release) {
   stopDrag ();
}

Четыре числа, стоящие после двух первых аргументов оператора startDrag, означают соответственно координаты левого верхнего (60, 60) и правого нижнего (200,400) углов невидимого прямоугольника, внутри которого разрешено перемещаться объекту (точнее, его центру).

7.3.2. Управление формой указателя мыши

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

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

Откройте новый ролик, нажмите клавиши CTRL+F8 для создания флэш-символа, сделайте его мувиком Symbol1 и нарисуйте в нем маленький косой крест (или любой другой объект, пригодный на роль указателя мыши). Вернитесь на основную сцену, создайте новый мувик Symbol2 и поместите в него экземпляр мувика с крестиком. Этот экземпляр можно назвать cross.

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

Теперь поместите в первый кадр основного ролика такой код:

startDrag (cover.cross,true);
Mouse.hide ();

Просмотрите ролик. После нажатия клавиш CTRL+ENTER должно возникнуть впечатление, что указатель мыши превратился в косой крест. Правда, если увести мышь за пределы окна ролика, то "указатель" остановится у его края, но это уже детали. При необходимости можно приложить некоторые усилия и устранить этот эффект.

7.3.3. Выбор целевого объекта

В технологии drag-and-drop одной из наиболее важных задач является определение нулевого объекта, то есть, грубо говоря, анализ ситуации: куда, собственно был перетащен объект? В операционных системах, например, файлы с помощью мышки перетаскивают в другие папки или в "мусорную корзину"., где они перестают существовать. Давайте и мы с помощью программы Flash реализуем что-нибудь подобное.

Пусть в ролике имеется несколько перетаскиваемых объектов и "мусорная корзина". Задача состоит в том, чтобы при перетаскивании объекта на "мусорную корзину" он бесследно исчезал в ней (рис. 7.2).


Рис. 7.2. Объект, исчезающий в "мусорной корзине"

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

Создадим новый слой и назовем его Trash. Нарисуем в нем мусорную корзину и преобразуем ее в мувик. Экземпляр этого мувика тоже назовем Trash. Переместим слой Trash так, чтобы оказался ниже слоя с перетаскиваемыми объектами.

Нужно сделать так, чтобы при "освобождении" перетаскиваемого объекта над изображением мусорной корзины этот объект исчез. Достаточно, если он станет невидимым, для чего мы присвоим его свойству _visible значение false

Но каким образом определить, над каким объектом мы отпустили кнопку мыши? Для этого в языке ActionScript предусмотрено специальное свойство _droptarget. Его значением является имя экземпляра объекта, над которым находится перетаскиваемый объект. В данном случае нам нужно проверить, является ли значением свойства _droptarget объект _root.Trash.

Напомним, что код расположен в кнопке, а мусорная корзина расположена прямо в основном ролике, так что удобнее использовать абсолютное значение пути. Кроме того, необходимо учитывать, что свойство _droptarget тоже всегда возвращает абсолютное значение пути. Правда, возвращает оно его в "старой" нотации, в которой объект _root обозначается /. При этом имена вложенных объектов разделяются не точкой, а тоже косой чертой /, а имена переменных отделяются от имен объектов двоеточием. Но вспоминать правила "старой" нотации нет необходимости, поскольку применение к ней функции eval преобразует ее а новую, которой мы и пользовались до сих пор.

Таким образом, при отпускании кнопки мыши нам требуется нетолько освободить объект оператором stopDrag, но и проверить свойство _droptarget.

Если его значение, преобразованное в новую нотацию, равно _root.Trash, нужно сделать объект невидимым, изменив его свойство _visible.

Давайте посмотрим теперь на код кнопки целиком:

on (press) {
   startDrag (this);
}
on (release) {
   stopDrag ();
   if (eval(_droptarget)==_root.Trash) {
      _visible = false;
   }
}

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

Дополнительные эффекты

Эффект можно улучшить. Например, откройте мувик, содержащий нашу кнопку, и клавишей F6 добавьте ключевые кадры в позиции 2 и 15. Затем в позиции 15 установите прозрачность кнопки в 0, вернитесь в кадр 2 и создайте анимацию движения. Для усиления эффекта прозрачную кнопку в кадре 15 можно уменьшить раза в четыре, сделав ее совсем маленькой, а в кадре 2 на вспомогательной панели Frame (Кадр) установить вращение по часовой стрелке на 2 оборота.

Перейдите в позицию 16 и добавьте в ней еще один ключевой кадр с помощью клавиши F6. Переместите прозрачную кнопку в этом кадре куда-нибудь далеко вниз. Это необходимо для того, чтобы прозрачные объекты не мешали "выбрасывать" в мусорную корзину другие объекты. В кадры 1 и 16 введите команду:

stop ();

Войдите в окно редакции сценария кнопки и строку

_visible = false;

замените строкой

gotoAndPlay (2);

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

Этот пример наглядно демонстрирует применение технологии drag-and-drop в роликах Flash. Наличие в языке ActionScript таких операторов, как startDrag и stopDrag, а также свойства _droptarget делает работу флэшера с этой технологией очень простой и удобной.

[ предыдущая страница ] [ следующая страница ] [ содержание ]
Hosted by uCoz