Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox
Par nataly (Nataly), le 13 février 2012

Variables, fonctions, syntaxe
Objets, méthodes, propriétés…
Clics et événements souris sur les boutons et les clips
Champs texte et objet String
Structures de contrôle alternatives : if
Manipuler un movieClip
• Structures de contrôle alternatives : switch
• Structures de contrôle répétitives : for - while
Liste d'affichage, imbrication et profondeur des objets (ici)
Liste d'affichage, gestion dynamique des objets
Les tableaux

Liste d'affichage, imbrication et profondeur des objets

Maintenant qu'on est bien à l'aise avec les choses fondamentales, qu'on sait déclarer des variables, écrire des fonctions, structurer le code, écouter les événements et piloter la tête de lecture d'un clip1), on va pouvoir s'intéresser à la gestion dynamique des symboles de bibliothèque. J'entends par là travailler non plus seulement avec des symboles déjà présents sur l'animation, mais les ajouter (ou les supprimer) en cours d'exécution du code.

Les clips, les formes, les graphiques, les champs textes, les images et autres composants (listes déroulantes, cases à cocher, boutons radio…) sont des objets qui se voient et qu'on appelle objets d'affichage - rappelez vous : DisplayObjects.

Quand on parle de liste d'affichage, on parle de la hiérarchie de ces objets, de leur organisation, disposition, imbrication.

Attention : confuz !

Avant toute chose il va s'agir de se mettre bien au point du vocabulaire et de définir clairement ce qui se cache sous les termes d'usage courant 'scénario principal' et 'scène' souvent employés comme synonymes dans la plus joyeuse confusion.

la doc : La scène constitue le conteneur de base des objets d’affichage. Chaque application comporte un objet Stage, qui contient tous les objets d’affichage à l’écran. La scène correspond au conteneur de plus haut niveau et domine la hiérarchie de la liste d’affichage.

La scène est le conteneur principal de l'application (ou animation, c'est pareil pour moi), c'est elle qui est chargée par le lecteur Flash ou AIR.

Attention la scène en elle même n'est pas un clip.
Elle contient le clip de premier niveau, celui qui contiendra tous les autres et qu'on appelle le scénario principal.

Quand on parle de dessiner sur la scène, ou d'y glisser une instance de symbole c'est un abus de langage. En fait on dessine sur le scénario principal, on lui ajoute des instances de symbole, on en manipule la tête de lecture.

On est bien d'accord que quand vous “mettez un stop” image 1 de soit disant la scène, ce stop ne s'adresse pas à la scène - qui n'y peut mais, la pauvre - mais bel et bien au gros clip dont vous voyez d'ailleurs le scénario dans l'environnement de travail.

Vous pouvez vous figurer la scène comme une scène de théâtre, ce n'est rien d'autre qu'un espace où les acteurs jouent. C'est bien à l'acteur qu'on donne des consignes (joue/play) et pas à l'espace scénique.

Hiérarchie des objets d'affichage

Commençons donc par dire clairement ce que je me suis, jusqu'à présent, contentée d'utiliser sans plus m'y arrêter en considérant que votre côté intuitif ferait le reste, je parle de l'adressage.

Adressage descendant

Imaginons, posé image 1 du scénario principal, un clip nommé village dans lequel il y a plusieurs clips nommés maison1, maison2, maison3… et pourquoi pas un clip nommé eglise.
Imaginons toujours que dans le clip nommé maison1 se trouve un clip nommé fenetre et que l'on souhaite utiliser, manipuler, ce clip nommé fenetre (mettons pour l'allumer en affichant l'image deux à l'aide d'un nextFrame).

Rien de révolutionnaire pour vous : sur l'image 1 d'un calque dédié au code, comme on en a pris l'habitude, vous écririez :

village.maison1.fenetre.nextFrame();


C'est ce qu'on appelle la notation à points.

Quand on écrit du code “sur” une image d'un clip (ou d'un graphique) on ne peut atteindre que les objets qui sont directement posés sur l'image considérée. Pour atteindre les objets inclus il faut, à la façon des poupées russes, descendre de contenant en contenant en utilisant des points pour séparer les noms.

Conséquence seconde, si vous avez un objet posé image 10 d'un clip, vous ne pourrez pas écrire du code le concernant image 1. Il faudra soit écrire le code image 10, soit poser l'objet en question image 1 et le rendre invisible.

Notation “à points” disais-je… C'est là que le ronchon de service se réveille et râle que j'ai précédemment dit que le point sépare toujours l'objet (à gauche) de sa méthode ou propriété… Alors ce n'est plus vrai ?
Si :)
Quand j'écris : village.maison (etc), maison est compris comme une propriété de village (qui renvoie le clip maison). Ce qui d'ailleurs est furieusement pratique :

Imaginons la structure suivante : dans village un clip eglise, dans eglise un clip toit, dans toit un clip girouette (je force un peu de l'imbrication pour qu'on se comprenne bien), si on a à utiliser souvent le clip girouette, ça va devenir pénible de saisir à chaque fois :

village.eglise.toit.girouette.uneMéthode();

On peut alors s'y prendre comme suit :

var laGirouette:MovieClip= village.eglise.toit.girouette;
 
laGirouette.play();
 
[]
laGirouette.stop();// à chaque fois je peux utiliser la variable, ce qui rend le code plus lisible et manipulable ;)

Adressage ascendant

pour faire le chemin inverse : remonter au contenant d'un clip, on utilisera la propriété parent. En reprenant l'exemple précédant :

laGirouette.parent; // renvoie le clip toit
laGirouette.parent.parent; // renvoie le clip eglise

Attention transtypage !

La propriété parent est de type DisplayObjectContainer, comprendre elle renvoie un objet de type DisplayObjectContainer.
Du coup, si vous écrivez :

var laFenetre:MovieClip= maison.fenetre
 
laFenetre.parent.alpha=0.5; // tout va bien 
laFenetre.parent.stop(); // erreur !!

Vous voyez pourquoi la dernière ligne renvoie une erreur ?

Parce que la méthode stop est une méthode de MovieClip, or laFenetre.parent est un DisplayObjectContainer qui n'expose pas de méthode stop.
Selon le même raisonnement qu'expliqué chapitre manipuler les clips, il va alors falloir préciser qu'on est certain que laFenetre.parent est bien un clip, et peut être manipulé en tant que clip :

MovieClip(laFenetre.parent).stop();

[exo getChildByName ?]

Profondeur des objets d'affichage

Revenons à la liste d'affichage.
C'est donc la liste de tous les objets affichés, chaque DisplayObjectContenair 2) a sa liste d'affichage qui répertorie tous ses enfants. On peut en ajouter, en enlever et en gérer l'ordre de superposition.


Vous l'avez constaté, si vous posez plusieurs instances de symboles dans un même clip et que vous les faites se chevaucher, immanquablement elles se superposent et c'est bien normal.
Cette superposition, l'ordre dans lequel les objets sont empilés, c'est ce dont on parle quand il est question de profondeur. Chaque enfant (clip contenu) d'un conteneur est situé sur un niveau d'empilement propre qu'on appelle le numéro d'index.

Attention, dans la VEV (vie en vrai), on peut poser deux objets côte à côte : on peut disposer deux cartes à jouer sur la table, elles sont à la même hauteur (depuis la table), ce n'est que si on veut les mettre au même endroit qu'inéluctablement il faudra en glisser une par dessus l'autre.
Avec AS3, on a un objet par numéro d'index (ou le contraire ;)) même s'ils sont sur le même calque, et les numéro d'index se suivent3).

Ne confondez pas calque et profondeur : le rapport est assez lointain. Les calques sont des “outils” pour dessiner, ils n'existent pas pour le programmeur.
D'ailleurs, preuve : vous pouvez avoir des calques vides, et/ou plusieurs objets par calque.

Ici le carré noir est en zéro, le rouge en 1, le vert en 2, le bleu en 3, le jaune 4.

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

A retenir :
Le clip en arrière plan est toujours au niveau zéro et il n'existe pas d'index négatif.

Il ne peut pas y avoir de “trou” dans la séquence d'index (profondeurs). Dit autrement : vous ne pouvez pas avoir une instance en zéro, une autre en 2 et rien en 1.

Connaitre la profondeur : getChildIndex

Pour connaitre l'index d'un enfant d'un conteneur on a recours à la méthode getChildIndex appliquée au conteneur en question en lui passant l'objet dont on veut connaitre la profondeur.

var leClip:MovieClip=conteneur.rouge;
trace(conteneur.getChildIndex(leClip));

Pour vous dégourdir les doigts

Histoire de vous réveiller, je vous propose de d'écrire le bout de code qui permet la démo ci-dessus : écrire dans un champ texte le numéro d'index du clip cliqué.
Et comme il s'agit avant tout d'entrainement, il s'entend que vous ajouterez un seul écouteur (au conteneur) et que vous utiliserez le couplage faible (target et currentTarget) ;)

[solce plus bas ?]

Récupérer une instance selon son index : getChildAt

Le pendant de getChildIndex : donne moi la profondeur/index de cet enfant, c'est getChildAt : donne moi l'enfant à cette profondeur. Tout comme ses camarades cette méthode renvoie un DisplayObject.

var lobjetDaffichage:DisplayObject=conteneur.getChildAt(0);// ce qui est à l'arrière plan

Pour ce qui est de l'enfant au premier plan, et bien son index vaut le nombre d'enfants moins un (puisqu'on compte depuis zéro en informatique)

numChildren

Pendant qu'on parle du nombre d'enfants d'un clip, autant le dire tout de suite, c'est la propriété numChildren d'un conteneur qui renvoie le nombre de ses enfants.

trace(conteneur.numChildren);
var objetPremierPlan:DisplayObject=conteneur.getChildAt(conteneur.numChildren-1);// L'objet d'affichage au premier plan

Modifier l'ordre d'empilement

setChildIndex

Au même titre qu'on peut connaitre (get) le numéro d'index d'un clip dans la liste d'affichage, on peut affecter (set) un numéro d'index à un objet d'affichage.
Pour assigner un numéro d'index à un objet d'affichage, on a recours à la méthode setChildIndex appliquée au conteneur(toujours) à qui on passe un objet et le numéro d'index souhaité, en gardant bien en tête que :
• Pas de trou dans la séquence d'index ; donc pas d'index supérieur au nombre d'enfant 4)
• Assigner un numéro d'index autre que le courant, c'est forcément modifier l'ordre de superposition…

// "remonte" le clip rouge au niveau 4
var leClip:MovieClip=conteneur.rouge;
conteneur.setChildIndex(leClip,4));

swapChildren : intervertir les instances

Derniers outils pour gérer la profondeur des instances : comment intervertir deux enfants dans la “pile”.

Soit vous utilisez les objets eux même (des DisplayObject), sans forcément connaitre leurs profondeurs respectives et c'est swapChildren qui s'en charge :

conteneur.swapChildren(unClip,unAutreClip);

Soit vous souhaitez intervertir des objets d'affichages à des profondeurs explicites et vous aurez alors recours à swapChildrenAt :

conteneur.swapChildrenAt(index1,index2);

Pour vous dégourdir les doigts

A vous de jouer !

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.

Si la fenêtre de sortie vous énerve à répéter que :

Error #2025: Le DisplayObject indiqué doit être un enfant de l'appelant

… souvenez vous de la différence MouseOver/RollOver ;)

1) quand même !… C'est pas rien. Ne vous privez pas d'un peu d'autosatisfaction - vu qu'on n'est jamais si bien servi que par soi-même
2) conteneur d'objet d'affichage
3) en partant de zéro pour l'arrière plan
4) n'oubliez pas qu'en informatique on compte depuis zéro : 3 enfants implique que le dernier (premier plan) est en index 2.