Клипы как носители кода

Первые скриптовые команды Flash были предназначены для навигации по временной диаграмме.

Это аналоги современных методов gotoAndPlay(), gotoAndStop(), play(), stop(). Данные команды помешались на кадры, и при их проигрывании соответствующие действия выполнялись. Подобный подход позволял сделать управление прокруткой фильма предельно простым и избежать введения дополнительных структур языка. От версии к версии скриптовый язык Flash все усложнялся, но код по-прежнему размещался на кадрах (появились также сценарии кнопок и клипов — но на данный момент их использование не рекомендовано, поэтому обсуждать мы их не будем). Во Flash 5 ActionScript превратился в серьезный язык программирования.

Возникает вопрос: оправданна ли сейчас привязка исполнимого кода к кадрам временной диаграммы в той же степени, что и во времена FutureSplash? Ответить на поставленный вопрос не так просто. В зависимости от того, задачи какой сложности решаются при помощи ActionScript, на него можно дать как положительный, так и отрицательный ответ.

Подавляющим большинством пользователей ActionScript используется на самом элементарном уровне. Обычно запросы к скриптовому языку Flash ограничиваются командами навигации по временной шкале, несколькими событиями (чаще всего — onRelease — событием нажатия кноп-ки), функцией getURL(), методом loadMovie().


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

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

Труднее будет разобраться в сценарии вашим коллегам — следовательно, они не смогут дать вам дельного совета. Когда вы вернетесь к своей работе через несколько месяцев, чтобы внести в нее изменения, вам придется потратить много времени, чтобы понять, как же эти разрозненные кусочки кода взаимодействуют. В общем, можно сделать однозначный вывод: если ваш сценарий превышает 30-50 строчек, его код должен быть централи зова 14 и, в идеале, размешен на первом кадре первого слоя основной временной диаграммы.


Исключение представляют только фильмы с прелоадерами: в этом случае допустимы два кадра с кодом.

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

Но централизация означает, что все преимущества, обусловленные размещением кода на временной диаграмме (простота, интуитивность), теряются. Недостатки же остаются в целости и сохранности. «Как? — спросите вы. — Есть еще какие-то недостатки помимо децентрализации?» Увы — да. Правда, они носят достаточно тонкий характер и являются скорее преградой к построению стройной схемы языка, чем для эффективного написания сценариев.

Значительное количество нелепостей возникло в ActionScript из-за того, что выбранный в качестве его основы ECMAScript создавался, естественно, без учета специфики Flash. По этой причине многие понятия, абсолютно очевидные в JavaScript, в ActionScript становятся запуганными и даже таинственными. Приведем несколько примеров:

• В ActionScript переменные являются одновременно свойствами клип а-носителя кода. По этой причине разница между понятиями «переменная» и «свойство» стирается настолько, что невозможно обнаружить между ними хоть какое-то различие.


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

• В ECMAScript разница между переменными и свойствами достаточно прозрачна. Переменная — это именованный объект данных, находящийся в цепочке областей видимости исполнимого кода, Свойство — это именованный объект данных, «адресом» которого является объект или присущая ему цепочка наследования. Так как в ActionScript код расположен на временной диаграмме, то в его цепочку областей видимости входят клип-носитель и объект Global, косвенно — прототипы конструкторов MovieClip и Object. Это означает, что, например, сохранив свойство в Object.prototype, мы сможем получить к нему доступ как к свойству любого объекта и как к переменной любого исполнимого кода. В результате нивелируются различия между понятиями «переменная» и «свойство», «цепочка областей видимости» и «цепочка прототипов».

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

Последовательность выполнения кода
Код должен быть централизован. Это одно из важнейших правил эффективного программирования во Flash. Однако иметь четкое представление о том, в какой последовательности выполняются фрагменты сценария, распределенного по нескольким кадрам, все равно нужно. Зачем? Хотя бы, чтобы быть способным найти причину сбоя в фильме коллеги, не считающего, что код нужно централизовать.

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

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

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

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

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

Если код распределен по кадрам нескольких слоев, то выполнен он будет сверху вниз. Причем на последовательность исполнения его фрагментов не повлияет порядок загрузки элементов (сверху вниз или снизу вверх), установленный для данного фильма (отвечает за это опция Load Order закладки Flash панели Publish Settings).

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

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

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

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

_root.attachMovie("ball","new_ball",0); // Если код расположен на
// такая запись избыточна
attachMovie("ball","new ball",0); // Техничная запись

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

Для некоторых из них это приведет к ошибке. Например:

_root.startDrag(); // Данная директива делает основную временную шкалу
// протаскиваемой
startDrag(); // Строчка вызывает сшибку

То, что часть методов класса MovieClip не может быть применена без явного указания вызывающего их объекта, обусловлено исторически. Возможности, носителями которых данные методы являются, появились еще во Flash 4 (а некоторые даже раньше). ActionScript в те далекие времена не был основан на ЕСМА-262, поэтому ни объектов, ни методов в нем не было. Операции же над клипами осуществлялись при помощи функций, называвшихся действиями (actions). Данные функции сохранились и в современном ActionScript (во встроенном словаре они находятся в разделе Global Functions в директориях Timeline Control и Movie Clip Control). Они имеют такие же имена, как соответствующие методы, что является источником многочисленных сложностей. Например, существует как метод startDrag(), так и одноименная глобальная функция. То, какой инструмент будет задействован, определяется контекстом.

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

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

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

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

duplicateMovieClipt) // Создает копию клипа
loadMovie() // Подгружает внешний swf-файл
startDrag() // Делает клип протаскиваемым
stopDrag() // Отключает режим протаскивания
removeMovieClip() // Удаляет клип
unloadMovie() // Выгружает клип
loadVariables() // Подгружает в клип внешние текстовые данные

Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Action Script на эту тему:
Виртуальные слои клипов
Задание формулы цвета
Имена экземпляров клипов
Импорт внешних фильмов и изображений
Коллизии клипов. Метод hitTest()

Вернуться в раздел: Action Script / 10. Клипы