В попередніх статтях нам неодноразово доводилося працювати з об’єктами відображення (display object), хоча саме поняття display object вживається на “сторінках” цього блога вперше. По-суті будь-який візуальний об’єкт, який можна розмістити на сцені – це і є об’єкт відображення.
Клас DisplayObject є базовим для всіх об’єктів, які можуть бути візуально представлені у флеш-кліпі. Наприклад, будь-який MovieClip чи Sprite, з якими нам доводилося працювати раніше, також належить до об’єктів відображення, хоча насправді їх перелік куди ширший. Згадайте хоча б статтю про динамічне додавання MovieClip на сцену методами ActionScript 3. Зірки, які використовувалися у наведеному там прикладі також належать до об’єктів відображення.
Розуміння концепції списку відображення (display list) та ролі об’єктів відображення у створенні flash-програм надзвичайно важливе для кожного початківця, який прагне навчитися програмуванню на ActionScript. Адже по суті кожна програма, написана на ActionScript 3.0 має власну ієрархію об’єктів відображення, яка включає повний набір візуальних елементів. Це базова концепція, зрозумівши яку, ви наблизитесь до розуміння принципів функціонування AS3-програм та навчитесь з легкістю маніпулювати будь-якими візуальними об’єктами всередині власної програми.
Візуальні елементи можна умовно поділити на три групи:
- Сцена (Stage). Це основний контейнер для всіх об’єктів відображення. Сцена завжди знаходиться в основі ієрархії візуальних елементів і тому будь-яка flash-програма може включати лише одну сцену.
- Об’єкт відображення (Display object). У ActionScript 3 всі без виключення елементи, які можуть бути візуально представлені на екрані, належать до типу об’єктів відображення та є успадкованими від класу DisplayObject. Форми (Shapes), фрагменти кліпу (Movie clips), спрайти (Sprites) і навіть текстові поля (Text fields) по суті є об’єктами відображення. І це лише невелика частина від загальної їх кількості.
- Контейнер об’єктів відображення (Display object container). Об’єкти відображення можуть бути розміщені тільки всередині контейнерів, основним з яких є вже згадана нами сцена. Втім, не тільки сцена може фізично містити візуальні елементи. Деякі об’єкти відображення (Movie Clip, Sprite) водночас можуть бути контейнерами для інших об’єктів відображення. Наприклад, ви можете розмістити довільну кількість форм, кліпів чи текстових полів всередині іншого кліпу чи спрайта. Такі об’єкти відображення, розміщені всередині контейнера, називаються дітьми (children) цього контейнера і записуються до списку дітей (child list).
Список об’єктів відображення (Display list)
Список об’єктів відображення у ActionScript завжди включає в себе всі видимі елементи вашої програми. Найпростіший спосіб зрозуміти принцип формування списку об’єктів відображення – уявити собі структуру дерева, в якій сцена є стовбуром (основою), гілки – контейнерами об’єктів відображення, а листя – самими об’єктами відображення. У дерева є тільки один стовбур, але може бути бути скільки-завгодно гілок. На одній гілці може рости багато листя, а також інші гілки. Але ніколи гілки не ростуть на листі.
Наведена нижче діаграма демонструє приклад гіпотетичної ієрархії об’єктів відображення у SWF-файлі:
Діти (тобто будь-які об’єкти відображення всередині контейнерів) завжди візуально знаходяться вище, ніж їхні “батьки” (тобто сам контейнер). Якщо ж контейнер містить багато об’єктів відображення (дітей) то вище будуть знаходитися ті об’єкти, які були додані в контейнер пізніше. Кожному такому об’єктові присвоюється свій порядковий номер (починаючи з нуля). За допомогою коду ActionScript ми можемо впливати на порядок розміщення візуальних елементів у списку відображення.
Як додавати об’єкти (display object) в список відображення (display list)
Що ж, сподіваюся, я не надто втомив вас “сухою” теорією. Зараз ми спробуємо створити просту флеш-програму, яка продемонструє всі переваги використання об’єктів відображення та списку відображення, а також керування ними методами ActionScript 3.
Створіть новий флеш-файл, в якому створіть три символи MovieClip: чотирикутник, коло та трикутник. Для зручності можете розфарбувати їх різними кольорами. А також не забудьте під час створення символів експортувати кожен з них для використання через ActionScript. Про те, як це зробити, написано у вже згаданій раніше статті. Я назвав символи Square_mc, Circle_mc та Triangle_mc відповідно. Приставка _mc дозволяє легко орієнтуватися, що ми маємо справу з Movie Clip-ами. Це додає читабельності нашому коду, особливо, якщо останнього буде дуже багато.
Після створення символів видаліть їх зі сцени, щоб вони залишилися тільки у бібліотеці. Ми будемо додавати ці символи динамічно, за допомогою ActionScript.
Тепер приступаємо до написання коду. Якщо у попередніх статтях код ми писали безпосередньо у кадрах fla-файлу, то тепер настав час переходити до створення окремих as-файлів. Пора звикати до нормальної роботи зі зручними інструментами розробки і нарешті відмовитися від убогого редактора коду у Flash IDE.
Для роботи з as-файлами вам знадобиться редактор FlashDevelop. Про те, як налаштувати FlashDevelop, структурувати as-файли та підключити файл до проекту я писав у статті “Використання Flash IDE + Flash Develop“. В майбутньому ми будемо завжди користуватися подібною структурою, тому раджу вивчити та звикнути до неї. З часом ви зрозумієте, наскільки це просто та зручно.
Скажу лишень, що для потреб демонстрації роботи display object зовсім не обов’язково створювати багато вкладених папок і файлів. Я розмістив fla-файл та єдиний as-файл Main.as у одній папці. Нагадаю, що для підключення as-файла до вашого флеш-проекту потрібно прописати його у полі Class. Ось як це виглядає:
У файлі Main.as пишемо наступний код:
package //не потрібно вказувати пакет, бо as-файл та fla-файл знаходяться в одній папці { import flash.display.Sprite; import flash.display.MovieClip; import flash.display.TriangleCulling; public class Main extends Sprite { /*вказуємо три змінні: чотирикутник, коло та трикутник *і зразу присвоюємо їм візуальне відображення із бібліотеки */ private var square:MovieClip = new Square_mc(); private var circle:MovieClip = new Circle_mc(); private var triangle:MovieClip = new Triangle_mc(); public function Main ():void { //вказуємо координати об'єктам, щоб красиво розмістити їх на сцені square.x = 100; square.y = 100; circle.x = 150; circle.y = 60; triangle.x = 140; triangle.y = 120; //додаємо об'єкти до списку відображення addChild(square); addChild(circle); addChild(triangle); } } }
Якщо все було зроблено правильно, то при тестуванні файлу отримаємо такий результат:
Зверніть увагу, що порядок об’єктів відображення у списку відповідає порядку їх додавання. Першим був доданий чотирикутник – тож візуально він знаходиться під колом та трикутником. Останнім був доданий трикутник – він знаходиться над обома іншими об’єктами.
Власне, метод addChild() і є основною директивою, яка додає об’єкт до списку відображення. Якщо ви хочете “вставити” новий об’єкт в конкретну позицію списку, потрібно використовувати метод addChildAt().
Нумерація об’єктів у списку починається з нуля. Тому метод addChildAt(0) вставить об’єкт на найнижчу позицію у переліку.
Спробуйте змінити частину коду, в якій об’єкти додаються у список на:
addChild(square); addChild(circle); addChildAt(triangle, 0);
і ви побачите, що хоча чотирикутник та коло були додані першими, та все ж трикутник опинився найнижче, оскільки ми чітко вказали йому позицію на самому початку списку відображення. Таким чином індекси у списку відображення трикутника, чотирикутника та кола стали відповідно 0, 1 та 2.
Варто також пам’ятати, що у списку відображення існують тільки ті індекси, які присвоєні вже доданим до нього об’єктам. Спроба додати об’єкт на позицію, якої ще не існує, викличе помилку. Таким чином, наприклад, код:
addChildAt(square, 2); addChild(circle); addChild(triangle);
буде неправильним і програма не запуститься, тому що в момент додавання першого об’єкта (чотирикутника) індекса 2 у списку відображення ще не існує.
Зміна глибини (depth) об’єкта у списку відображення (display list)
Існує кілька способів змінити індекс об’єкта у списку відображення. З одним із них ми вже познайомилися вище – це метод addChildAt(), який дозволяє вказати точний індекс об’єкта. При цьому якщо об’єкт з таким індексом існує, то він автоматично переміщується вище.
Розберемо повторно код:
addChild(square); addChild(circle); addChildAt(triangle, 0);
Спершу до списку відображення додається чотирикутник і йому присвоюється індекс 0. Другим додається коло, і йому, відповідно, присвоюється індекс 1. Потім додається трикутник і йому примусово встановлюється індекс 0. Таким чином трикутник опиняється на “дні” списку відображення, а чотирикутнику та колу присвоюються індекси 1 і 2 відповідно.
Для об’єктів, які вже знаходяться у списку відображення, можна використовувати метод setChildIndex(), який діє по аналогії з addChildAt(). Якщо ж ви просто хочете поміняти місцями два об’єкти у списку відображення – використовується метод swapChildren() (якщо у вас є посилання на обидва об’єкти) або swapChildrenAt() (якщо вам відомі індекси цих об’єктів).
Якщо ж ви знаєте індекс об’єкта і хочете звернутися до нього – використовуйте метод getChildAt().
Щоб закріпити матеріал на практиці давайте спробуємо модифікувати попередній приклад з чотирикутником, колом та трикутником таким чином, щоб при кліку по будь-якому із об’єктів, він переміщувався на вершину списку відображення.
Значна частина коду залишилася без змін. З’явилося тільки кілька нових імпортів, слухачі подій мишки та функція, яка змінює розташування об’єктів у списку відображення. Ось оновлений код:
package //не потрібно вказувати пакет, бо as-файл та fla-файл знаходяться в одній папці { import flash.display.DisplayObject; import flash.display.Sprite; import flash.display.MovieClip; import flash.events.MouseEvent; public class Main extends Sprite { /*вказуємо три змінні: чотирикутник, коло та трикутник *і зразу присвоюємо їм візуальне відображення із бібліотеки */ private var square:MovieClip = new Square_mc(); private var circle:MovieClip = new Circle_mc(); private var triangle:MovieClip = new Triangle_mc(); public function Main ():void { //вказуємо координати об'єктам, щоб красиво розмістити їх на сцені square.x = 100; square.y = 100; circle.x = 150; circle.y = 60; triangle.x = 140; triangle.y = 120; //додаємо об'єкти до списку відображення addChild(square); addChild(circle); addChild(triangle); //додаємо слухачі подій до кожного об'єкта square.addEventListener(MouseEvent.CLICK, onClickHandler); circle.addEventListener(MouseEvent.CLICK, onClickHandler); triangle.addEventListener(MouseEvent.CLICK, onClickHandler); } private function onClickHandler(e:MouseEvent): void { //присвоюємо змінній clickedObject об'єкт, на який ми клікнули var clickedObject:DisplayObject = e.target as DisplayObject; /*Змінюємо індекс у списку відображення нашого об'єкта. *Зверніть увагу, на змінну numChildren, яка завжди повертає *загальну кількість об'єктів відображення. Таким чином, *щоб розмістити об'єкт останнім у списку відображення, *потрібно присвоїти йому індекс numChildren - 1 */ setChildIndex(clickedObject, numChildren - 1); } } }
Особливу увагу потрібно звернути на нову змінну numChildren, яка повертає загальну кількість дітей у списку відображення. В нашому випадку їх 3. Таким чином, оскільки нумерація в списку починається з нуля, щоб отримати індекс найвищого об’єкта, потрібно від змінної numChildren відняти одиницю.
А ось і результат виконання нового коду. Клікайте по об’єктах і вони будуть переміщуватися на вершину списку відображення:
Видалення об’єктів (display object) зі списку відображення (display list)
Останнє, що потрібно навчитися для повноцінної роботи зі списком відображення – це видалення об’єктів зі списку. Для цього використовується метод removeChild(), який передає посилання на об’єкт як параметр. Спробуйте модифікувати код першого прикладу, додавши одну стрічку:
addChild(square); addChild(circle); addChild(triangle); removeChild(circle);
І ви побачите, що при тестуванні флеш-файлу коло на екрані не з’явиться. Воно буде спершу додане у список відображення, але потім відразу ж видалене з нього.
Для видалення об’єкта з конкретним індексом у списку використовується метод removeChildAt().
Було б логічно, якби існував метод, який видаляє всі об’єкти зі списку відображення. Та з незрозумілих причин розробники AS3 не створили такого методу. Тому, щоб видалити всі об’єкти зі списку відображення, програмісти використовують наступну конструкцію-цикл:
while (numChildren > 0) { removeChildAt(0); }
Саме цей метод я використовував для того, щоб очистити сцену від зірок у статті про динамічне додавання Movie Clip на сцену.
Сподіваюся, тут все зрозуміло. Цикл перевіряє, чи є в контейнері хоча б один об’єкті відображення (numChildren > 0). Якщо хоча б один об’єкт присутній – виконується наступна стрічка коду: removeChildAt(0); – яка видаляє найнижчий об’єкт. Цикл повторюється до тих пір, поки в списку відображення не залишиться жодного об’єкту.
На цьому розповідь про роботу з об’єктами відображення та списком відображення можна закінчити. Сподіваюся, стаття не виявилася занадто складною. Зате такі базові знання допоможуть вам краще орієнтуватися у керуванні візуальними елементами. Задавайте запитання у коментарях.
Якщо стаття вам сподобалася, підпишіться на RSS блога про Flash та ActionScript, щоб не пропустити нічого важливого.
Грудень 18, 2012 о 23:28
Ярославе, хочу подякувати Вам за цей класний сайт, він допоміг мені стартувати у флеші. І одне питання маю, можливо, дурне. Як вказувати координати об”єкта в його контейнері?От я створив мувікліп, у нього помістив через addChild кілька інших мувиків, а коли я прописую їм координати, то програма сприймає їх як координати на сцені, глобальні.Мені потрібно рухати контейнер і щоб з ним рухались дочірні об”єкти. Дякую.