Виртуальные слои клипов

Немного отвлечемся от ActionScript и вспомним, что происходит при создании экземпляров клипов «вручную». Вы замечали, что экземпляр, изготовленный позже данного, будет отображаться строго выше него (они, естественно, должны располагаться на одном слое). Более того, сколько бы вы ни бились, поместить клипы на один уровень у вас не получится. То же самое справедливо и для кнопок, экземпляров символов типа Graph, текстовых полей и даже фигур статичной графики.

В общем, все элементы, которые вы добавляете на один слой, отображаются относительно друг друга в той последовательности, в которой они были созданы. Однако при необходимости вы можете изменить взаимное расположение объектов, используя команды подменю Arrange меню Modify.

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


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

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

Номер виртуального слоя, на котором «прописан* объект, называется его глубиной (depth). С этим понятием мы уже встречались, когда разбирали методы, создающие экземпляры клипов.

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

// Создайте символ, хранящий изображение кружка, и "перетащите" один его
// экземпляр на рабочее поле.


Назовите его ball.
trace(ball.getDepth()); // Выводит: -16383

Таким образом, самый «глубокий» из созданных «вручную» объектов занимает виртуальный слой с номером -16383.

Кстати, метод getDepths(), помимо класса MovieClip, имеется у классов Button и TextField. Поэтому вы можете с легкостью узнавать глубину, на которой расположена кнопка или текстовое поле.

Значение глубины -16383 не является наименьшим. Flash-плейер резервирует позицию номер - 16384, чтобы вы могли программно поместить экземпляр клипа ниже всех остальных объектов, Лимита на наибольшее значение глубины не существует, т. е. организованные по виртуальным слоям объекты фактически образуют стек — очередь, у которой есть позиция начала, но нет постоянной позиции конца, Поэтому в некоторых книгах виртуальные слои клипов называют стеком клипов.

Логичным будет предположить, что созданные «вручную» компоненты клипа плотно упакованы — последовательно занимают все виртуальные слои, начиная от слоя с номером -16383. Однако это стоит проверить. Посмотрим, насколько отличаются глубины, занимаемые двумя последовательно созданными экземплярами клипа. Для этого «перетащим» на рабочее поле два кружка, назвав их ball и ball 1:

trace(ball.getDepth()); // Выводит: -16383
trace(ball1.getDepth()); // Выводит: -16381

Наше предположение оказалось неверным: разница в глубине между соседними созданными «вручную» объектами составляет 2 (в случае статичной графики разница равна 1).


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

Попробуем теперь разобраться, как связаны виртуальные слои со слоями «настоящими». Для этого поместим ball 1 на новый слой, лежащий выше старого. Глубина его при этом не изменится — это означает, что слои клипа в среде разработки и его внутренние слои прямо не связаны. При перемещении же нового слоя на вторую позицию получим:

traceball.getDepth()); // Выводит: -16381
trace(ball1.getDepth()); // Выводит: -16383

Таким образом, расположение слоя с одним экземпляром выше слоя со вторым вызывает своеобразный обмен глубинами.

Если вы попытаетесь поместить экземпляр клипа или текстовое поле на глубину, меньшую -16383, то необходимый элемент попросту не будет создан:

trace(attachMovie("ball","ball",-16385); // Выводит: undefined

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

attachMovie("ball", "ball1", 1000000);
trace(ball.getDepth()); // Выводит: 1000000

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

Поэтому очень большие значения глубины применять нет никакого смысла. Тем более, что к клипам, помещенным на очень маленькие или на очень большие глубины, не могут быть применены некоторые методы класса MovieClip. Так, например, метод removeMovieClip() (он служит для удаления клипа) не работает, если клип находится на глубине, меньшей нуля или большей 0xFFFFF.

На одной глубине может располагаться только один объект. Если вы попытаетесь «уплотнить» его соседом, то он просто исчезнет. Чтобы в этом убедиться, используем метод attachMovie для «перетаскивания» двух экземпляров при одинаковом значении depth:

attachMovie("ball","ball1",1,{_x:100});
attachMovie("ball","ball2",1,{_x:200}); // При тестировании отображается
// только один шарик

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

// Создайте несколько слоев и на каждом что-нибудь нарисуйте
// Очищаем 1000 глубин — чаще всего этого более чем достаточно
for (var i = 0; i<1000; i++) {
// Создаем пустой клип на очередной глубине
createEmptyMovieClip("clip", -16384+i);
clip.swapDepths(1); // removeMovieClip() не удаляет клипы
// с отрицательных глубин
clip.removeMovieClip(); // Удаляем клип
} // При тестировании рабочее поле будет полностью чистым

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

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

Метод swapDepths() имеет следующий синтаксис:

clip.swapDepths(depth),
где:

• clip — клип, который должен быть перемещен на другую глубину;
• depth — номер виртуального слоя, на который должен быть помещен клип.
Пример:
// Создайте клип в виде кружочка и назовите его ball
trace(ball.getDepth()); // Выводит: -16383
ball.swapDepths(1000); // Помещаем клип на тысячный виртуальный слой
trace(ball.getDepth()); // Выводит: 1000

Если на глубине, которая была прописана в качестве параметра метода swapDepths(), уже имеется экземпляр клипа, то он выгружен не будет. Данный клип будет помешен на глубину, которую освободил клип, вызвавший метод. Два клипа как бы обменяются глубинами. Отсюда, кстати, и название метода (английское swap — обменивать). Вообще случайно удалить какой-то объект, используя swapDepths(), в отличие от методов attachMovie(), duplicateMovieClip(), createEmptyMovieClip(), невозможно.

// Создаем два пустых клипа с сильно различающимися глубинами
createEmptyMovieClip("clip1", -1000);
createEmptyMovieClip("clip2", 1000);
clip2.swapDepths(-1000); // Пробуем поместить клип на занятую глубину
trace(clip1.getDepth()); // Выводит: 1000
trace(clip2.getDepth()); // Выводит: -1000 (произошел обмен глубинами)

Если глубину, на которую нужно поместить клип, занимает не клип, а кнопка, текстовое поле или статичная графика, обмен виртуальными слоями все равно будет проведен. Если клип проигрывался, то при применении к нему метода swapDepths() его прокрутка прекратится.

Метод swapDepths() предлагает также альтернативный синтаксис, позволяющий обменять глубинами два клипа:

createEmptyMovieClip("clip1", -1000);
createEmptyMovieClip("clip2", 1000);
clip2.swapDepths{clip1);
trace(clip1.getDepth()); // Выводит: 1000
trace(clip2.getDepth()); // Выводит: -1000

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

Метод swapDepths() позволяет менять глубину не только вложенных клипов, но и порядок отображения проигрываемых в плейере фильмов.

Поиск свободной глубины. Методы getlnstanceAtDepth() и getNextHighestDepth()
Главная сложность, которая связана с использованием методов dupticateMovieClip(), attachMovie(), createEmptyMovieClip(), а также с применением еще не рассмотренного нами метода createTextFileld(), заключается в том, что имеется риск задействовать уже занятую глубину. При этом объект, который на ней располагается (это может быть экземпляр клипа или кнопки, текстовое поле или простая графика), будет удален. Поэтому в тех случаях, когда вы не уверены, что данная глубина свободна, нужно проводить соответствующую проверку. Служит для этого метод getInstanceAtDepth(depth), где depth — номер глубины, вакантность которой должна быть определена. Возвращает данный метод ссылку на экземпляр, занимающий глубину depth. Если глубина свободна, результатом будет undefined.

Пример:
this.createEmptyMovieClip("clip", 0);
trace(this.getInstanceAtDepth(0)); // Выводит: _level0.clip
trace(this.getInstanceAtDepth(1)); // Выводит: undefined

Недостатком метода getInstanceAtDepth() является то, что он способен определять наличие на глубине лишь именованных объектов. Зарегистрировать же на данной глубине экземпляр символа типа Graph или статичную графику он не может. Это означает, что вы должны с чрезвычайной осторожностью применять отрицательные величины глубин, так как именно на них располагаются созданные «вручную» объекты. А лучше вообще отказаться от использования отрицательных глубин.

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

var i:Number=0;
while (clip.getInstanceAtDepth(i) != undefined) {
i++;
}
clip.createEmptyMovieClip("new_clip", i);

Если новый экземпляр должен отображаться выше всех остальных объектов на данной временной диаграмме, то определить подходящую для него глубину можно при помощи метода getNextHighestDepth(). Данный метод возвращает номер первой свободной глубины после самой высокой занятой. Например:

this.createEmptyMovieClip("clip",100);
trace(this.getNextHigheatDepth()); // Выводит: 101

Недостатком метода getNextHighestDepth() является то, что он не работает с отрицательными глубинами. Минимальное значение, которое может быть от него получено, равно 0:

this.createEmptyMovieClip("clip",-100);
trace(this.getNextHighestDepth()); // Выводит: 0 (должно быть: -99)

Метод getNextHighestDepth() довольно полезен, так как он дает возможность обойтись без введения дополнительной переменной, а которой бы фиксировалось, сколько экземпляров уже было создано.

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

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

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