Программная анимация во Flash MX

Программная анимация во Flash MX

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

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

  1. Создаем новый документ. Переходим на первый слой и рисуем мяч. Для этого:
  • Рисуем небольшой круг, используя инструмент Oval (Овал) при нажатой клавише <Shift>.
  • Создаем радиальную заливку, которая поможет передать объемность мяча. Для этого маркеру центра ставим в соответствие белый цвет, маркеру границы — светло-коричневый (максимально близко соответствующий традиционной окраске баскетбольного мяча). Для того чтобы переход от блика к умеренно освещенным фрагментам был максимально естественен, где-то на расстоянии в одну треть от общей длины градиента добавляем новый маркер (левым щелчком мыши) и определяем его цвет как коричнево-красный. Чуть ближе к маркеру границы ставим новый маркер с цветом, чуть более светлым, чем у последнего. Убрать лишние маркеры можно, выполнив их протаскивание при нажатой клавише мыши вниз.
  • Заливаем круг созданным градиентом.

  • На данном этапе наш объект не похож не то что на мяч, но даже на шар (см. рис. 1 (a)). Чтобы придать ему больше естественности, при помощи инструмента Fill Transform (Преобразование заливки) перемещаем центр заливки ближе к краю мяча, немного увеличиваем ее радиус и сжимаем по оси, совпадающей по направлению с предполагаемым источником света. Приблизительный итог представлен на рис. 1 (b) (черно-белый формат газеты плохо передает сложные цветовые переходы).



    Рис.1. Создание прообраза мяча

  • Теперь — самый сложный этап. Рисуем характерные для баскетбольного мяча линии (сделать это нужно на отдельном слое). Чисто технически это реализуется несложно: в масштабе 300% проводим при помощи инструмента Pencil (Карандаш) (в режиме Smooth (Гладкие)) три кривые и затем придаем им более правильную форму при помощи инструмента Array (Стрелка). Гораздо сложнее представить, как эти самые линии должны пройти. Для этого закройте глаза и немного пофантазируйте. Если и это не поможет — найдите картинку с изображением мяча и просто ее перерисуйте. При необходимости, выделив весь объект, увеличьте толщину линий. Вот и все. Ваш мяч должен выглядеть приблизительно так же, как на рисунке 2.



  • Рис.2. Готовый мяч

    Раз на мяче имеется блик, значит, он освещен достаточно сильным источником и не может не отбрасывать тени. Чтобы ее создать:

  • Вводим новый слой ниже существующих и перемещаемся на него.
  • При помощи инструмента Oval (Овал) создаем эллипс и поворачиваем его так, чтобы его главная ось совпадала с гипотетическим направлением света от источника.
  • Так как интенсивность тени должна изменяться от низа мяча (почти черный цвет) к своей вершине (совершенно белый цвет), то созданный эллипс необходимо залить подходящим радиальным градиентом (центр его должен быть помещен в начало тени). Через тень должен быть виден фон, поэтому ее коэффициент прозрачности следует уменьшить до 50% (параметр Alpha (Альфа) панели Color Mixer (Смеситель цветов)). Результатом должно быть изображение, подобное представленному на рис. 3.



  • Рис.3. Так должна выглядеть тень

    1. Чтобы мы могли управлять поведением графического объекта, его необходимо перевести в символ. Для этого нужно, выделив его, нажать F8. Тип символа необходимо определить как MovieClip. В нашем случае движение мяча будет имитировано перемещением трех объектов — контура, "тела" и тени. Соответственно, необходимо создать три символа. Назовите их так, как пожелаете (это несущественно).
    2. В программе вы не можете написать: "Компьютер, возьми вон тот красный мячик в углу и передвинь его чуть-чуть вниз". Машина способна выполнять лишь четкие указания вроде: "При наступлении события Event координату y экземпляра N символа Object увеличить на 5". Следовательно, в самом начале мы должны дать нашим символам конкретные имена. Вернее, идентификаторы следует определить для экземпляров символов, так как материнские объекты уже имеют имена, которые были им даны при их создании. Сделать это можно в строке Instance Name (Имя экземпляра) инспектора свойств экземпляра (рис. 4.). В качестве имени может выступать практически любой текст (кроме некоторых служебных символов (например, "/") и русскоязычных слов). Нашим объектам дадим следующие идентификаторы: contour, ball, shade.



    3. Рис.4. Присвоение экземпляру символа имени

    4. Создайте новый слой и назовите его "Action". Поместите его выше остальных. Выделив его первый кадр, нажмите <F9>. При этом будет открыта панель ввода кода Actions (Действия). Так как нам придется вводить достаточно много скрипта, расширьте ее протаскиванием за верхний край так, чтобы она закрыла все рабочее поле.

    5. Во Flash имеется два режима ввода кода: экспертный (Expert Mode) и обычный (Normal). Хотя последний, возможно, более понятен для новичков, так как скрипт в нем создается простым заполнением форм, но использовать его мы не будем. Дело в том, что написать при помощи него даже простую программу весьма проблематично. Лучше с самого начала привыкнуть к работе в экспертном режиме, при котором панель Actions представляет собой простой текстовый редактор. Чтобы перейти в него, нажимаем кнопку меню панели в ее правом верхнем углу и ставим флажок в строку Expert Mode (Экспертный режим).

    6. Подготовительный этап закончен. Можно приступать к написанию кода. Подумаем, что мы должны задать в самом начале. Очевидно, что нам следует привести систему в нужное исходное состояние. То есть объекты должны быть помещены в точки, в которых начнется их движение. Почему этого нельзя сделать вручную? Во-первых, позиционировать символы с точностью до пикселя весьма непросто, и, во-вторых, если расположить их произвольным образом и написать код исходя из значений в соответствующих окошках инспектора свойств, то будет достаточно легкого смещения одного из объектов, чтобы все перестало работать. Итак, чтобы поместить экземпляр ball в нужную точку:
  • Пишем "адрес" объекта. Так как в нашем случае экземпляры находятся на той же временной шкале, что и сам код, то задавать путь необязательно.
  • Задаем имя экземпляра и ставим точку: "ball.". Это означает, что нужно обратиться к какому-то методу или свойству объекта с именем "ball".
  • Задаем имя свойства, к которому следует обратиться. В нашем случае это координата по оси X: "ball._x". Знак подчеркивания в начале имени свойства — это особенность синтаксиса ActionScript, характерная для всех свойств: _rotation, _xscale, _alpha. Если свойство было задано верно, то оно будет подсвечено синим цветом. Вообще подсветка — это отличный подсказчик при написании сценариев: в случае ошибки команда из лексикона языка программирования не подсветится, и вы легко найдете ошибку в ее синтаксисе.
  • Так как экземпляр ball уже присутствует на экране, то его свойство _x уже имеет конкретное значение. Нам же нужно переопределить его. Сделать это можно при помощи оператора присваивания, задающегося при помощи обычного "=" (логическое равенство чего-либо чему-либо проверяется в ActionScript при помощи оператора "=="): "ball._x=".
  • Координаты документа на главной временной шкале отсчитываются по-другому, чем принято в декартовой системе. Точкой (0,0) является верхний левый угол листа. Ось X направлена слева направо, а ось Y — сверху вниз. Таким образом, если мы хотим поместить объект левее видимой области, то его свойству _x должно быть определено некоторое отрицательное значение. Так как общая длина листа составляет 550 px, то приемлемой цифрой будет -50. Пишем: "ball._x=-50".
  • Ставим ";". Точка с запятой в ActionScript (да и во всех С-подобных языках) обозначает конец строки. Этот знак надо ставить после любого определения или вызова метода. В том случае, если вы его пропустите, программа может выполниться некорректно или не выполниться в принципе. Когда вы работаете в экспертном режиме, очень важно следить за правильностью синтаксиса. Помните, что обязательно нужно завершать строки символом ";", согласовывать количество открывающих и закрывающих скобок в функциях, циклах и условиях. Много ошибок связано с использованием прописной литеры (для программы "flash" и "Flash" это разные объекты).
  • Аналогичным образом определяем координату экземпляра по Y. Так как мяч должен начать движение где-то с точки, расположенной на уровне 3/5 от всей ширины рабочей области (равной 400 px), а ось направлена сверху вниз, то подходящим значением будет 170.

  • Полный текст скрипта, позиционирующего "тело" мяча в нужной точке:

    ball._x=-50;

    ball._y=170;

    1. Теперь нужно поместить в ту же точку, что и сам мяч, его контур:
    2. contour._x=-50;

      contour._y=170;

    3. Чтобы убедиться в том, что введенный код действует, нажмите <Ctrl>+<Enter>. Вы увидите, что, первоначально расположенные стихийно, объекты были совмещены и выглядят, как один цельный предмет. Кстати, просто проиграв кадр при помощи команды Play (Прокрутить) меню Control (Контроль) (или нажав <Enter>), вы подобного результата не получите — поэтому ввиду ограниченности далее использовать ее мы не будем.
    4. Далее необходимо определить, как часто мы будем производить изменение в положении объектов, связанных с их движением. Мы создадим специальный объект — функцию, которая будет запускаться каждый новый кадр и менять положение мяча и тени. Для этого:
  • Вводим "_root.onEnterFrame". Это означает, что мы заставляем "слушать" объект _root (основную временную шкалу) событие onEnterFrame (системный обработчик события наступления нового кадра). В принципе, вместо _root можно использовать любой "слушающий" системные события объект (называемый листенером (Listener)), например, видеоклип contour.
  • Указываем системе, что именно следует выполнять в случае наступления "прослушиваемого" события. В нашем случае это будет функция, содержащая управляющий движением объекта код. Поэтому пишем: "_root.onEnterFrame=function(){}". Разберемся в приведенной записи:
  • function — это служебное слово, регистрирующее функцию. В ActionScript понятие "функция" не идентично математическому смыслу этого слова. Функция — это подпрограмма, выполнение которой может быть вызвано отовсюду при помощи ее имени-идентификатора. Функции используются тогда, когда одно и то же действие должно быть повторено много раз (или в том случае, если один и тот же код должен быть применен в разных местах).
  • Круглые скобки. Служат для задания параметров. В нашем случае пустые.
  • Ажурные скобки. В них задается текст функции — действия, которые должны быть выполнены при ее вызове. Очень важно не потерять одну из скобок — иначе функция работать не будет. После определения функции (это важно) точка с запятой не ставится.
  • Чтобы убедиться, что созданный код работает, введите в ажурные скобки функции следующий скрипт и протестируйте фильм:
  • ball._x+=2;

    contour._x+=2;

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

    1. Самое трудное. Нужно описать в ажурных скобках созданной функции движение мяча. Для этого придется немного вспомнить курс механики за 9 класс.

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

      Если вы помните, в механике координата ускоренно движущегося тела определяется по формуле Y=Y0+Vy0´fSymbol;t+1/2´fSymbol;a´fSymbol;t2, где Y0 —начальное положение, Vy0 — начальная скорость вдоль соответствующей оси, a — ускорение, t — время движения. Ее-то мы и используем, присваивая в каждом новом кадре координате y мяча вычисляемое по ней значение:

      ball._y=Y0+Vy*t+a*t*t/2;

      Символом "*" в ActionScript задается умножение. Через него же определен и квадрат времени, так как использование для этого специального метода слишком громоздко.

      Движение мяча по горизонтали равномерно, поэтому и формула используется более простая: X=X0+Vx´fSymbol;t, где X0 — координата по оси абсцисс начальной точки, Vx — скорость в рассматриваемом направлении, t — время движения. В форме скрипта:

      ball._x=X0+Vx*t;

    3. При задании уравнений движения нами были использованы переменные. Теперь необходимо их явно определить и присвоить им подходящие значения. Сделать это надо вне пределов тела функции, так как некоторые из переменных будут изменять свои значения в ходе движения мяча (записанные же в ее ажурных скобках они будут принимать свою первоначальную величину при каждом ее вызове). Поэтому выше функции вводим:
    4. var t=0;

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

      То, почему время задается равным нулю, очевидно.

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

      Итак, данному выше описанию должен соответствовать следующий скрипт:

      var X0=50;

      var Y0=170;

      var t=0;

      var a=2;

      var Vy=0;

      var Vx=6;

    5. Теперь нужно определиться, что у нас будет выступать в качестве времени. Привязаться к номеру кадра мы не можем — он у нас только один. Мы поступим по-другому: при каждом запуске функции будем прибавлять к переменной t некоторую величину (ее подходящее значение подберем потом эмпирически). Это даст тот же эффект, что и привязка к реальным "часам". Необходимый код:
    6. t+=0.6;

      Оператор "+=" служит для увеличения переменной или свойства на определенную величину. Аналогичный оператор для вычитания значения — "-=" (что достаточно очевидно).

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

    7. Тестируем фильм. В том случае, если мяч не будет двигаться по параболе, набирая скорость, проверяем верность введенного кода.
    8. Далее следует описать то, что должно произойти при столкновении мяча с "полом". Однако прежде нужно разобраться, как мы будем узнавать об ударе. Так как единичное перемещение объекта в нашем случае невелико, то наиболее удачным признаком этого будет превышение координатой Y мяча некоторого порогового значения:
    if (ball._y>350){}

    "if" — это логический оператор условия. В том случае, если выполняется предложение в его круглых скобках, то (подобно функциям) запускается код в его ажурных скобках. Точка с запятой после "if" не ставится.

    В ажурных скобках оператора условия следует прописать следующие действия:

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

  • newV=Vy+a*t;

  • Итак, переменной Vy присваиваем значение, равное переменной newV. Помимо этого, так как при ударе мяч должен потерять часть энергии, вводим понижающий коэффициент:

  • Vy=-newV*0.85;

  • В результате удара должна уменьшиться и горизонтальная (ранее неизменная) составляющая скорости:

  • Vx=0.85*Vx;

  • Изменение знака скорости — это операция, требующая, чтобы координаты начальной точки (X0,Y0) были заменены на координаты точки отскока (подумайте, почему). Поэтому так же, как и для вертикальной составляющей скорости, вводим "следящие" переменные в теле функции для координат мяча:
  • newY=ball._y;

    newX=ball._x;

  • При выполнении условия отскока их значения должны быть присвоены переменным X0 и Y0:
  • X0=newX;

    Y0=newY;

  • Так как была изменена начальная точка, время должно быть обнулено. Но чтобы код не прокрутился вхолостую, присвоим переменной t ее шаговое значение:
  • t=0.6;

    Скрипт условного оператора должен быть помещен выше остального кода в теле функции.

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


    2. _root.onEnterFrame=function(){

      if(ball._y>350){

      Vy=-newV*0.85;

      Vx=0.85*Vx;

      t=0.6;

      X0=newX;

      Y0=newY;

      }

      ball._y=Y0+Vy*t+a*t*t/2;

      ball._x=X0+Vx*t;

      newV=Vy+a*t;

      newY=ball._y;

      newX=ball._x;

      t+=0.6;

      };

    3. Описываем движение контура мяча. В качестве тренировки добавьте необходимый код самостоятельно. Подсказка: для этого достаточно всего двух строк скрипта.
    4. Помимо простого перемещения, контур должен еще и вращаться. Угол поворота (в радианах) объекта определяет свойство "_rotation". Оптимальная величина поворота определяется подбором:
    contour._rotation+=8;

    Код для перемещения тени напишите самостоятельно. Это будет неплохое домашнее задание, выполнив которое, вы без труда разберетесь со всеми тонкостями созданной нами программы. Подсказка: изменять размеры тени (в процентах) вы сможете при помощи свойств "_xscale" и "_yscale".

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



    Рис.5. Траектории движения мяча

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

    Дмитрий Гурский, Юрий Стрельченко, dot@omen.ru


    Компьютерная газета. Статья была опубликована в номере 09 за 2003 год в рубрике soft :: графика

    ©1997-2024 Компьютерная газета