В этом уроке:

Приложение для рисования – один из проектов, которые мы создадим в этом уроке в ходе изучения различных способов динамического управления клипами.
На выполнение этого урока требуется примерно один час.
Файлы-носители:
Нет
Стартовые файлы:
Lesson14/Assets/scrollingList1.fla Lesson14/Assets/draw1.fla
Законченные проекты:
scrollingList3.fla draw5.fla
Для динамического создания экземпляра фильма-символа предназначены три метода объекта
Каждый из этих методов мы с вами применим в ходе выполнения упражнений этого урока.
Мы уже познакомили вас с этим методом в Уроке 10 – Автоматизация скриптов с помощью циклов, однако сделали это бегло, не вдаваясь в детали. Теперь, наконец, вы узнаете все об этом мощном методе!
Метод duplicateMovieClip() служит для Flash указанием создать дубликат имеющегося на сцене экземпляра фильма-символа, дав ему новое имя. Если указанный экземпляр клипа на сцене не присутствует (находится в одном из предыдущих или последующих кадров), то Flash не сможет дублировать его. Другое ограничение состоит в том, что дубликат может быть создан только на том же самом монтажном столе, где находится оригинал. Для динамического создания экземпляра клипа на любом монтажном столе следует применять метод – мы еще поговорим о нем в этом уроке.
Создаваемый дубликат наследует все физические свойства, которые имел оригинал на момент дублирования.
Дубликат фильма-символа наследует следующие свойства оригинала:
Дубликат фильма-символа не наследует:

Примечание Воспроизведение экземпляра-дубликата начинается с кадра 1, даже если оригинальный клип в момент дублирования находился на другом кадре.
Синтаксис дублирования экземпляра фильма-символа таков:
myClip.duplicateMovieClip(имя, глубина, объект);
Эта строка duplicateMovieClip() объекта . В результате создается новый экземпляр, именем которого будет значение параметра имя, на глубине глубина. Параметр объект – не обязательный. Пример:
name = "ball2"; depth = 100; ball.duplicateMovieClip(name, depth);
Эти три строки создают дубликат экземпляра клипа экземпляр-дубликат получает имя ball2 и располагается на глубине 100.
Примечание Говоря здесь о глубине ( depth ), мы подразумеваем
Каждый монтажный стол в фильме имеет диапазон глубин от -16384 до 1048575, причем все отсчеты глубин ведутся относительно главного монтажного стола фильма. Иными словами, некий "экземпляр 1" может содержать дочерние экземпляры, расположенные на его монтажном столе на глубинах от -16384 до 1048575. Но если на основном монтажном столе "экземпляр 1" находится под "экземпляром 2", то всякий, даже самый верхний дочерний экземпляр "экземпляра 1" окажется ниже самого нижнего из дочерних экземпляров "экземпляра 2".

На каждой глубине в каждый момент времени может располагаться только один экземпляр фильма-символа. Попытавшись дублировать экземпляр клипа на глубину, где уже имеется другой экземпляр, вы тем самым уничтожите этот второй экземпляр.
Итак, каждый монтажный стол имеет 1064960 уровней глубины (от -16384 до 1048575). При этом глубины разных монтажных столов никоим образом не пересекаются между собой.
Третий параметр метода duplicateMovieClip(), параметр объект, необязателен, но отнюдь не бесполезен. Свойства объекта, указанного в качестве этого параметра, станут элементами данных нового дубликата клипа. Если параметр опущен, он игнорируется. Расширим немного предыдущий пример:
myObject = new Object(); myObject.ballColor = "red"; name = "ball2"; depth = 100; ball.duplicateMovieClip(name, depth, myObject);
Новый экземпляр-дубликат ball2 будет содержать все свойства объекта myObject. В данном случае в новом экземпляре будет создана переменная ballColor со значением "red".
Совет Если нужно скопировать переменные из оригинального экземпляра в дубликат, следует использовать в качестве третьего параметра имя оригинального экземпляра. Например:
ball.duplicateMovieClip(name, depth, ball);
C помощью метода можно взять фильм-символ из библиотеки и динамически "присоединить" ( ) экземпляр его к любому монтажному столу из имеющихся в данный момент в сцене фильма – при этом, естественно, все содержимое этого экземпляра добавится к содержимому фильма, к которому он присоединяется. Присоединенный клип становится дочерним по отношению к монтажному столу, к которому он присоединен. Он наследует все графические трансформации, выполняемые над родителем (изменения размеров, прозрачности, повороты и т.п.), при этом сохраняя самостоятельность в отношении данных, видимости, текущего кадра и т.п. (подробнее об отношениях родитель/

В чем же состоят отличия этого метода от метода duplicateMovieClip()? Как уже было сказано, присоединяет экземпляр клипа из библиотеки к любому из монтажных столов в фильме. Поскольку присоединяемый клип берется из библиотеки (а библиотека содержит все клипы фильма), клип, к которому присоединяется экземпляр, не обязан находиться на сцене в момент присоединения. С методом duplicateMovieClip() все наоборот: экземпляр клипа, который подлежит дублированию, должен находиться на сцене. Более того, дубликат создается только на том же монтажном столе, что и оригинал. Еще одно различие состоит в следующем. Если дублируемый экземпляр имеет присоединенные к нему обработчики событий ( data, enterFrame, mouseDown и т.п.), то дубликат автоматически наследует их. С присоединяемым клипом такого не происходит. Конечно, имеются способы добавить обработчики событий и к присоединяемому клипу, но этот процесс не столь прост, как при дублировании.
Проще говоря, присоединение позволяет, в сущности, добавить любой монтажный стол на любой другой монтажный стол. Дублирование позволяет только создавать точные копии экземпляра клипа в пределах того монтажного стола, где находится оригинал.

Применение метода требует выполнения некоторых условий. Первое условие состоит в том, что находящиеся в библиотеке клипы, предназначенные для присоединения, следует должным образом подготовить. Такая подготовка называется связыванием. Возможно,
Пошаговый процесс
Linkage ).Export for ActionScript ).Identifier ) (этот идентификатор будет служить в Совет Установить связь можно также при создании фильма-символа, нажав в диалоговом окне Преобразовать в символ ( ) кнопку Расширенный ( Advanced ).

Примечание При связывании обратите внимание еще на одну опцию – "Экспорт в первый кадр" ( ), которая включается по умолчанию. Эта опция определяет, в какой момент будет загружаться связанный (или присоединяемый) фильм-символ при просмотре фильма. Если флажок установлен, то клип будет загружен до кадра 1 основного фильма, и, таким образом, его содержимое будет доступно прежде, чем будет предпринята любая попытка присоединить его (например, уже в кадре 1). При использовании крупных клипов (таких, которые содержат много других фильмов-символов или звукозаписей) Flash может в начале фильма "затормозить". Не стоит беспокоиться: просто происходит загрузка содержимого всех связанных фильмов-символов. Если флажок "Экспорт в первый кадр" не установлен, то фильм-символ не будет загружаться перед первым кадрам. В этом случае вы должны поместить экземпляр такого клипа на сцену до того, как попытаетесь присоединить его. После того, как фильм-символ будет обработан (появится
в фильме) в каком-либо кадре, его можно будет присоединять когда и где угодно. Например, если в кадре 25 имеется действие, присоединяющее клип, то экземпляр этого клипа должен появиться в фильме в кадре 24 или раньше – иначе метод не сработает. После кадра 24 присоединять экземпляры этого клипа можно сколько угодно, поскольку он уже загружен в память.
Вот синтаксис присоединения к монтажному столу фильма-символа из библиотеки:
путь.attachMovie(идентификатор, новоеИмя, глубина, объект);
Например:
_root.wall.attachMovie("paint", "paint2", 10);
Этот скрипт присоединит фильм-символ из библиотеки, имеющий идентификатор ", к экземпляру фильма-символа _root.wall. Новый присоединенный экземпляр получит имя paint2 и будет помещен на глубину 10. Присоединенный клип станет дочерним для того экземпляра, к которому он присоединен, так что путь к нему будет выглядеть как _root.wall.paint2. Обратите внимание на пример синтаксиса (первая строка): здесь тоже имеется опция, позволяющая наполнить создаваемый клип свойствами и переменными объекта. Как и для duplicateMovieClip(), эта опция необязательна и в нашем примере (вторая строка) опущена.
Совет Простейший способ динамически назначить события клипа присоединенному (или
_root.attachMovie("box", "dynamicBox", 1);
dynamicBox.onEnterFrame = function(){
dynamicBox._rotation += 15;
}
В этом примере экземпляр фильма-символа (это его имя в библиотеке) динамически присоединяется к основному монтажному столу. Присоединенный экземпляр получает имя dynamicBox. Строки, следующие за действием присоединения, назначают обработчик события клипа для нового экземпляра.
Метод createEmptyMovieClip() позволяет динамически создать (на любом монтажном столе) новый экземпляр пустого фильма-символа. Для чего это может понадобиться? Вот несколько примеров.
Синтаксис создания экземпляра пустого фильма-символа следующий:
путь.createEmptyMovieClip(имя, глубина);
Например:
_root.createEmptyMovieClip("box", 1);
Здесь первый параметр – имя, которое будет присвоено новому экземпляру пустого клипа; второй параметр – глубина, на которую будет помещен этот экземпляр. Если вы попытаетесь протестировать это действие, то не обнаружите никакого видимого результата – ведь созданный экземпляр совершенно пуст. В этом уроке мы с вами используем метод createEmptyMovieClip() для динамического рисования линий.
Метод создает новый экземпляр фильма-символа из библиотеки. В этом упражнении мы с вами создадим проект, при запуске которого на сцене будет отображаться прокручиваемый список. Элементы этого списка будут создаваться посредством динамического присоединения экземпляров клипа.
На основном монтажном столе мы видим три слоя: Actions, Window и Background. Слой Background содержит общее графическое оформление проекта; в слой Actions мы поместим большинство скриптов; а в слое Window находится экземпляр фильма-символа под названием display.
Внутри монтажного стола display вы найдете четыре слоя: list, к которому мы будем присоединять экземпляры, создавая их при помощи . Эти присоединенные экземпляры станут элементами списка, располагаясь один под другим. Список (экземпляр клипа list ), будучи наполнен присоединенными к нему экземплярами, станет довольно-таки длинным. Поэтому мы маскируем list прямоугольником, находящимся в слое list, находящаяся "внутри" окна.

Теперь этот клип готов к использованию методом .
Для каждой строки в прокручиваемом списке к экземпляру list будет присоединяться один экземпляр клипа infoBar (16 строк, 16 присоединений). Внутри каждого из присоединенных клипов будет два moonName и moonNum; в этих полях будут отображаться названия лун Юпитера и соответствующие номера.

list = ["Adrastea", "Amalthea", "Ananke", "Callisto", "Carme", "Elara", "Europa", "Ganymede", "Himalia", "Io", "Leda", "Lysithea", "Metis", "Pasiphae", "Sinope", "Thebe"];
Цель этого упражнения – создать список, элементами которого будут присоединенные экземпляры фильма-символа. Для этого мы прежде всего создаем массив из названий 16 наиболее известных лун Юпитера. Для каждой луны из этого массива к экземпляру list мы должны присоединить экземпляр клипа из библиотеки.
Теперь нужно описать функцию, которая и будет создавать список из экземпляров клипа.
function buildList() {
spacing = 30;
}
В конечном итоге функция buildList() будет содержать все действия, необходимые для присоединения, spacing и присваиваем ей значение 30 – эта переменная будет определять дистанцию по вертикали (y) между центрами присоединенных экземпляров клипа.
var i = -1;
while (++i < list.length) {
name = "infoBar" + i;
y = i * spacing;
display.list.attachMovie("infoBar", name, i);
display.list[name]._y = y;
display.list[name].moonName.text = list[i];
display.list[name].moonNum.text = i + 1;
}
В этой части функции используется цикл while, перебирающий поочередно все элементы массива list. Для каждого элемента массива цикл присоединяет к экземпляру list экземпляр клипа infoBar.
Первым действием в name, значение которой задается выражением, которое присоединяет к строке "infoBar" текущее значение i. Поскольку значение i при каждом проходе цикла увеличивается на единицу, name будет принимать значения "infoBar0", "infoBar1", "infoBar2" и так далее. Далее в name будет использовано для присвоения имени каждому успешно присоединенному экземпляру клипа infoBar. А пока в цикле создается переменная y, которая будет хранить y-координату присоединяемого в данный момент экземпляра. Значение этой переменной вычисляется умножением текущего значения i на значение spacing. Поскольку значение i при каждой итерации увеличивается, то же будет происходить и со значением y. В результате присоединенные экземпляры будут располагаться друг под другом.
Последние четыре действия в infoBar, имя и глубина которого содержатся в переменных name и i, соответственно. Далее этот присоединенный экземпляр получает y-координату, равную значению переменной y. Каждый из присоединяемых экземпляров содержит те же элементы, что и оригинал, а значит, в каждом имеется два текстовых поля: moonName и moonNum. Последние два действия в moonName присоединенного экземпляра помещается строковое значение (название луны) – i-й элемент массива list. В текстовое поле moonNum каждого экземпляра помещается числовое значение i плюс 1. Таким образом, в этом текстовом поле для соответствующих
экземпляров будут выводиться значения 1, 2, 3 и так далее.
По завершении цикла каждому элементу массива list будет соответствовать присоединенный экземпляр фильма-символа, заполненный информацией и расположенный по вертикали среди других экземпляров.


Эта строка будет вызывать только что описанную нами функцию – в результате будут выполнены все действия, запрограммированные нами на предыдущих шагах.
После инициализации фильма появится наш с вами список. Не забудьте: с помощью маски мы ограничили число одновременно видимых элементов, поэтому вы можете наблюдать только часть списка.
Мы завершили наиболее трудную часть этого урока: написали скрипт, динамически присоединяющий экземпляры фильма-символа из библиотеки для построения списка. В следующем упражнении мы продолжим работу с этим файлом и сделаем окно списка прокручиваемым.
Порой возникает необходимость в том, чтобы некие действия выполнялись непрерывно, пока нажата кнопка. Кнопки, запрограммированные таким образом, называют кнопками с непрерывной
Примечание В большинстве случаев реализовать прокрутку гораздо проще с помощью компонента Scrollbar (полоса прокрутки). Это упражнение имеет целью разъяснить вам, как вообще программируется и работает прокрутка – тогда вы сможете, при желании, внедрить собственные идеи вместо
Если информации в окне при каждом нажатии на соответствующую кнопку будет прокручиваться на одну строку, пользователь быстро устанет. Гораздо удобнее, если прокрутка при нажатой кнопке происходит непрерывно, и прекращается, когда кнопка отпущена. Во Flash это можно реализовать (вскоре мы это продемонстрируем) с помощью событий клипа enterFrame или mouseMove.
В этом упражнении мы с вами добавим кнопки прокрутки к списку, построенному нами в предыдущем упражнении.
Этот файл должен быть вам хорошо знаком – в таком виде мы оставили его по завершении предыдущего упражнения. В этом упражнении мы добавим действия
Напомним, что здесь имеется экземпляр клипа list, расположенный внутри клипа display. Все вновь создаваемые экземпляры (клипа infoBar ) помещаются в экземпляр list. Таким образом, нашей функции достаточно будет перемещать по вертикали экземпляр клипа list, чтобы создать эффект прокрутки списка.
Примечание В этом упражнении, используя термин "прокрутка", мы будем подразумевать перемещение по экрану вверх и вниз фильма-символа list путем изменения значения его свойства _y.
startingY = display.list._y;
Для правильной работы прокрутки мы должны установить максимальное и минимальное положения ( Y ), списка – задать границы прокрутки списка (вертикального перемещения). В любом приложении, где используется прокрутка, необходимо предотвращать возможность прокрутку за пределы документа. Добавленная нами строка скрипта будет использоваться для установления одной из этих вертикальных границ: прокрутка экземпляра клипа list (содержащий присоединенные экземпляры) должна прекращаться, если его Y-координата достигла стартовой Y-координаты ( startingY ). C этой целью мы и используем сейчас значение переменной startingY.

Как было сказано на предыдущем шаге, наибольшая возможная Y-координата прокрутки экземпляра клипа list – это его стартовая позиция. Переменная bottom, которую мы определяем на этом шаге, будет содержать значение координаты такое, чтобы самый нижний элемент списка не мог выйти за пределы окна. Каким образом это будет достигаться, вы поймете из следующих шагов.
function scroll (direction) {
speed = 10;
}
Впоследствии мы организуем вызов этой функции в нашем проекте посредством события enterFrame, присоединенного к экземплярам клипов, содержащих кнопки прокрутки. Одна из кнопок будет предназначена для прокрутки вверх, другая – вниз. Параметр , передаваемый этой функции, будет содержать строковое значение: "up" или "down". list вверх или вниз. Переменная – скорость прокрутки. Пока одна из кнопок удерживается в нажатом положении, экземпляр list будет перемещаться (либо вверх, либо вниз). Скорость его перемещения и определяется значением переменной . Кстати, число 10 взято вовсе не из каких-то "высших соображений"; если хотите, можете взять другое значение.
if (direction == "up") {
} else if (direction == "down") {
}
Как мы уже сказали, передается функции в качестве параметра и может принимать строковые значения "up" либо "down". Данный
if (display.list._y – speed + display.list._height > (startingY + bottom)) {
display.list._y -= speed;
} else {
display.list._y = (startingY + bottom) – display.list._height;
}
Поскольку этот
В условии оператора проверяется, где окажется нижняя грань экземпляра list при перемещении его на 10 пикселей вверх. Вычисляется это так: берется текущая Y-координата экземпляра list, из нее вычитается значение , затем прибавляется общая высота экземпляра. Полученная координата нижней грани экземпляра сравнивается с одним из ограничителей прокрутки (который получается путем сложения значений bottom и startingY ). Если в результате перемещения экземпляра list он не достиг ограничителя, то все в порядке – выполняется действие из первой секции оператора, движение экземпляра продолжается. Если же экземпляр дошел до ограничителя, выполняется секция else, и экземпляр попросту устанавливается в максимальную разрешенную координату по вертикали.

Если все это вам не совсем понятно, не расстраивайтесь: сейчас мы рассмотрим на примере, как все это работает. Для этого предположим, что элементы нашего скрипта имеют следующие значения:
speed = 10 startingX = 100 bottom = 120 display.list._height = 400 //высота (размер по вертикали) экземпляра list display.list._y = -165 //текущая координата экземпляра list по вертикали
С этими значениями if будет выглядеть следующим образом:
if (-165 – 10 + 400 > (100 + 120))
В итоге получим:
if (225 > 220)
Поскольку 225 больше 220, выполняется следующее действие:
display.list._y -= speed;
Тем самым экземпляр list переместится на 10 пикселей вверх, и его Y-координата станет равна -175. Теперь, при следующем выполнении
if (-175 – 10 + 400 > (100 + 120))
И, в итоге:
if (215 > 220)
Утверждение ложно, ведь 215 меньше 220, поэтому выполняется действие из секции else:
display.list._y = (startingY + bottom) – display.list._height;
Экземпляр list помещается в Y-координату, значение которой вычисляется в правой части этого выражения:
(startingY + bottom) – display.list._height
Подставляя наши значения, получим:
(100 + 120) – 400
Это даст
220 - 400
И в итоге
-180
Тем самым экземпляр list будет привязан к вертикальной координате -180 – нижняя грань экземпляра будет совмещена к верхнему ограничителю прокрутки – дальнейшая прокрутка экземпляра list невозможна.
Теперь давайте настроим обработку прокрутки вниз.
if (display.list._y + speed < startingY) {
display.list._y += speed;
} else {
display.list._y = startingY;
}

Эта часть list при перемещении вниз на значение не вышел за нижний ограничитель прокрутки ( startingY ). Если этого не произошло, выполняется действие из первой секции оператора, перемещающее экземпляр клипа вниз. В противном случае ( else ) нижняя грань экземпляра совмещается с нижним ограничителем прокрутки.
Описание функции мы закончили, теперь пора поработать с кнопками прокрутки.
На экране появится кнопка list , частью которого она является) мы будем использовать для прокрутки в обоих направлениях – и вверх, и вниз.
on (press) {
buttonPressed = "yes";
}
on (release, releaseOutside, dragOut) {
buttonPressed = "";
}
Эта кнопка будет попросту присваивать значение переменной buttonPressed – "yes" или "", в зависимости от действий пользователя. Если пользователь нажал эту кнопку, buttonPressed получает значение "yes". Если пользователь отпускает кнопку мыши (неважно, где при этом находится указатель – на кнопке или за ее пределами), переменная buttonPressed получает значение "". На следующем шаге мы используем значение этой переменной.
Монтажный стол этого клипа содержит два экземпляра фильма-символа list , который содержит кнопку down, а нижний экземпляр – up.
Как вы помните, при нажатии кнопки, имеющейся в каждом из этих двух экземпляров, переменная buttonPressed получает значение "yes". Важно понимать, что каждый из экземпляров представляет собой самостоятельный монтажный стол. Нажатие кнопки, находящейся в одном из экземпляров, изменит значение переменной buttonPressed только на этом монтажном столе; на переменную другого экземпляра это событие никак не повлияет.
onClipEvent (enterFrame) {
if (buttonPressed == "yes") {
_root.scroll("down");
}
}
Мы используем событие enterFrame: buttonPressed на монтажном столе этого клипа, и если это значение равно "yes", будет вызывать функцию с главного монтажного стола. Это – основа принципа действия нашей кнопки с непрерывной buttonPressed имеет значение "yes" (то бишь, пока кнопка внутри данного экземпляра нажата), происходит прокрутка. Параметр "down", передаваемый функции , дает ей знать, в каком направлении должна происходить прокрутка.
onClipEvent (enterFrame) {
if (buttonPressed == "yes") {
_root.scroll("up");
}
}
Скрипт идентичен тому, что был на предыдущем шаге, только функции передается другое значение параметра – "up".
Давайте пустим в дело кнопки, чтобы проверить наши скрипты. Нажмите и удерживайте кнопку "вниз", чтобы начать прокрутку, потом попробуйте другую кнопку. Как видите, когда экземпляр list достигает верхнего или нижнего предела, прокрутка останавливается.
Итак, мы с вами в этом упражнении организовали с помощью
Посредством , предназначенными для рисования.
Методы рисования позволяют:
В этом разделе вы научитесь рисовать линии, перемещать "курсор рисования", задавать стиль линий и очищать от рисунков экземпляр фильма-символа. В следующем разделе мы коснемся обычных и градиентных заливок. Метод curveTo() (позволяющий динамически рисовать кривые) мы здесь описывать не станем, однако к концу этого урока вы в достаточной степени овладеете основами динамического рисования во Flash, так что сможете без проблем использовать в своих приложениях и этот метод.
Прежде, чем рисовать на монтажном столе какие-либо линии, необходимо установить стиль линий для этого монтажного стола. Это значит, что нужно указать Flash:
Синтаксис таков:
путь.lineStyle(толщина, цвет, прозрачность)
В качестве значения толщины линии следует указать целое число от 0 до 255 (значению 0 соответствует самая тонкая линия). Цвет линии указывается в виде шестнадцатеричного кода. Прозрачность – число от 0 (полностью прозрачная) до 100 (полностью непрозрачная). Рассмотрим пример:
_root.myClip.lineStyle(10, 0x009900, 100);
Эта строка скрипта устанавливает стиль линий для myClip: все линии, изображаемые в этом клипе, будут зелеными, непрозрачными, толщиной 10.
Каждому экземпляру фильма-символа присуще такое свойство, как lineTo() (смотри следующий подраздел). Другими словами, это стартовая точка очередной линии. При создании экземпляра курсор рисования устанавливается в позицию с координатами x=0, y=0. Однако курсор рисования можно в любой момент переместить с помощью метода moveTo().
Синтаксис применения moveTo() следующий:
путь.moveTo(x, y);
Все, что нужно – это указать координаты x и y для нового положения курсора рисования. Например:
_root.myClip.lineStyle(10,0x009900,100); _root.myClip.moveTo(100,100);
Этот скрипт устанавливает стиль линии, а затем перемещает курсор рисования.
Метод lineTo() объекта рисует на указанном lineStyle данного монтажного стола) от текущей позиции курсора рисования до точки, указанной при вызове метода.
Синтаксис lineTo() прост:
myClip.lineTo(x,y);
Параметры x и y, как вы догадываетесь, определяют конечную точку рисуемой линии.
Совет После того, как линия нарисована, текущая
Вот пример рисования линии с использованием всех описанных нами методов:
_root.createEmptyMovieClip("canvas",1);
_root.canvas.lineStyle(2,0x009900,100);
_root.canvas.moveTo(100,100);
_root.canvas.lineTo(200,150);
Этот скрипт нарисует линию между точками (100, 100) и (200, 150).
В этом упражнении мы с вами, используя методы рисования объекта , мы начнем создавать несложное приложение, позволяющее пользователю рисовать.
Основной монтажный стол состоит из пяти слоев, названных в соответствии с их содержимым. Слой Background содержит общее графическое оформление проекта. В слое – это будет рабочая область для рисования. Слой , в следующем упражнении мы создадим дубликаты этого экземпляра, предоставив пользователю несколько значков, которые он сможет перетащить на сцену, чтобы рисовать поверх шаблона. В слое Controller находится особый экземпляр клипа – он называется controller и представляет собой так называемый клип-контроллер (в принципе, это просто экземпляр, который будет содержать большую часть скриптов, обеспечивающих работу нашего проекта). И, наконец, в слое Windows находятся два экземпляра – window1 и window2; они расположены в правой части сцены и пригодятся нам в одном из
следующих упражнений.

Основной целью данного упражнения будет создание скрипта, который даст возможность рисовать в предназначенной для этого рабочей области. Мы используем события клипа в сочетании с методом hitTest(), чтобы отслеживать нажатия кнопки мыши в пределах экземпляра . После этого для рисования мы используем событие клипа mouseMove. Каждый раз при наступлении события mouseMove положение мыши будет записываться и будет рисоваться линия от предыдущей координаты мыши к текущей координате.
onClipEvent (mouseUp) {
down = false;
}
Как мы уже сказали, большую часть действий для обеспечения работоспособности проекта мы будем помещать в экземпляр controller. Данный скрипт создает переменную с именем down, которая будет хранить текущее состояние мыши. С помощью события mouseUp эта переменная будет при отпускании кнопки мыши получать значение false, показывая другим скриптам, что кнопка мыши не нажата.
onClipEvent (mouseDown) {
if (_root.canvas.hitTest(_root._xMouse,_root._yMouse)) {
x = _root._xMouse;
y = _root._yMouse;
_root.holder.moveTo(x,y);
down = true;
}
}
При нажатии кнопки мыши ( mouseDown ) . Если это так, то выполняется несколько действий. Во-первых, координаты мыши по x и y записываются в качестве значений переменных x и y соответственно. Затем эти значения используются в методе moveTo() для перемещения курсора рисования клипа в текущие координаты мыши. Клип – это пустой экземпляр, который будет создаваться динамически (мы запрограммируем это на следующем шаге). Этот-то экземпляр и будет содержать все нарисованные линии. Последнее действие этого скрипта присваивает переменной down значение true, означающее, что кнопка мыши нажата.
onClipEvent (load) {
currentColor = "7F6696";
_root.createEmptyMovieClip("holder",100);
}
В нашем приложении цвет всех рисуемых линий будет зависеть от текущего значения переменной currentColor. В этом скрипте этой переменной присваивается начальное значение – то, которое она получит при запуске приложения. В следующем упражнении мы запрограммируем динамическое изменение этого значения – оно будет изменяться при помощи кнопок в одном из клипов-окон (в правой части), что даст пользователю возможность менять цвет линий.
Следующая строка этого скрипта создает пустой экземпляр фильма-символа под именем . Как было сказано, именно этот клип будет содержать все рисуемые линии. Он располагается на глубине 100, так что нарисованные линии будут располагаться поверх всех шаблонов, которые пользователь перетащит на сцену.
function draw() {
_root.holder.lineStyle(0, parseInt(currentColor,16) ,100);
x = _root._xmouse;
y = _root._ymouse;
_root.holder.lineTo(x, y);
}
Понятно, что эта функция будет вызываться обработчиком события mouseMove, который мы еще не описали. Функция при вызове первым делом устанавливает стиль линий. Как видите, линии будут самыми тонкими (толщина 0), на 100% непрозрачными, цвет же линий зависит от текущего значения переменной currentColor. Три последние строки функции обеспечивают рисование линии. Линия проводится методом lineTo() от текущего положения курсора рисования (установленного посредством moveTo() в нашем обработчике события mouseDown ) до текущего положения курсора мыши (значения x и y в этом скрипте).
onClipEvent (mouseMove) {
updateAfterEvent();
if (down _root.canvas.hitTest(_root._xMouse, _root._yMouse)) {
draw();
}
}
Событие mouseMove наступает всякий раз при перемещении мыши. Функция updateAfterEvent() – if проверяет, чему равна переменная down и находится ли мышь над областью рисования ( ). Если и то, и другое – true, вызывается функция draw(). Таким образом, повторяющийся вызов этой функции создает эмуляцию рисования, пока мышь находится над и ее кнопка нажата. Оператор if предотвращает вызов функции draw(), когда кнопка мыши отпущена или мышь выведена за пределы экземпляра .

Когда вы, наведя мышь на область рисования, нажмете кнопку, переменной down будет присвоено значение true – и это значит, что при всяком перемещении мыши будет рисоваться линия. Если мышь покидает пределы клипа , рисование прекращается.
Теперь мы готовы активировать окна справа от области рисования, а также добавить возможность перетаскивания значков-шаблонов в рабочую область.
Хотя для этого раздела упражнение не предусмотрено, рисование закрашенных фигур обсудить необходимо.
С помощью синтаксических конструкций с использованием методов рисования, которые мы с вами уже применяли в этом уроке, можно нарисовать замкнутый контур, а затем заполнить получившуюся фигуру сплошным цветом или
Чтобы создать заливку, прежде всего следует дать Flash знать, где будет находиться фигура, которую следует закрасить. Делается это при помощи следующего метода:
путь.beginFill(color, alpha)
Путь указывает на монтажный стол, на котором будут располагаться линии. Параметр color – шестнадцатеричный код цвета. Второй параметр – alpha – означает степень прозрачности заливки: число от 0 до 100. Чтобы сообщить Flash о том, что рисование фигуры завершено, следует применить следующий метод:
путь.endFill()
Вот пример применения этих методов:
_root.createEmptyMovieClip("box",1);
with (_root.box) {
lineStyle(0,0x000000,100);
beginFill(0x990000,100);
moveTo(0,0);
lineTo(100,0);
lineTo(100,100);
lineTo(0,100);
lineTo(0,0);
box.endFill();
}
Данный скрипт делает следующее:
Важно отметить, что при создании фигуры для заливки ее стартовая точка (указанная в moveTo() ) должна совпадать с конечной точкой (указанной в последнем lineTo() ).

Создать
путь.beginGradientFill (type, colors, alphas, ratios, matrix)
Первый параметр, type, может принимать строковое значение – либо (линейный или радиальный тип colors – массив шестнадцатеричных цветовых кодов, используемых в alphas, есть массив значений прозрачности, применяемых к соответствующим цветам. Этот массив должен содержать столько же элементов, что и массив colors. Параметр – массив, элементы которого могут иметь значения от 0 до 255. Эти значения определяют распределение оттенков.
Параметр метода beginGradientFill() требует особого внимания. Это – объект, содержащий значения, используемые при перемещении, сдвиге и вращении
Существует два способа конфигурирования объекта . Чаще всего он содержит следующие свойства:
"box ". Для Flash она обозначает тип используемой матрицы.
Вот пример создания фигуры с
_root.createEmptyMovieClip("holder", 1);
with (_root.holder) {
lineStyle(0, 0x000000, 0);
rotation = 90 * (Math.PI/180);
colors = [ 0x6666FF, 0xFF6600 ];
alphas = [ 100, 100 ];
ratios = [ 0, 255 ];
matrix = { matrixType:"box", x:0, y:150, w:200, h:100, r:rotation };
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveTo(0,0);
lineTo(550,0);
lineTo(550,300);
lineTo(0,300);
lineTo(0,0);
endFill();
}
Приведенный скрипт создает квадрат, который затем закрашивает
Чтобы лучше освоить метод градиентной заливки, вам, возможно, стоит несколько раз попробовать его в деле самостоятельно.
Изменение глубины расположения экземпляров фильмов-символов называют z-сортировкой. Почему z? Да потому, что глубину во Flash можно рассматривать, как третье измерение, Z-координату (вдобавок к X и Y ). В момент создания экземпляра клипа его глубина устанавливается при помощи duplicateMovieClip() или , а для динамического изменения глубины расположения клипов предназначен метод объекта . C помощью этого метода можно "поменять глубинами" любые два фильма-символа либо переместить экземпляр на указанную глубину.
Для взаимного обмена глубинами двух экземпляров клипов используется следующий синтаксис:
movieClip1.swapDepths(movieClip2);
Если, например, movieClip2 располагался поверх movieClip1, то в результате выполнения этого скрипта они поменяются местами, и movieClip1 окажется над movieClip2.
Синтаксис перемещения экземпляра клипа (созданного до этого при помощи duplicateMovieClip() или ) на нужную глубину следующий:
movieClip1.swapDepths(нужнаяГлубина);
Метод прост в использовании, в то же время он позволяет создавать замечательные эффекты в приложениях и играх. В этом упражнении перетаскиваемыми два окна в нашем приложении для рисования, при помощи расположим нужное окно поверх прочего содержимого, а также назначим действия некоторым кнопкам.
В таком виде мы с вами оставили файл, с которым работали в предыдущем упражнении. В этом упражнении мы добавим кое-что в скрипт экземпляра клипа controller, а также поработаем с клипами-окнами.
onClipEvent (load) {
this.gotoAndStop("color");
}

И window1, и window2 – экземпляры одного и того же клипа, только под разными именами. Этот скрипт будет направлять экземпляр window1 к кадру с меткой color сразу после загрузки фильма. В этом кадре имеется несколько кнопок, которые будут предназначены для выбора цвета линий при рисовании.
onClipEvent (load) {
this.gotoAndStop("admin");
}
Этот скрипт сразу после загрузки фильма будет направлять данный экземпляр к кадру с меткой admin. В этом кадре имеется две кнопки, позволяющие очищать область рисования и распечатывать ее содержимое.
on (release) {
_parent.controller.currentColor = "7F6696";
}
Вы, вероятно, помните, что переменная currentColor (в экземпляре клипа controller ) хранит цвет рисуемых линий. Этот скрипт как раз присваивает переменной currentColor новое значение – шестнадцатеричный код цвета.
Для второй кнопки:
on (release) {
_parent.controller.currentColor = "FAC81C";
}
Для третьей кнопки:
on (release) {
_parent.controller.currentColor = "E72638";
}
Для четвертой кнопки:
on (release) {
_parent.controller.currentColor = "1091CB";
}
Для пятой кнопки:
on (release) {
_parent.controller.currentColor = "1FA900";
}
Для шестой кнопки:
on (release) {
_parent.controller.currentColor = "BC0077";
}
Скрипты те же самые, что и для первой кнопки, разнятся только значения цвета.
Теперь давайте запрограммируем перетаскивание окна.
on (press) {
startDrag (this);
_root.controller.swap(_name);
}

Поскольку кнопка находится на монтажном столе клипа, изображающего окно, при нажатии кнопки начинается перетаскивание самого этого ( this ) окна.
Второе действие вызывает функцию (пока не написанную). Функция эта, под названием , будет находиться в клипе controller, ее роль будет заключаться в изменении z-положения окна так, чтобы оно оказалось на самом верху. Функция при вызове смотрит переданное ей значение свойства _name (представляющее имя экземпляра) текущего фильма. Наш проект содержит два экземпляра одного и того же клипа – window1 и window2, поэтому кнопка будет работать следующим образом: если кнопка нажата в экземпляре window1, начинается перетаскивание этого экземпляра, и функции передается значение "window1". Если же кнопка нажата в экземпляре window2, начинается перетаскивание этого экземпляра, и функции передается значение "window2".
on (release) {
stopDrag ();
}
При отпускании кнопки процесс перетаскивания прекращается.
topDog = "window1";
Для смены глубин размещения экземпляров window1 и window2 мы применим метод . Переменная topDog будет хранить имя того экземпляра, который расположен выше. При генерации фильма выше окажется window1, поэтому мы присваиваем переменной именно такое начальное значение.
function swap (name) {
_root[name].swapDepths(_root[topDog]);
topDog = name;
}
Назначение этой функции – поменять глубинами экземпляр клипа с именем, содержащимся в name (значение параметра, передаваемого функции) и экземпляр с именем, содержащимся в переменной topDog. После этого переменная topDog получает новое значение – это будет имя экземпляра, который теперь оказался сверху. На шаге 6 мы видели, что функции в качестве параметра передается свойство _name текущего фильма (это может быть либо window1, либо window2 ). Предполагая, что в некоторый момент переменная topDog имеет значение "window1", нажатие кнопки перетаскивания в window2 (при этом будет вызвана функция и ей передано значение "window2" ) приведет к такому выполнению функции:
function swap ("window2") {
_root.window2.swapDepths(_root.window1);
topDog = "window2";
}
Как только вы нажмете кнопку в верхней части окна, он окажется верхним по глубине и начнется процесс перетаскивания.
Ну, а при нажатии на кнопки выбора цвета происходит только одно: изменяется значение переменной currentColor в экземпляре клипа controller, в результате чего новые линии будут изображаться новым цветом.
Итак, мы с вами применили метод для перемещения на передний план нужного окна. Но проект еще не закончен! Мы должны запрограммировать очистку рабочей области рисования, а также возможность перетаскивания на нее картинок-шаблонов.
Зачастую при создании пользовательского интерфейса возникает необходимость реализовать для экземпляров клипов операцию типа "перетащить и оставить" ( ). Этим термином обозначают следующий процесс: при нажатии кнопки мыши на экземпляре начинается его перетаскивание, которое прекращается, как только кнопка мыши будет отпущена. В результате может быть выполнен некоторый набор действий (в зависимости от того, в каком месте оставлен экземпляр). Самый простой пример – "мусорная" Корзина на
Обычно во Flash операция "перетащить и оставить" реализуется при помощи _droptarget или hitTest(). Значение свойства фильма _droptarget – путь к самому "переднеплановому" экземпляру фильма-символа из тех, над которыми в данный момент находится перетаскиваемый экземпляр клипа. С помощью метода hitTest() можно определить момент, когда экземпляр касается своей границей границы другого экземпляра (подробнее об этом см. Урок 9, Использование логических условий). На практике чаще метод hitTest() используется гораздо чаще, чем свойство _droptarget, как более гибкий и многоцелевой.
В этом упражнении мы добавим в наш проект динамически формируемую строку значков (простых графических фильмов-символов), которые можно будет перетаскивать в рабочую область рисования – это мы реализуем с помощью метода hitTest(). Для перетащенного и оставленного значка будет создана копия (при помощи duplicateMovieClip() ), а оригинал будет возвращен на прежнее место.
В таком виде мы с вами оставили этот файл после выполнения предыдущего упражнения. Сейчас мы будем добавлять скрипты к экземплярам клипов controller и . Для начала мы создадим функцию, формирующую строку значков под областью рисования. Затем мы запрограммируем возможность перетаскивания этих значков, а также отслеживание случая, если они оставлены на области рисования.
function buildIconList() {
spacing = 85;
iconY = 360;
iconX = 70;
var i = -1;
while (++i < _root.icon._totalFrames) {
newName = "icon" + i;
_root.icon.duplicateMovieClip(newName, 10000 + i);
_root[newName]._x = iconX + i * spacing;
_root[newName]._y = iconY;
_root[newName].gotoAndStop(i + 1);
}
}
Ничего для вас нового в этой функции нет. На монтажном столе экземпляра клипа содержится некоторое количество кадров, в каждом из которых имеется изображение одного из значков. Данный скрипт создает по одному дубликату клипа для каждого из этих кадров. Дубликаты располагаются в одну линию в нижней части экрана; курсор воспроизведения каждого дубликата перемещается на соответствующий кадр. В результате мы получим строку из нескольких значков. Можно уменьшить или увеличить число значков (то бишь, кадров в экземпляре клипа ) – наш скрипт сам "узнает" об этом, поскольку примененный нами while базируется на значении свойства _totalFrames (общее число кадров в клипе). Переменная spacing определяет расстояние по горизонтали между дубликатами. Переменные iconX и iconY – координаты первого дубликата.

Это будет вызов только что созданной нами функции для
on (press) {
startDrag (this);
}
Итак, повторим, что у нас происходит на двух предыдущих шагах. Экземпляр клипа (содержащий кнопку, к которой мы только что присоединили скрипт) дублируется четырежды, каждый из четырех дубликатов переходит к одному из четырех кадров, имеющихся на его монтажном столе. Тем самым под областью рисования появляется четыре значка, каждый со своим рисунком. Любой из этих значков можно перетащить в область рисования, и, если он будет там оставлен, в рабочей области будет создана его копия (да-да, дубликат дубликата). Невидимая кнопка при нажатии выполняет действие startDrag(),
Важно отметить, что эта невидимая кнопка имеет имя iconButton. Для чего это нужно? Когда значок будет оставлен в области рисования и продублирован, дубликат унаследует и невидимую кнопку, и все присоединенные к ней действия. А это значит, что дубликат в области рисования тоже будет перетаскиваемым, а это нам совершенно не нужно. Мы хотим, чтобы в области рисования осталось стационарное изображение, в качестве шаблона для рисования. Поэтому мы и присвоили кнопке имя – чтобы иметь возможность отключить ее в дубликате, помещенном в область рисования. Функцию, обрабатывающую перетаскивание, мы настроим таким образом, чтобы после создания дубликата кнопка в нем отключалась и не могла более вызвать действие startDrag(). Кнопка должна работать только в тех экземплярах клипа , которые находятся под областью рисования.

on (release) {
stopDrag();
_root.controller.iconReleased(_name);
}
Первое действие в этом скрипте просто прекращает процесс перетаскивания, если кнопка отпущена – экземпляр клипа "оставлен". Второе действие вызывает функцию iconReleased() (еще не написанную) в экземпляре клипа controller. Эта функция будет создавать дубликат клипа-значка, перетащенного в область рисования, а оригинал возвращать на прежнее место (под областью рисования), откуда его можно будет вновь перетащить. Обратите внимание, что функции в качестве параметра передается свойство _name перетащенного экземпляра – ведь функция должна знать, какой из четырех значков был в данном случае перетащен в область рисования.
onClipEvent (load) {
homeX = _x;
homey = _y;
}
Используя событие load, мы создаем в экземпляре, сразу после его загрузки, две переменные – homeX и homeY, в которых хранятся начальные координаты экземпляра. Этот скрипт будут наследовать все дубликаты, и значит, на монтажном столе каждого из них будут храниться начальные координаты по X и Y. Эти значения нужны нам, чтобы возвращать на место значки после перетаскивания их в область рисования.
Теперь давайте напишем функцию, которая объединит наши разрозненные скрипты.
function iconReleased (name) {
if (_root.canvas.hitTest(_root._xmouse, _root._ymouse)) {
++v;
newName = "object" + v;
_root[name].duplicateMovieClip(newName, v);
_root[newName].gotoAndStop(_root[name]._currentFrame);
_root[newName].iconButton.enabled = false;
_root[newName]._xscale = 250;
_root[newName]._yscale = 250;
}
_root[name]._x = _root[name].homeX;
_root[name]._y = _root[name].homeY;
}
У этой функции один аргумент – name. Как мы упоминали на шаге 5, значением этого параметра будет имя экземпляра (свойство _name ) значка, перетащенного в область рисования. Значение параметра играет важнейшую роль в работе функции.
Первым делом duplicateMovieClip() создается копия перетащенного экземпляра клипа. Имя, которое получит дубликат, получается путем объединения строки "object" и значения переменной v (которая увеличивается на единицу при каждом очередном создании дубликата). Таким образом, текущее значение v всегда равно числу дубликатов значков, перетащенных в область рисования – запомните это, в следующем упражнении оно нам пригодится.
Созданный дубликат отсылается к тому же кадру, что и экземпляр-оригинал (значок, перетащенный в область рисования). Следующее действие отключает в дубликате невидимую кнопку iconButton (мы говорили об этом на шаге 4). Вдобавок дубликат масштабируется по вертикали и горизонтали до размера 250 процентов – таким образом, экземпляр клипа в области рисования получится больше, чем соответствующий значок.
Примечание Экземпляр-дубликат наследует (в момент дублирования) X и Y координаты оригинала. Поэтому, если дубликат сразу же не переместить, он расположится прямо над оригиналом (в этом случае, если бы не масштабирование, на экране даже не произошло бы никаких видимых изменений).о отправляют перетащенный экземпляр клипа на прежнее место, координаты которого хранятся в переменных homeX и homeY на его монтажном столе. Обратите внимание: эти два действия находятся вне false, и дубликат не был создан. Таким образом, если пользователь попытается оставить значок не в области рисования (над экземпляром клипа ), а где-либо в другом месте, дубликат не создается, и значок просто возвращается на свою начальную позицию в нижней части экрана.

Если вы попытаетесь оставить перетаскиваемый значок за пределами экземпляра , он вернется на прежнее место, без создания дубликата. Если же кнопка мыши будет отпущена в тот момент, когда значок находится над экземпляром клипа , будет создан дубликат, а оригинал опять же вернется на прежнее место.
Мы с вами создали простенькое приложение для рисования. Возможности
Динамически созданные линии можно легко удалить с любого монтажного стола при помощи метода clear(). Синтаксис прост:
путь.clear();
Экземпляры клипов, созданные при помощи duplicateMovieClip() или (как значки, которые мы перетаскивали в область рисования), можно удалить при помощи метода объекта .
Примечание С помощью этого метода можно удалить только те экземпляры клипов, которые созданы динамически, при помощи
Удаление экземпляров клипов может пригодиться для динамического удаления содержимого со сцены, для реинициализации приложений и освобождения
someMovieClip.removeMovieClip();
В этом упражнении мы с вами создадим функцию, которая будет удалять из области рисования все динамически нарисованные линии, а также экземпляры клипа , перетащенные в область рисования.
В таком виде мы оставили файл после выполнения предыдущего упражнения. В этом упражнении мы добавим в controller функцию, очищающую область рисования. Запускаться функция будет скриптом, который мы присоединим к кнопке Clear, находящейся в экземпляре клипа window2.
function clearContent () {
_root.holder.clear();
i = 0;
while (++i <= v) {
name = "object" + i;
_root[name].removeMovieClip();
}
v = 0;
}
Первое действие в этой функции удаляет все динамически нарисованные линии из экземпляра клипа . Далее следует несложный цикл while, удаляющий все перетащенные на сцену экземпляры клипа . Значение переменной v равно общему числу перетащенных экземпляров , ведь v увеличивается на единицу всякий раз, когда в области рисования создается дубликат – мы с вами запрограммировали это в функции buildIconList(), в предыдущем упражнении. Теперь мы используем значение v для определения количества итераций цикла, удаляющего дубликаты. После того, как цикл завершен (все экземпляры из области рисования удалены), переменной v присваивается значение 0, так что когда в область рисования будет перетащен новый экземпляр , нумерация дубликатов вновь начнется с нуля.

В этом кадре имеется две кнопки – Clear и Print. Нам нужно присоединить к кнопке Clear скрипт, вызывающий функцию clearContent() из экземпляра клипа controller. Заодно уж давайте добавим скрипт к кнопке Print.
on (release) {
printAsBitmap ("_root", "bmovie");
}
Если эту кнопку нажать и отпустить, графическое содержимое главного монтажного стола (то есть, все, что в момент нажатия кнопки находится на сцене, включая динамически созданные экземпляры) будет распечатано как растровое изображение в натуральную величину.
Примечание Этим скриптом мы хотим продемонстрировать, что динамически созданные экземпляры можно распечатать столь же легко, как и другое содержимое фильма. Если бы создавали более изощренное приложение, мы могли бы предпочесть распечатывание только содержимого области рисования. Однако тогда пришлось бы иначе строить наши функции, а мы не захотели усложнять упражнения, поскольку изучение возможностей печати не является целью данного урока.
on (release) {
_parent.controller.clearContent();
}
Если эту кнопку нажать и отпустить, будет выполнена функция clearContent(), присоединенная к экземпляру controller.
При нажатии кнопки Clear будет выполнена функция очистки, цикл while в ней удалит все созданные в области рисования экземпляры клипов.
На этом закончено упражнение и весь урок. Как видите, процесс динамического удаления материалов куда проще процесса создания. Ну, теперь вы умеете делать и то, и другое, а это обеспечит вашим проектам колоссальные возможности взаимодействия с пользователем. Ну, разве не великолепен этот
В этом уроке:

Приложение для рисования – один из проектов, которые мы создадим в этом уроке в ходе изучения различных способов динамического управления клипами.
На выполнение этого урока требуется примерно один час.
Файлы-носители:
Нет
Стартовые файлы:
Lesson14/Assets/scrollingList1.fla Lesson14/Assets/draw1.fla
Законченные проекты:
scrollingList3.fla draw5.fla
Для динамического создания экземпляра фильма-символа предназначены три метода объекта
Каждый из этих методов мы с вами применим в ходе выполнения упражнений этого урока.
Мы уже познакомили вас с этим методом в Уроке 10 – Автоматизация скриптов с помощью циклов, однако сделали это бегло, не вдаваясь в детали. Теперь, наконец, вы узнаете все об этом мощном методе!
Метод duplicateMovieClip() служит для Flash указанием создать дубликат имеющегося на сцене экземпляра фильма-символа, дав ему новое имя. Если указанный экземпляр клипа на сцене не присутствует (находится в одном из предыдущих или последующих кадров), то Flash не сможет дублировать его. Другое ограничение состоит в том, что дубликат может быть создан только на том же самом монтажном столе, где находится оригинал. Для динамического создания экземпляра клипа на любом монтажном столе следует применять метод – мы еще поговорим о нем в этом уроке.
Создаваемый дубликат наследует все физические свойства, которые имел оригинал на момент дублирования.
Дубликат фильма-символа наследует следующие свойства оригинала:
Дубликат фильма-символа не наследует:

Примечание Воспроизведение экземпляра-дубликата начинается с кадра 1, даже если оригинальный клип в момент дублирования находился на другом кадре.
Синтаксис дублирования экземпляра фильма-символа таков:
myClip.duplicateMovieClip(имя, глубина, объект);
Эта строка duplicateMovieClip() объекта . В результате создается новый экземпляр, именем которого будет значение параметра имя, на глубине глубина. Параметр объект – не обязательный. Пример:
name = "ball2"; depth = 100; ball.duplicateMovieClip(name, depth);
Эти три строки создают дубликат экземпляра клипа экземпляр-дубликат получает имя ball2 и располагается на глубине 100.
Примечание Говоря здесь о глубине ( depth ), мы подразумеваем
Каждый монтажный стол в фильме имеет диапазон глубин от -16384 до 1048575, причем все отсчеты глубин ведутся относительно главного монтажного стола фильма. Иными словами, некий "экземпляр 1" может содержать дочерние экземпляры, расположенные на его монтажном столе на глубинах от -16384 до 1048575. Но если на основном монтажном столе "экземпляр 1" находится под "экземпляром 2", то всякий, даже самый верхний дочерний экземпляр "экземпляра 1" окажется ниже самого нижнего из дочерних экземпляров "экземпляра 2".

На каждой глубине в каждый момент времени может располагаться только один экземпляр фильма-символа. Попытавшись дублировать экземпляр клипа на глубину, где уже имеется другой экземпляр, вы тем самым уничтожите этот второй экземпляр.
Итак, каждый монтажный стол имеет 1064960 уровней глубины (от -16384 до 1048575). При этом глубины разных монтажных столов никоим образом не пересекаются между собой.
Третий параметр метода duplicateMovieClip(), параметр объект, необязателен, но отнюдь не бесполезен. Свойства объекта, указанного в качестве этого параметра, станут элементами данных нового дубликата клипа. Если параметр опущен, он игнорируется. Расширим немного предыдущий пример:
myObject = new Object(); myObject.ballColor = "red"; name = "ball2"; depth = 100; ball.duplicateMovieClip(name, depth, myObject);
Новый экземпляр-дубликат ball2 будет содержать все свойства объекта myObject. В данном случае в новом экземпляре будет создана переменная ballColor со значением "red".
Совет Если нужно скопировать переменные из оригинального экземпляра в дубликат, следует использовать в качестве третьего параметра имя оригинального экземпляра. Например:
ball.duplicateMovieClip(name, depth, ball);
C помощью метода можно взять фильм-символ из библиотеки и динамически "присоединить" ( ) экземпляр его к любому монтажному столу из имеющихся в данный момент в сцене фильма – при этом, естественно, все содержимое этого экземпляра добавится к содержимому фильма, к которому он присоединяется. Присоединенный клип становится дочерним по отношению к монтажному столу, к которому он присоединен. Он наследует все графические трансформации, выполняемые над родителем (изменения размеров, прозрачности, повороты и т.п.), при этом сохраняя самостоятельность в отношении данных, видимости, текущего кадра и т.п. (подробнее об отношениях родитель/

В чем же состоят отличия этого метода от метода duplicateMovieClip()? Как уже было сказано, присоединяет экземпляр клипа из библиотеки к любому из монтажных столов в фильме. Поскольку присоединяемый клип берется из библиотеки (а библиотека содержит все клипы фильма), клип, к которому присоединяется экземпляр, не обязан находиться на сцене в момент присоединения. С методом duplicateMovieClip() все наоборот: экземпляр клипа, который подлежит дублированию, должен находиться на сцене. Более того, дубликат создается только на том же монтажном столе, что и оригинал. Еще одно различие состоит в следующем. Если дублируемый экземпляр имеет присоединенные к нему обработчики событий ( data, enterFrame, mouseDown и т.п.), то дубликат автоматически наследует их. С присоединяемым клипом такого не происходит. Конечно, имеются способы добавить обработчики событий и к присоединяемому клипу, но этот процесс не столь прост, как при дублировании.
Проще говоря, присоединение позволяет, в сущности, добавить любой монтажный стол на любой другой монтажный стол. Дублирование позволяет только создавать точные копии экземпляра клипа в пределах того монтажного стола, где находится оригинал.

Применение метода требует выполнения некоторых условий. Первое условие состоит в том, что находящиеся в библиотеке клипы, предназначенные для присоединения, следует должным образом подготовить. Такая подготовка называется связыванием. Возможно,
Пошаговый процесс
Linkage ).Export for ActionScript ).Identifier ) (этот идентификатор будет служить в Совет Установить связь можно также при создании фильма-символа, нажав в диалоговом окне Преобразовать в символ ( ) кнопку Расширенный ( Advanced ).

Примечание При связывании обратите внимание еще на одну опцию – "Экспорт в первый кадр" ( ), которая включается по умолчанию. Эта опция определяет, в какой момент будет загружаться связанный (или присоединяемый) фильм-символ при просмотре фильма. Если флажок установлен, то клип будет загружен до кадра 1 основного фильма, и, таким образом, его содержимое будет доступно прежде, чем будет предпринята любая попытка присоединить его (например, уже в кадре 1). При использовании крупных клипов (таких, которые содержат много других фильмов-символов или звукозаписей) Flash может в начале фильма "затормозить". Не стоит беспокоиться: просто происходит загрузка содержимого всех связанных фильмов-символов. Если флажок "Экспорт в первый кадр" не установлен, то фильм-символ не будет загружаться перед первым кадрам. В этом случае вы должны поместить экземпляр такого клипа на сцену до того, как попытаетесь присоединить его. После того, как фильм-символ будет обработан (появится
в фильме) в каком-либо кадре, его можно будет присоединять когда и где угодно. Например, если в кадре 25 имеется действие, присоединяющее клип, то экземпляр этого клипа должен появиться в фильме в кадре 24 или раньше – иначе метод не сработает. После кадра 24 присоединять экземпляры этого клипа можно сколько угодно, поскольку он уже загружен в память.
Вот синтаксис присоединения к монтажному столу фильма-символа из библиотеки:
путь.attachMovie(идентификатор, новоеИмя, глубина, объект);
Например:
_root.wall.attachMovie("paint", "paint2", 10);
Этот скрипт присоединит фильм-символ из библиотеки, имеющий идентификатор ", к экземпляру фильма-символа _root.wall. Новый присоединенный экземпляр получит имя paint2 и будет помещен на глубину 10. Присоединенный клип станет дочерним для того экземпляра, к которому он присоединен, так что путь к нему будет выглядеть как _root.wall.paint2. Обратите внимание на пример синтаксиса (первая строка): здесь тоже имеется опция, позволяющая наполнить создаваемый клип свойствами и переменными объекта. Как и для duplicateMovieClip(), эта опция необязательна и в нашем примере (вторая строка) опущена.
Совет Простейший способ динамически назначить события клипа присоединенному (или
_root.attachMovie("box", "dynamicBox", 1);
dynamicBox.onEnterFrame = function(){
dynamicBox._rotation += 15;
}
В этом примере экземпляр фильма-символа (это его имя в библиотеке) динамически присоединяется к основному монтажному столу. Присоединенный экземпляр получает имя dynamicBox. Строки, следующие за действием присоединения, назначают обработчик события клипа для нового экземпляра.
Метод createEmptyMovieClip() позволяет динамически создать (на любом монтажном столе) новый экземпляр пустого фильма-символа. Для чего это может понадобиться? Вот несколько примеров.
Синтаксис создания экземпляра пустого фильма-символа следующий:
путь.createEmptyMovieClip(имя, глубина);
Например:
_root.createEmptyMovieClip("box", 1);
Здесь первый параметр – имя, которое будет присвоено новому экземпляру пустого клипа; второй параметр – глубина, на которую будет помещен этот экземпляр. Если вы попытаетесь протестировать это действие, то не обнаружите никакого видимого результата – ведь созданный экземпляр совершенно пуст. В этом уроке мы с вами используем метод createEmptyMovieClip() для динамического рисования линий.
Метод создает новый экземпляр фильма-символа из библиотеки. В этом упражнении мы с вами создадим проект, при запуске которого на сцене будет отображаться прокручиваемый список. Элементы этого списка будут создаваться посредством динамического присоединения экземпляров клипа.
На основном монтажном столе мы видим три слоя: Actions, Window и Background. Слой Background содержит общее графическое оформление проекта; в слой Actions мы поместим большинство скриптов; а в слое Window находится экземпляр фильма-символа под названием display.
Внутри монтажного стола display вы найдете четыре слоя: list, к которому мы будем присоединять экземпляры, создавая их при помощи . Эти присоединенные экземпляры станут элементами списка, располагаясь один под другим. Список (экземпляр клипа list ), будучи наполнен присоединенными к нему экземплярами, станет довольно-таки длинным. Поэтому мы маскируем list прямоугольником, находящимся в слое list, находящаяся "внутри" окна.

Теперь этот клип готов к использованию методом .
Для каждой строки в прокручиваемом списке к экземпляру list будет присоединяться один экземпляр клипа infoBar (16 строк, 16 присоединений). Внутри каждого из присоединенных клипов будет два moonName и moonNum; в этих полях будут отображаться названия лун Юпитера и соответствующие номера.

list = ["Adrastea", "Amalthea", "Ananke", "Callisto", "Carme", "Elara", "Europa", "Ganymede", "Himalia", "Io", "Leda", "Lysithea", "Metis", "Pasiphae", "Sinope", "Thebe"];
Цель этого упражнения – создать список, элементами которого будут присоединенные экземпляры фильма-символа. Для этого мы прежде всего создаем массив из названий 16 наиболее известных лун Юпитера. Для каждой луны из этого массива к экземпляру list мы должны присоединить экземпляр клипа из библиотеки.
Теперь нужно описать функцию, которая и будет создавать список из экземпляров клипа.
function buildList() {
spacing = 30;
}
В конечном итоге функция buildList() будет содержать все действия, необходимые для присоединения, spacing и присваиваем ей значение 30 – эта переменная будет определять дистанцию по вертикали (y) между центрами присоединенных экземпляров клипа.
var i = -1;
while (++i < list.length) {
name = "infoBar" + i;
y = i * spacing;
display.list.attachMovie("infoBar", name, i);
display.list[name]._y = y;
display.list[name].moonName.text = list[i];
display.list[name].moonNum.text = i + 1;
}
В этой части функции используется цикл while, перебирающий поочередно все элементы массива list. Для каждого элемента массива цикл присоединяет к экземпляру list экземпляр клипа infoBar.
Первым действием в name, значение которой задается выражением, которое присоединяет к строке "infoBar" текущее значение i. Поскольку значение i при каждом проходе цикла увеличивается на единицу, name будет принимать значения "infoBar0", "infoBar1", "infoBar2" и так далее. Далее в name будет использовано для присвоения имени каждому успешно присоединенному экземпляру клипа infoBar. А пока в цикле создается переменная y, которая будет хранить y-координату присоединяемого в данный момент экземпляра. Значение этой переменной вычисляется умножением текущего значения i на значение spacing. Поскольку значение i при каждой итерации увеличивается, то же будет происходить и со значением y. В результате присоединенные экземпляры будут располагаться друг под другом.
Последние четыре действия в infoBar, имя и глубина которого содержатся в переменных name и i, соответственно. Далее этот присоединенный экземпляр получает y-координату, равную значению переменной y. Каждый из присоединяемых экземпляров содержит те же элементы, что и оригинал, а значит, в каждом имеется два текстовых поля: moonName и moonNum. Последние два действия в moonName присоединенного экземпляра помещается строковое значение (название луны) – i-й элемент массива list. В текстовое поле moonNum каждого экземпляра помещается числовое значение i плюс 1. Таким образом, в этом текстовом поле для соответствующих
экземпляров будут выводиться значения 1, 2, 3 и так далее.
По завершении цикла каждому элементу массива list будет соответствовать присоединенный экземпляр фильма-символа, заполненный информацией и расположенный по вертикали среди других экземпляров.


Эта строка будет вызывать только что описанную нами функцию – в результате будут выполнены все действия, запрограммированные нами на предыдущих шагах.
После инициализации фильма появится наш с вами список. Не забудьте: с помощью маски мы ограничили число одновременно видимых элементов, поэтому вы можете наблюдать только часть списка.
Мы завершили наиболее трудную часть этого урока: написали скрипт, динамически присоединяющий экземпляры фильма-символа из библиотеки для построения списка. В следующем упражнении мы продолжим работу с этим файлом и сделаем окно списка прокручиваемым.
Порой возникает необходимость в том, чтобы некие действия выполнялись непрерывно, пока нажата кнопка. Кнопки, запрограммированные таким образом, называют кнопками с непрерывной
Примечание В большинстве случаев реализовать прокрутку гораздо проще с помощью компонента Scrollbar (полоса прокрутки). Это упражнение имеет целью разъяснить вам, как вообще программируется и работает прокрутка – тогда вы сможете, при желании, внедрить собственные идеи вместо
Если информации в окне при каждом нажатии на соответствующую кнопку будет прокручиваться на одну строку, пользователь быстро устанет. Гораздо удобнее, если прокрутка при нажатой кнопке происходит непрерывно, и прекращается, когда кнопка отпущена. Во Flash это можно реализовать (вскоре мы это продемонстрируем) с помощью событий клипа enterFrame или mouseMove.
В этом упражнении мы с вами добавим кнопки прокрутки к списку, построенному нами в предыдущем упражнении.
Этот файл должен быть вам хорошо знаком – в таком виде мы оставили его по завершении предыдущего упражнения. В этом упражнении мы добавим действия
Напомним, что здесь имеется экземпляр клипа list, расположенный внутри клипа display. Все вновь создаваемые экземпляры (клипа infoBar ) помещаются в экземпляр list. Таким образом, нашей функции достаточно будет перемещать по вертикали экземпляр клипа list, чтобы создать эффект прокрутки списка.
Примечание В этом упражнении, используя термин "прокрутка", мы будем подразумевать перемещение по экрану вверх и вниз фильма-символа list путем изменения значения его свойства _y.
startingY = display.list._y;
Для правильной работы прокрутки мы должны установить максимальное и минимальное положения ( Y ), списка – задать границы прокрутки списка (вертикального перемещения). В любом приложении, где используется прокрутка, необходимо предотвращать возможность прокрутку за пределы документа. Добавленная нами строка скрипта будет использоваться для установления одной из этих вертикальных границ: прокрутка экземпляра клипа list (содержащий присоединенные экземпляры) должна прекращаться, если его Y-координата достигла стартовой Y-координаты ( startingY ). C этой целью мы и используем сейчас значение переменной startingY.

Как было сказано на предыдущем шаге, наибольшая возможная Y-координата прокрутки экземпляра клипа list – это его стартовая позиция. Переменная bottom, которую мы определяем на этом шаге, будет содержать значение координаты такое, чтобы самый нижний элемент списка не мог выйти за пределы окна. Каким образом это будет достигаться, вы поймете из следующих шагов.
function scroll (direction) {
speed = 10;
}
Впоследствии мы организуем вызов этой функции в нашем проекте посредством события enterFrame, присоединенного к экземплярам клипов, содержащих кнопки прокрутки. Одна из кнопок будет предназначена для прокрутки вверх, другая – вниз. Параметр , передаваемый этой функции, будет содержать строковое значение: "up" или "down". list вверх или вниз. Переменная – скорость прокрутки. Пока одна из кнопок удерживается в нажатом положении, экземпляр list будет перемещаться (либо вверх, либо вниз). Скорость его перемещения и определяется значением переменной . Кстати, число 10 взято вовсе не из каких-то "высших соображений"; если хотите, можете взять другое значение.
if (direction == "up") {
} else if (direction == "down") {
}
Как мы уже сказали, передается функции в качестве параметра и может принимать строковые значения "up" либо "down". Данный
if (display.list._y – speed + display.list._height > (startingY + bottom)) {
display.list._y -= speed;
} else {
display.list._y = (startingY + bottom) – display.list._height;
}
Поскольку этот
В условии оператора проверяется, где окажется нижняя грань экземпляра list при перемещении его на 10 пикселей вверх. Вычисляется это так: берется текущая Y-координата экземпляра list, из нее вычитается значение , затем прибавляется общая высота экземпляра. Полученная координата нижней грани экземпляра сравнивается с одним из ограничителей прокрутки (который получается путем сложения значений bottom и startingY ). Если в результате перемещения экземпляра list он не достиг ограничителя, то все в порядке – выполняется действие из первой секции оператора, движение экземпляра продолжается. Если же экземпляр дошел до ограничителя, выполняется секция else, и экземпляр попросту устанавливается в максимальную разрешенную координату по вертикали.

Если все это вам не совсем понятно, не расстраивайтесь: сейчас мы рассмотрим на примере, как все это работает. Для этого предположим, что элементы нашего скрипта имеют следующие значения:
speed = 10 startingX = 100 bottom = 120 display.list._height = 400 //высота (размер по вертикали) экземпляра list display.list._y = -165 //текущая координата экземпляра list по вертикали
С этими значениями if будет выглядеть следующим образом:
if (-165 – 10 + 400 > (100 + 120))
В итоге получим:
if (225 > 220)
Поскольку 225 больше 220, выполняется следующее действие:
display.list._y -= speed;
Тем самым экземпляр list переместится на 10 пикселей вверх, и его Y-координата станет равна -175. Теперь, при следующем выполнении
if (-175 – 10 + 400 > (100 + 120))
И, в итоге:
if (215 > 220)
Утверждение ложно, ведь 215 меньше 220, поэтому выполняется действие из секции else:
display.list._y = (startingY + bottom) – display.list._height;
Экземпляр list помещается в Y-координату, значение которой вычисляется в правой части этого выражения:
(startingY + bottom) – display.list._height
Подставляя наши значения, получим:
(100 + 120) – 400
Это даст
220 - 400
И в итоге
-180
Тем самым экземпляр list будет привязан к вертикальной координате -180 – нижняя грань экземпляра будет совмещена к верхнему ограничителю прокрутки – дальнейшая прокрутка экземпляра list невозможна.
Теперь давайте настроим обработку прокрутки вниз.
if (display.list._y + speed < startingY) {
display.list._y += speed;
} else {
display.list._y = startingY;
}

Эта часть list при перемещении вниз на значение не вышел за нижний ограничитель прокрутки ( startingY ). Если этого не произошло, выполняется действие из первой секции оператора, перемещающее экземпляр клипа вниз. В противном случае ( else ) нижняя грань экземпляра совмещается с нижним ограничителем прокрутки.
Описание функции мы закончили, теперь пора поработать с кнопками прокрутки.
На экране появится кнопка list , частью которого она является) мы будем использовать для прокрутки в обоих направлениях – и вверх, и вниз.
on (press) {
buttonPressed = "yes";
}
on (release, releaseOutside, dragOut) {
buttonPressed = "";
}
Эта кнопка будет попросту присваивать значение переменной buttonPressed – "yes" или "", в зависимости от действий пользователя. Если пользователь нажал эту кнопку, buttonPressed получает значение "yes". Если пользователь отпускает кнопку мыши (неважно, где при этом находится указатель – на кнопке или за ее пределами), переменная buttonPressed получает значение "". На следующем шаге мы используем значение этой переменной.
Монтажный стол этого клипа содержит два экземпляра фильма-символа list , который содержит кнопку down, а нижний экземпляр – up.
Как вы помните, при нажатии кнопки, имеющейся в каждом из этих двух экземпляров, переменная buttonPressed получает значение "yes". Важно понимать, что каждый из экземпляров представляет собой самостоятельный монтажный стол. Нажатие кнопки, находящейся в одном из экземпляров, изменит значение переменной buttonPressed только на этом монтажном столе; на переменную другого экземпляра это событие никак не повлияет.
onClipEvent (enterFrame) {
if (buttonPressed == "yes") {
_root.scroll("down");
}
}
Мы используем событие enterFrame: buttonPressed на монтажном столе этого клипа, и если это значение равно "yes", будет вызывать функцию с главного монтажного стола. Это – основа принципа действия нашей кнопки с непрерывной buttonPressed имеет значение "yes" (то бишь, пока кнопка внутри данного экземпляра нажата), происходит прокрутка. Параметр "down", передаваемый функции , дает ей знать, в каком направлении должна происходить прокрутка.
onClipEvent (enterFrame) {
if (buttonPressed == "yes") {
_root.scroll("up");
}
}
Скрипт идентичен тому, что был на предыдущем шаге, только функции передается другое значение параметра – "up".
Давайте пустим в дело кнопки, чтобы проверить наши скрипты. Нажмите и удерживайте кнопку "вниз", чтобы начать прокрутку, потом попробуйте другую кнопку. Как видите, когда экземпляр list достигает верхнего или нижнего предела, прокрутка останавливается.
Итак, мы с вами в этом упражнении организовали с помощью
Посредством , предназначенными для рисования.
Методы рисования позволяют:
В этом разделе вы научитесь рисовать линии, перемещать "курсор рисования", задавать стиль линий и очищать от рисунков экземпляр фильма-символа. В следующем разделе мы коснемся обычных и градиентных заливок. Метод curveTo() (позволяющий динамически рисовать кривые) мы здесь описывать не станем, однако к концу этого урока вы в достаточной степени овладеете основами динамического рисования во Flash, так что сможете без проблем использовать в своих приложениях и этот метод.
Прежде, чем рисовать на монтажном столе какие-либо линии, необходимо установить стиль линий для этого монтажного стола. Это значит, что нужно указать Flash:
Синтаксис таков:
путь.lineStyle(толщина, цвет, прозрачность)
В качестве значения толщины линии следует указать целое число от 0 до 255 (значению 0 соответствует самая тонкая линия). Цвет линии указывается в виде шестнадцатеричного кода. Прозрачность – число от 0 (полностью прозрачная) до 100 (полностью непрозрачная). Рассмотрим пример:
_root.myClip.lineStyle(10, 0x009900, 100);
Эта строка скрипта устанавливает стиль линий для myClip: все линии, изображаемые в этом клипе, будут зелеными, непрозрачными, толщиной 10.
Каждому экземпляру фильма-символа присуще такое свойство, как lineTo() (смотри следующий подраздел). Другими словами, это стартовая точка очередной линии. При создании экземпляра курсор рисования устанавливается в позицию с координатами x=0, y=0. Однако курсор рисования можно в любой момент переместить с помощью метода moveTo().
Синтаксис применения moveTo() следующий:
путь.moveTo(x, y);
Все, что нужно – это указать координаты x и y для нового положения курсора рисования. Например:
_root.myClip.lineStyle(10,0x009900,100); _root.myClip.moveTo(100,100);
Этот скрипт устанавливает стиль линии, а затем перемещает курсор рисования.
Метод lineTo() объекта рисует на указанном lineStyle данного монтажного стола) от текущей позиции курсора рисования до точки, указанной при вызове метода.
Синтаксис lineTo() прост:
myClip.lineTo(x,y);
Параметры x и y, как вы догадываетесь, определяют конечную точку рисуемой линии.
Совет После того, как линия нарисована, текущая
Вот пример рисования линии с использованием всех описанных нами методов:
_root.createEmptyMovieClip("canvas",1);
_root.canvas.lineStyle(2,0x009900,100);
_root.canvas.moveTo(100,100);
_root.canvas.lineTo(200,150);
Этот скрипт нарисует линию между точками (100, 100) и (200, 150).
В этом упражнении мы с вами, используя методы рисования объекта , мы начнем создавать несложное приложение, позволяющее пользователю рисовать.
Основной монтажный стол состоит из пяти слоев, названных в соответствии с их содержимым. Слой Background содержит общее графическое оформление проекта. В слое – это будет рабочая область для рисования. Слой , в следующем упражнении мы создадим дубликаты этого экземпляра, предоставив пользователю несколько значков, которые он сможет перетащить на сцену, чтобы рисовать поверх шаблона. В слое Controller находится особый экземпляр клипа – он называется controller и представляет собой так называемый клип-контроллер (в принципе, это просто экземпляр, который будет содержать большую часть скриптов, обеспечивающих работу нашего проекта). И, наконец, в слое Windows находятся два экземпляра – window1 и window2; они расположены в правой части сцены и пригодятся нам в одном из
следующих упражнений.

Основной целью данного упражнения будет создание скрипта, который даст возможность рисовать в предназначенной для этого рабочей области. Мы используем события клипа в сочетании с методом hitTest(), чтобы отслеживать нажатия кнопки мыши в пределах экземпляра . После этого для рисования мы используем событие клипа mouseMove. Каждый раз при наступлении события mouseMove положение мыши будет записываться и будет рисоваться линия от предыдущей координаты мыши к текущей координате.
onClipEvent (mouseUp) {
down = false;
}
Как мы уже сказали, большую часть действий для обеспечения работоспособности проекта мы будем помещать в экземпляр controller. Данный скрипт создает переменную с именем down, которая будет хранить текущее состояние мыши. С помощью события mouseUp эта переменная будет при отпускании кнопки мыши получать значение false, показывая другим скриптам, что кнопка мыши не нажата.
onClipEvent (mouseDown) {
if (_root.canvas.hitTest(_root._xMouse,_root._yMouse)) {
x = _root._xMouse;
y = _root._yMouse;
_root.holder.moveTo(x,y);
down = true;
}
}
При нажатии кнопки мыши ( mouseDown ) . Если это так, то выполняется несколько действий. Во-первых, координаты мыши по x и y записываются в качестве значений переменных x и y соответственно. Затем эти значения используются в методе moveTo() для перемещения курсора рисования клипа в текущие координаты мыши. Клип – это пустой экземпляр, который будет создаваться динамически (мы запрограммируем это на следующем шаге). Этот-то экземпляр и будет содержать все нарисованные линии. Последнее действие этого скрипта присваивает переменной down значение true, означающее, что кнопка мыши нажата.
onClipEvent (load) {
currentColor = "7F6696";
_root.createEmptyMovieClip("holder",100);
}
В нашем приложении цвет всех рисуемых линий будет зависеть от текущего значения переменной currentColor. В этом скрипте этой переменной присваивается начальное значение – то, которое она получит при запуске приложения. В следующем упражнении мы запрограммируем динамическое изменение этого значения – оно будет изменяться при помощи кнопок в одном из клипов-окон (в правой части), что даст пользователю возможность менять цвет линий.
Следующая строка этого скрипта создает пустой экземпляр фильма-символа под именем . Как было сказано, именно этот клип будет содержать все рисуемые линии. Он располагается на глубине 100, так что нарисованные линии будут располагаться поверх всех шаблонов, которые пользователь перетащит на сцену.
function draw() {
_root.holder.lineStyle(0, parseInt(currentColor,16) ,100);
x = _root._xmouse;
y = _root._ymouse;
_root.holder.lineTo(x, y);
}
Понятно, что эта функция будет вызываться обработчиком события mouseMove, который мы еще не описали. Функция при вызове первым делом устанавливает стиль линий. Как видите, линии будут самыми тонкими (толщина 0), на 100% непрозрачными, цвет же линий зависит от текущего значения переменной currentColor. Три последние строки функции обеспечивают рисование линии. Линия проводится методом lineTo() от текущего положения курсора рисования (установленного посредством moveTo() в нашем обработчике события mouseDown ) до текущего положения курсора мыши (значения x и y в этом скрипте).
onClipEvent (mouseMove) {
updateAfterEvent();
if (down _root.canvas.hitTest(_root._xMouse, _root._yMouse)) {
draw();
}
}
Событие mouseMove наступает всякий раз при перемещении мыши. Функция updateAfterEvent() – if проверяет, чему равна переменная down и находится ли мышь над областью рисования ( ). Если и то, и другое – true, вызывается функция draw(). Таким образом, повторяющийся вызов этой функции создает эмуляцию рисования, пока мышь находится над и ее кнопка нажата. Оператор if предотвращает вызов функции draw(), когда кнопка мыши отпущена или мышь выведена за пределы экземпляра .

Когда вы, наведя мышь на область рисования, нажмете кнопку, переменной down будет присвоено значение true – и это значит, что при всяком перемещении мыши будет рисоваться линия. Если мышь покидает пределы клипа , рисование прекращается.
Теперь мы готовы активировать окна справа от области рисования, а также добавить возможность перетаскивания значков-шаблонов в рабочую область.
Хотя для этого раздела упражнение не предусмотрено, рисование закрашенных фигур обсудить необходимо.
С помощью синтаксических конструкций с использованием методов рисования, которые мы с вами уже применяли в этом уроке, можно нарисовать замкнутый контур, а затем заполнить получившуюся фигуру сплошным цветом или
Чтобы создать заливку, прежде всего следует дать Flash знать, где будет находиться фигура, которую следует закрасить. Делается это при помощи следующего метода:
путь.beginFill(color, alpha)
Путь указывает на монтажный стол, на котором будут располагаться линии. Параметр color – шестнадцатеричный код цвета. Второй параметр – alpha – означает степень прозрачности заливки: число от 0 до 100. Чтобы сообщить Flash о том, что рисование фигуры завершено, следует применить следующий метод:
путь.endFill()
Вот пример применения этих методов:
_root.createEmptyMovieClip("box",1);
with (_root.box) {
lineStyle(0,0x000000,100);
beginFill(0x990000,100);
moveTo(0,0);
lineTo(100,0);
lineTo(100,100);
lineTo(0,100);
lineTo(0,0);
box.endFill();
}
Данный скрипт делает следующее:
Важно отметить, что при создании фигуры для заливки ее стартовая точка (указанная в moveTo() ) должна совпадать с конечной точкой (указанной в последнем lineTo() ).

Создать
путь.beginGradientFill (type, colors, alphas, ratios, matrix)
Первый параметр, type, может принимать строковое значение – либо (линейный или радиальный тип colors – массив шестнадцатеричных цветовых кодов, используемых в alphas, есть массив значений прозрачности, применяемых к соответствующим цветам. Этот массив должен содержать столько же элементов, что и массив colors. Параметр – массив, элементы которого могут иметь значения от 0 до 255. Эти значения определяют распределение оттенков.
Параметр метода beginGradientFill() требует особого внимания. Это – объект, содержащий значения, используемые при перемещении, сдвиге и вращении
Существует два способа конфигурирования объекта . Чаще всего он содержит следующие свойства:
"box ". Для Flash она обозначает тип используемой матрицы.
Вот пример создания фигуры с
_root.createEmptyMovieClip("holder", 1);
with (_root.holder) {
lineStyle(0, 0x000000, 0);
rotation = 90 * (Math.PI/180);
colors = [ 0x6666FF, 0xFF6600 ];
alphas = [ 100, 100 ];
ratios = [ 0, 255 ];
matrix = { matrixType:"box", x:0, y:150, w:200, h:100, r:rotation };
beginGradientFill( "linear", colors, alphas, ratios, matrix );
moveTo(0,0);
lineTo(550,0);
lineTo(550,300);
lineTo(0,300);
lineTo(0,0);
endFill();
}
Приведенный скрипт создает квадрат, который затем закрашивает
Чтобы лучше освоить метод градиентной заливки, вам, возможно, стоит несколько раз попробовать его в деле самостоятельно.
Изменение глубины расположения экземпляров фильмов-символов называют z-сортировкой. Почему z? Да потому, что глубину во Flash можно рассматривать, как третье измерение, Z-координату (вдобавок к X и Y ). В момент создания экземпляра клипа его глубина устанавливается при помощи duplicateMovieClip() или , а для динамического изменения глубины расположения клипов предназначен метод объекта . C помощью этого метода можно "поменять глубинами" любые два фильма-символа либо переместить экземпляр на указанную глубину.
Для взаимного обмена глубинами двух экземпляров клипов используется следующий синтаксис:
movieClip1.swapDepths(movieClip2);
Если, например, movieClip2 располагался поверх movieClip1, то в результате выполнения этого скрипта они поменяются местами, и movieClip1 окажется над movieClip2.
Синтаксис перемещения экземпляра клипа (созданного до этого при помощи duplicateMovieClip() или ) на нужную глубину следующий:
movieClip1.swapDepths(нужнаяГлубина);
Метод прост в использовании, в то же время он позволяет создавать замечательные эффекты в приложениях и играх. В этом упражнении перетаскиваемыми два окна в нашем приложении для рисования, при помощи расположим нужное окно поверх прочего содержимого, а также назначим действия некоторым кнопкам.
В таком виде мы с вами оставили файл, с которым работали в предыдущем упражнении. В этом упражнении мы добавим кое-что в скрипт экземпляра клипа controller, а также поработаем с клипами-окнами.
onClipEvent (load) {
this.gotoAndStop("color");
}

И window1, и window2 – экземпляры одного и того же клипа, только под разными именами. Этот скрипт будет направлять экземпляр window1 к кадру с меткой color сразу после загрузки фильма. В этом кадре имеется несколько кнопок, которые будут предназначены для выбора цвета линий при рисовании.
onClipEvent (load) {
this.gotoAndStop("admin");
}
Этот скрипт сразу после загрузки фильма будет направлять данный экземпляр к кадру с меткой admin. В этом кадре имеется две кнопки, позволяющие очищать область рисования и распечатывать ее содержимое.
on (release) {
_parent.controller.currentColor = "7F6696";
}
Вы, вероятно, помните, что переменная currentColor (в экземпляре клипа controller ) хранит цвет рисуемых линий. Этот скрипт как раз присваивает переменной currentColor новое значение – шестнадцатеричный код цвета.
Для второй кнопки:
on (release) {
_parent.controller.currentColor = "FAC81C";
}
Для третьей кнопки:
on (release) {
_parent.controller.currentColor = "E72638";
}
Для четвертой кнопки:
on (release) {
_parent.controller.currentColor = "1091CB";
}
Для пятой кнопки:
on (release) {
_parent.controller.currentColor = "1FA900";
}
Для шестой кнопки:
on (release) {
_parent.controller.currentColor = "BC0077";
}
Скрипты те же самые, что и для первой кнопки, разнятся только значения цвета.
Теперь давайте запрограммируем перетаскивание окна.
on (press) {
startDrag (this);
_root.controller.swap(_name);
}

Поскольку кнопка находится на монтажном столе клипа, изображающего окно, при нажатии кнопки начинается перетаскивание самого этого ( this ) окна.
Второе действие вызывает функцию (пока не написанную). Функция эта, под названием , будет находиться в клипе controller, ее роль будет заключаться в изменении z-положения окна так, чтобы оно оказалось на самом верху. Функция при вызове смотрит переданное ей значение свойства _name (представляющее имя экземпляра) текущего фильма. Наш проект содержит два экземпляра одного и того же клипа – window1 и window2, поэтому кнопка будет работать следующим образом: если кнопка нажата в экземпляре window1, начинается перетаскивание этого экземпляра, и функции передается значение "window1". Если же кнопка нажата в экземпляре window2, начинается перетаскивание этого экземпляра, и функции передается значение "window2".
on (release) {
stopDrag ();
}
При отпускании кнопки процесс перетаскивания прекращается.
topDog = "window1";
Для смены глубин размещения экземпляров window1 и window2 мы применим метод . Переменная topDog будет хранить имя того экземпляра, который расположен выше. При генерации фильма выше окажется window1, поэтому мы присваиваем переменной именно такое начальное значение.
function swap (name) {
_root[name].swapDepths(_root[topDog]);
topDog = name;
}
Назначение этой функции – поменять глубинами экземпляр клипа с именем, содержащимся в name (значение параметра, передаваемого функции) и экземпляр с именем, содержащимся в переменной topDog. После этого переменная topDog получает новое значение – это будет имя экземпляра, который теперь оказался сверху. На шаге 6 мы видели, что функции в качестве параметра передается свойство _name текущего фильма (это может быть либо window1, либо window2 ). Предполагая, что в некоторый момент переменная topDog имеет значение "window1", нажатие кнопки перетаскивания в window2 (при этом будет вызвана функция и ей передано значение "window2" ) приведет к такому выполнению функции:
function swap ("window2") {
_root.window2.swapDepths(_root.window1);
topDog = "window2";
}
Как только вы нажмете кнопку в верхней части окна, он окажется верхним по глубине и начнется процесс перетаскивания.
Ну, а при нажатии на кнопки выбора цвета происходит только одно: изменяется значение переменной currentColor в экземпляре клипа controller, в результате чего новые линии будут изображаться новым цветом.
Итак, мы с вами применили метод для перемещения на передний план нужного окна. Но проект еще не закончен! Мы должны запрограммировать очистку рабочей области рисования, а также возможность перетаскивания на нее картинок-шаблонов.
Зачастую при создании пользовательского интерфейса возникает необходимость реализовать для экземпляров клипов операцию типа "перетащить и оставить" ( ). Этим термином обозначают следующий процесс: при нажатии кнопки мыши на экземпляре начинается его перетаскивание, которое прекращается, как только кнопка мыши будет отпущена. В результате может быть выполнен некоторый набор действий (в зависимости от того, в каком месте оставлен экземпляр). Самый простой пример – "мусорная" Корзина на
Обычно во Flash операция "перетащить и оставить" реализуется при помощи _droptarget или hitTest(). Значение свойства фильма _droptarget – путь к самому "переднеплановому" экземпляру фильма-символа из тех, над которыми в данный момент находится перетаскиваемый экземпляр клипа. С помощью метода hitTest() можно определить момент, когда экземпляр касается своей границей границы другого экземпляра (подробнее об этом см. Урок 9, Использование логических условий). На практике чаще метод hitTest() используется гораздо чаще, чем свойство _droptarget, как более гибкий и многоцелевой.
В этом упражнении мы добавим в наш проект динамически формируемую строку значков (простых графических фильмов-символов), которые можно будет перетаскивать в рабочую область рисования – это мы реализуем с помощью метода hitTest(). Для перетащенного и оставленного значка будет создана копия (при помощи duplicateMovieClip() ), а оригинал будет возвращен на прежнее место.
В таком виде мы с вами оставили этот файл после выполнения предыдущего упражнения. Сейчас мы будем добавлять скрипты к экземплярам клипов controller и . Для начала мы создадим функцию, формирующую строку значков под областью рисования. Затем мы запрограммируем возможность перетаскивания этих значков, а также отслеживание случая, если они оставлены на области рисования.
function buildIconList() {
spacing = 85;
iconY = 360;
iconX = 70;
var i = -1;
while (++i < _root.icon._totalFrames) {
newName = "icon" + i;
_root.icon.duplicateMovieClip(newName, 10000 + i);
_root[newName]._x = iconX + i * spacing;
_root[newName]._y = iconY;
_root[newName].gotoAndStop(i + 1);
}
}
Ничего для вас нового в этой функции нет. На монтажном столе экземпляра клипа содержится некоторое количество кадров, в каждом из которых имеется изображение одного из значков. Данный скрипт создает по одному дубликату клипа для каждого из этих кадров. Дубликаты располагаются в одну линию в нижней части экрана; курсор воспроизведения каждого дубликата перемещается на соответствующий кадр. В результате мы получим строку из нескольких значков. Можно уменьшить или увеличить число значков (то бишь, кадров в экземпляре клипа ) – наш скрипт сам "узнает" об этом, поскольку примененный нами while базируется на значении свойства _totalFrames (общее число кадров в клипе). Переменная spacing определяет расстояние по горизонтали между дубликатами. Переменные iconX и iconY – координаты первого дубликата.

Это будет вызов только что созданной нами функции для
on (press) {
startDrag (this);
}
Итак, повторим, что у нас происходит на двух предыдущих шагах. Экземпляр клипа (содержащий кнопку, к которой мы только что присоединили скрипт) дублируется четырежды, каждый из четырех дубликатов переходит к одному из четырех кадров, имеющихся на его монтажном столе. Тем самым под областью рисования появляется четыре значка, каждый со своим рисунком. Любой из этих значков можно перетащить в область рисования, и, если он будет там оставлен, в рабочей области будет создана его копия (да-да, дубликат дубликата). Невидимая кнопка при нажатии выполняет действие startDrag(),
Важно отметить, что эта невидимая кнопка имеет имя iconButton. Для чего это нужно? Когда значок будет оставлен в области рисования и продублирован, дубликат унаследует и невидимую кнопку, и все присоединенные к ней действия. А это значит, что дубликат в области рисования тоже будет перетаскиваемым, а это нам совершенно не нужно. Мы хотим, чтобы в области рисования осталось стационарное изображение, в качестве шаблона для рисования. Поэтому мы и присвоили кнопке имя – чтобы иметь возможность отключить ее в дубликате, помещенном в область рисования. Функцию, обрабатывающую перетаскивание, мы настроим таким образом, чтобы после создания дубликата кнопка в нем отключалась и не могла более вызвать действие startDrag(). Кнопка должна работать только в тех экземплярах клипа , которые находятся под областью рисования.

on (release) {
stopDrag();
_root.controller.iconReleased(_name);
}
Первое действие в этом скрипте просто прекращает процесс перетаскивания, если кнопка отпущена – экземпляр клипа "оставлен". Второе действие вызывает функцию iconReleased() (еще не написанную) в экземпляре клипа controller. Эта функция будет создавать дубликат клипа-значка, перетащенного в область рисования, а оригинал возвращать на прежнее место (под областью рисования), откуда его можно будет вновь перетащить. Обратите внимание, что функции в качестве параметра передается свойство _name перетащенного экземпляра – ведь функция должна знать, какой из четырех значков был в данном случае перетащен в область рисования.
onClipEvent (load) {
homeX = _x;
homey = _y;
}
Используя событие load, мы создаем в экземпляре, сразу после его загрузки, две переменные – homeX и homeY, в которых хранятся начальные координаты экземпляра. Этот скрипт будут наследовать все дубликаты, и значит, на монтажном столе каждого из них будут храниться начальные координаты по X и Y. Эти значения нужны нам, чтобы возвращать на место значки после перетаскивания их в область рисования.
Теперь давайте напишем функцию, которая объединит наши разрозненные скрипты.
function iconReleased (name) {
if (_root.canvas.hitTest(_root._xmouse, _root._ymouse)) {
++v;
newName = "object" + v;
_root[name].duplicateMovieClip(newName, v);
_root[newName].gotoAndStop(_root[name]._currentFrame);
_root[newName].iconButton.enabled = false;
_root[newName]._xscale = 250;
_root[newName]._yscale = 250;
}
_root[name]._x = _root[name].homeX;
_root[name]._y = _root[name].homeY;
}
У этой функции один аргумент – name. Как мы упоминали на шаге 5, значением этого параметра будет имя экземпляра (свойство _name ) значка, перетащенного в область рисования. Значение параметра играет важнейшую роль в работе функции.
Первым делом duplicateMovieClip() создается копия перетащенного экземпляра клипа. Имя, которое получит дубликат, получается путем объединения строки "object" и значения переменной v (которая увеличивается на единицу при каждом очередном создании дубликата). Таким образом, текущее значение v всегда равно числу дубликатов значков, перетащенных в область рисования – запомните это, в следующем упражнении оно нам пригодится.
Созданный дубликат отсылается к тому же кадру, что и экземпляр-оригинал (значок, перетащенный в область рисования). Следующее действие отключает в дубликате невидимую кнопку iconButton (мы говорили об этом на шаге 4). Вдобавок дубликат масштабируется по вертикали и горизонтали до размера 250 процентов – таким образом, экземпляр клипа в области рисования получится больше, чем соответствующий значок.
Примечание Экземпляр-дубликат наследует (в момент дублирования) X и Y координаты оригинала. Поэтому, если дубликат сразу же не переместить, он расположится прямо над оригиналом (в этом случае, если бы не масштабирование, на экране даже не произошло бы никаких видимых изменений).о отправляют перетащенный экземпляр клипа на прежнее место, координаты которого хранятся в переменных homeX и homeY на его монтажном столе. Обратите внимание: эти два действия находятся вне false, и дубликат не был создан. Таким образом, если пользователь попытается оставить значок не в области рисования (над экземпляром клипа ), а где-либо в другом месте, дубликат не создается, и значок просто возвращается на свою начальную позицию в нижней части экрана.

Если вы попытаетесь оставить перетаскиваемый значок за пределами экземпляра , он вернется на прежнее место, без создания дубликата. Если же кнопка мыши будет отпущена в тот момент, когда значок находится над экземпляром клипа , будет создан дубликат, а оригинал опять же вернется на прежнее место.
Мы с вами создали простенькое приложение для рисования. Возможности
Динамически созданные линии можно легко удалить с любого монтажного стола при помощи метода clear(). Синтаксис прост:
путь.clear();
Экземпляры клипов, созданные при помощи duplicateMovieClip() или (как значки, которые мы перетаскивали в область рисования), можно удалить при помощи метода объекта .
Примечание С помощью этого метода можно удалить только те экземпляры клипов, которые созданы динамически, при помощи
Удаление экземпляров клипов может пригодиться для динамического удаления содержимого со сцены, для реинициализации приложений и освобождения
someMovieClip.removeMovieClip();
В этом упражнении мы с вами создадим функцию, которая будет удалять из области рисования все динамически нарисованные линии, а также экземпляры клипа , перетащенные в область рисования.
В таком виде мы оставили файл после выполнения предыдущего упражнения. В этом упражнении мы добавим в controller функцию, очищающую область рисования. Запускаться функция будет скриптом, который мы присоединим к кнопке Clear, находящейся в экземпляре клипа window2.
function clearContent () {
_root.holder.clear();
i = 0;
while (++i <= v) {
name = "object" + i;
_root[name].removeMovieClip();
}
v = 0;
}
Первое действие в этой функции удаляет все динамически нарисованные линии из экземпляра клипа . Далее следует несложный цикл while, удаляющий все перетащенные на сцену экземпляры клипа . Значение переменной v равно общему числу перетащенных экземпляров , ведь v увеличивается на единицу всякий раз, когда в области рисования создается дубликат – мы с вами запрограммировали это в функции buildIconList(), в предыдущем упражнении. Теперь мы используем значение v для определения количества итераций цикла, удаляющего дубликаты. После того, как цикл завершен (все экземпляры из области рисования удалены), переменной v присваивается значение 0, так что когда в область рисования будет перетащен новый экземпляр , нумерация дубликатов вновь начнется с нуля.

В этом кадре имеется две кнопки – Clear и Print. Нам нужно присоединить к кнопке Clear скрипт, вызывающий функцию clearContent() из экземпляра клипа controller. Заодно уж давайте добавим скрипт к кнопке Print.
on (release) {
printAsBitmap ("_root", "bmovie");
}
Если эту кнопку нажать и отпустить, графическое содержимое главного монтажного стола (то есть, все, что в момент нажатия кнопки находится на сцене, включая динамически созданные экземпляры) будет распечатано как растровое изображение в натуральную величину.
Примечание Этим скриптом мы хотим продемонстрировать, что динамически созданные экземпляры можно распечатать столь же легко, как и другое содержимое фильма. Если бы создавали более изощренное приложение, мы могли бы предпочесть распечатывание только содержимого области рисования. Однако тогда пришлось бы иначе строить наши функции, а мы не захотели усложнять упражнения, поскольку изучение возможностей печати не является целью данного урока.
on (release) {
_parent.controller.clearContent();
}
Если эту кнопку нажать и отпустить, будет выполнена функция clearContent(), присоединенная к экземпляру controller.
При нажатии кнопки Clear будет выполнена функция очистки, цикл while в ней удалит все созданные в области рисования экземпляры клипов.
На этом закончено упражнение и весь урок. Как видите, процесс динамического удаления материалов куда проще процесса создания. Ну, теперь вы умеете делать и то, и другое, а это обеспечит вашим проектам колоссальные возможности взаимодействия с пользователем. Ну, разве не великолепен этот
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.