Список отображения (display list) в ActionScript 3

Во флеш-роликах, созданных с помощью ранних версий языка ActionScript (до 3-ей версии) можно было создавать различные типы визуальных объектов: movieclip, графику, текстовые поля, компоненты и т.д. Все эти объекты не были организованы иерархически, a также создавались, удалялись и управлялись различными способами.

Например, movieclip мог быть взят из другого источника, дублирован и затем помещен на сцену в IDE (среда разработки, Flash Professional, например) или создан абсолютно с нуля с помощью ActionScript. C текстовыми полями та же история. Когда дело доходило до растровых объектов (bitmap), видео, компонентов и прочего, то возникало чувство, что все они создавались на разных планетах, а затем помещались во Flash, чтобы как-то работать с другими. Словом, царил некоторый беспорядок, с которым нужно было что-то делать.

На этом уроке Вы узнаете как была решена эта проблема в ActionScript 3, а также:

  1. Что такое список отображения (display list) в ActionScript 3
  2. Вспомните, что такое объект отображения (display object)
  3. По какому принципу устроен список отображения
  4. Как поместить один объект в другой объект с помощью AS 3

Итак, все эти различия были устранены в ActionScript 3. Практически любой тип объекта, который Вы видите на сцене создается с помощью класса, расширяющего класс DisplayObject. Другими словами, все эти объекты теперь являются частью одной большой семьи и при их создании, размещении на сцене, удалении и управлении они ведут себя во многом сходным образом.

Cоздание объектов типа sprite, movieclip или текстового поля в ActionScript 3 происходит одинаково. Все они создаются с помощью оператора new. Например:

var myTextfield:TextField = new TextField();
var myMovieClip:MovieClip = new MovieClip();
var mySprite:Sprite = new Sprite();

Как видите все просто!

В предыдущих уроках было показано, что после создания movieclip или sprite можно рисовать непосредственно в них, т.е. наполнять их определенным содержанием. Например:

mySprite.graphics.beginFill(0xff0000);
mySprite.graphics.drawCircle(0, 0, 40);
mySprite.graphics.endFill();

Но, если делать только так, то Вы мало что сможете увидеть. Поэтому сейчас самое время поговорить о списках отображения (display list).

Что такое список отображения (display list) в ActionScript 3

Для AS3 список отображения (display list) — это новый термин. Но, если у Вас уже есть опыт работы во Flash, то, наверняка, Вы успели с ним познакомиться. Представляйте его в виде дерева визуальных объектов, которые находятся в Вашем флеш-ролике.

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

Для примера рассмотрим простую композицию из 4-х объектов: строчки текста и трех фигур.

display-list-before

На самом деле, во Flash, структурно, я организовал все это чуть сложнее, чем мы видим. Каждая фигура помещена в отдельный movieclip со своим именем: star, rect и circle, а они, в свою очередь, находятся внутри movieclip figures. На рисунке ниже это показано.

Как устроен список показа во Flash

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

В ActionScript 3, созданный movieclip, sprite или другой объект отображения НЕ добавляется на сцену автоматически.

В примере, показанном выше (mySprite), у объекта типа sprite нет родителя, т.е. объекта в который он помещается. Мы можем управлять им и без включения в список отображения.

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

До настоящего момента мы использовали две метафоры: дерева и сцены. Но для того, чтобы разобраться со списком отображения еще лучше давайте воспользуемся еще одной. О нем также можно думать и в терминах семьи: родитель, потомок, брат/сестра. Когда Вы что-то добавляете в список отображения, то объект, к которому Вы добавляете будет родителем, а сам добавляемый объект — потомком. В таком контектсте название метода addChild() имеет смысл и ставит все на свои места.

Класс документа (document class) представляет из себя основание дерева или прадедушку всех объектов отображения (display object). Он виден по умолчанию и при работе, практически, над любым флеш-роликом Вы начинаете с того, что добавляете ему потомков. В предыдущих примерах было показано, что для того чтобы сделать sprite или любой другой визульный объект видимым нужно вызвать метод addChild() и передать ему в виде параметра вновь созданный объект:

var mySprite:Sprite = new Sprite();
mySprite.graphics.beginFill(0xff0000);
mySprite.graphics.drawCircle(0, 0, 40);
mySprite.graphics.endFill();
addChild(mySprite);

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

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

Чтобы удалить объект из списка отображения нужно вызвать метод removeChild(), которому в виде параметра передается имя объекта.

О чем нужно помнить и знать

Первое. Удаление объекта со сцены НЕ уничтожает его! Он продолжает существовать точно в таком же состоянии, что и до удаления, и будет делать это после добавления его в список отображения снова. Другими словами, если Вы нарисовали или поместили что-то в объект отображения (display object), а затем удалили, то это не значит, что Вам нужно снова рисовать или загружать те же объект(ы) для помещения в список отображения. Они продолжают там находиться.

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

Следующий пример демонстрирует взаимосвязь родитель-потомок:

package {
  import flash.display.Sprite;
  import flash.events.MouseEvent;
  public class Reparenting extends Sprite {
  private var parent1:Sprite;
  private var parent2:Sprite;
  private var ball:Sprite;
  public function Reparenting() {
      init();
  }
  private function init():void {
    parent1 = new Sprite();
    addChild(parent1);
    parent1.graphics.lineStyle(1, 0);
    parent1.graphics.drawRect(-50, -50, 100, 100);
    parent1.x = 60;
    parent1.y = 60;
    parent2 = new Sprite();
    addChild(parent2);
    parent2.graphics.lineStyle(1, 0);
    parent2.graphics.drawRect(-50, -50, 100, 100);
    parent2.x = 170;
    parent2.y = 60;
    ball = new Sprite();
    parent1.addChild(ball);
    ball.graphics.beginFill(0xff0000);
    ball.graphics.drawCircle(0, 0, 40);
    ball.graphics.endFill();
    ball.addEventListener(MouseEvent.CLICK, onBallClick);
  }
  public function onBallClick(event:MouseEvent):void
  {
      parent2.addChild(ball);
  }
 }
}

Как видно из кода этот класс создает три объекта типа sprite: parent1, parent2 и ball. Sprit'ы-родители непосредственно добавляются на сцену и в них рисуются квадраты. Sprite с именем ball добавляется в parent1. В результате он находится на сцене и мы его видим.

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

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

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

Итоги

В этом уроке Вы узнали о том, что такое список отображения (display list) и для чего он нужен. Это важный момент. В своей дальнейшей практике программиста Вы будете сталкиваться с этим постоянно, поэтому должны четко понимать как с этим работать. Чтобы закрепить изученный материал ответьте на несколько вопросов.

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

  1. В чем разница между списком отображения и объектом отображения в AS3?
  2. Как поместить один объект в другой?
  3. Что происходит с объектом после удаления его со сцены?
  4. Нужно ли создавать заново или импортировать объект, если Вы его удалили, а затем снова хотите поместить на сцену?

Жду вопросов. Задавайте в комментариях. Постараюсь ответить на все.