Forums Développement Multimédia

Les formations Mediabox
Les formations Mediabox
Compatible ActionScript 3. Cliquer pour en savoir plus sur les compatibilités.Par Nataly, le 19 octobre 2011

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
MovieClip : manipuler (ici)
• Structures de contrôle alternatives : switch
• Structures de contrôle répétitives : for - while
Liste d'affichage, imbrication et profondeur des objets
Liste d'affichage, gestion dynamique des objets
Les tableaux

Manipuler un MovieClip

L'objet phare, la vedette de Flash, c'est le clip, c'est donc par là que nous allons attaquer les choses vraiment sérieuses (ou rigolotes c'est selon l'état d'esprit).

Un clip, quand on parle vite, c'est une instance d'un symbole de bibliothèque de type Clip.

Dans un premier temps on va manipuler des instances (occurrences) de symbole déjà présentes sur la scène, on verra plus tard comment les ajouter en cours d'exécution (à la volée) - on dit dynamiquement.

Fabriquons donc un symbole de type Clip, animé - puisque c'est LA caractéristique principale de ces objets.

Tiens on va faire un ballon qui vole (ou une soucoupe volante pour les garçons :mrgreen:) :
Une instance de graphique Gr_Ballon animée sur un guide mouvement (pour CS3 et comme vous voulez après).



On en glisse une occurrences sur la scène et nous voilà prêts à tester les principales méthodes et propriétés1) des objets de type MovieClip.

Et puisque je vient de lâcher le mot, ne confondez pas le type MovieClip, qui est le nom de la classe que nous allons de fait manipuler avec le “type” Clip que vous choisissez dans l'environnement auteur. Le “type” Clip qui apparait dans le panneau Propriétés ou dans la bibliothèque, n'existe pas pour AS3, pas plus que le type Bouton ou Graphique2) ;)


Manipuler la tête de lecture

Les méthodes caractéristiques de la classe MovieClip vous les connaissez certainement - au moins de réputation - ce sont celles qui permettent de manipuler la tête de lecture, et quand je disais tout à l'heure un peu vite que la caractéristique principale des MovieClip c'est d'être animés, en parler correct c'est : d'avoir plusieurs images3) et une tête de lecture… qu'on peut piloter, donc.

stop, play, gotoAndStop et gotoAndPlay

Ça, on a déjà vu et même pris de l'avance avec l'exercice du skieur.

Je résume tout de même : stop arrête la tête de lecture du clip considéré là ou elle se trouve ; play démarre la lecture depuis l'image courante (actuellement affichée).

Par exemple pour arrêter la course du ballon en cliquant dessus…

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

Deux possibilités :

• Soit vous nommez l'instance (disons leBallon pour faire original) et, sur le calque dédié au code du scénario principal4), vous lui associez un écouteur :

leBallon.addEventListener(MouseEvent.MOUSE_DOWN,qdClicBallon);
 
function qdClicBallon(me:MouseEvent):void {
	me.currentTarget.stop();
}



• Soit vous décidez d'écrire ce bout de code dans le clip lui même image 1 d'un calque dédié.

this.addEventListener(MouseEvent.MOUSE_DOWN,explose);
 
function explose(me:MouseEvent):void {
	this.stop();
}


Ici, avec un seul clip, c'est la première option la meilleure : on a tout le code sous les yeux en ouvrant le .fla, mais vous verrez que quelquefois l'option 'code dans le clip' se révèle bien utile



gotoAndStop envoie la tête de lecture à une image considérée, sans lire les autres, la tête de lecture “saute” jusqu'à l'image et y reste ; gotoAndPlay lit depuis l'image en question.

On précise le numéro d'image entre parenthèses comme illustré là bas, mais on peut aussi préciser une étiquette d'image en passant une chaîne.

Les étiquettes d'image

Pour poser une étiquette d'image il suffit de sélectionner une image clé5) dans le scénario du clip considéré et de saisir un nom dans le champ Nom du panneau Propriétés.


Il vous suffira par la suite de “passer” ce nom, entre guillemets, à un gotoAnd… pour y envoyer la tête de lecture :

leClip.gotoAnStop("uneEtiquette");
//ou
//leClip.gotoAnPlay("uneEtiquette");



Par exemple, sauriez vous faire un ballon qui explose quand on clique dessus ?

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


Ce n'est qu'une ruse de construction et du code qu'on connait, n'allez pas chercher midi à quatorze heure…
Jusqu'alors on avait un clip (Mv_BallonVole) qui animait un graphique nommé ballon (instance de Gr_Ballon) sur une guide mouvement. Il vous suffit de remplacer cette instance (bouton Permuter du panneau Propriétés) par un clip présentant image 1 le visuel du ballon et, plus loin, une animation figurant l'explosion à partir d'une image quelconque que vous aurez pris soin de repérer à l'aide d'une étiquette d'image (“paf”, par exemple).
Un clic sur l'instance de Mv_BallonVole, en arrête la tête de lecture et envoie celle du clip contenu lire depuis l'étiquette “explose” (gotoAndPlay).


Prenez soin, si vous avez procédé par permutation, de régler le type sur “Clip” dans le panneau Propriétés.
Toujours les deux mêmes possibilités :

Sur la première image de Mv_BallonVole :

this.addEventListener(MouseEvent.MOUSE_DOWN,explose);
 
function explose(me:MouseEvent):void {
	this.stop();
	this.removeEventListener(MouseEvent.MOUSE_DOWN,explose);// plus besoin de l'écouteur on le supprime
	this.ballon.gotoAndPlay("paf");
}


Sur la première image du scénario principal :

leBallon.addEventListener(MouseEvent.MOUSE_DOWN,explose);
 
function explose(me:MouseEvent):void {
	me.currentTarget.stop();
	me.currentTarget.removeEventListener(MouseEvent.MOUSE_DOWN,explose);// plus besoin de l'écouteur on le supprime
	me.currentTarget.ballon.gotoAndPlay("paf");
}


nextFrame et prevFrame

Comme leur nom l'indique, nextFrame et prevFrame, permettent d'envoyer la tête de lecture, respectivement, image suivante ou image précédente. On pourrait par exemple fabriquer cette toute petite chose (aussi, ça nous permettra de tester d'autres propriétés par la suite).
L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
Il s'agit d'un bête clip avec une poignée d'images clés, sur chacune d'elle une illustration différente. Quand on clique, l'image suivante est affichée (la tête de lecture se déplace vers l'avant), si on clique avec la touche majuscule enfoncée c'est l'image précédente qui est affichée (tête de lecture recule d'une image).

C'est une bonne occasion de réviser les propriétés du paramètre de la fonction de rappel ainsi que l'emploi de la structure if ;)

Notez qu'aucune erreur ne se produit si on invoque nextFrame sur la dernière image, ou prevFrame sur la première… Rien ne se passe, c'est tout.


Et pour ceux qui se demandent comment faire changer le pointeur en main, tant pis si ce n'est pas le chapitre je le dis quand même : c'est la propriété buttonMode valorisée à true qui produit ça.

demo.buttonMode=true;



Je vous laisse trouver, et si vous séchez vous trouverez le code à l'occasion du chapitre suivant.

Les propriétés bien utiles de MovieClip

Puisqu'on peut déplacer la tête lecture sur des images de son choix selon leur numéro ou leur nom d'étiquette, voici une poignée de propriétés auxquelles vous aurez souvent recours dès qu'il s'agira de “se” déplacer sur un scénario.

currentFrame et totalFrame

Ces deux propriétés renvoient un int qui vaut pour
currentFrame le numéro de l'image en cours de lecture, celle sur laquelle se trouve la tête de lecture à l'instant considéré,
totalFrame le nombre d'images du clip en question.

Vous pouvez tester en ajoutant deux traces au code que vous venez d'écrire à l'occasion de l'exercice du dessus :

demo.stop();
 
demo.addEventListener(MouseEvent.CLICK,qdClic);
demo.buttonMode = true; // pointeur en forme de main au survol
 
function qdClic(me:MouseEvent) {
	if (me.shiftKey) { // touche majuscule du clavier enfoncée
		me.currentTarget.prevFrame();// reculer d'une image
	} else {
		me.currentTarget.nextFrame();// avancer d'une image
	}
	trace("image courante : "+me.currentTarget.currentFrame);
	trace("nombre d'images du clip : "+me.currentTarget.totalFrames);
}


Exercices

Défiler et boucler

Histoire d'illustrer l'utilisation de ces deux propriétés, je vous propose la consigne suivante avec le toujours même clip aux bestioles (ou une autre instance, si ça vous arrange) : quand on clique, on passe à l'image suivante et on revient à la première après la dernière. En gros, ça boucle.
Bien sûr le code doit fonctionner quelque soit le nombre d'images du clip sans qu'on ait à le modifier, et pour corser la chose - sans quoi c'est trop facile :mrgreen:- j'ajoute la contrainte de ne pas utiliser de if.


En fait il s'agit d'une seule ligne un peu rusée, mais vous avez déjà rencontré tout ce qu'il faut pour faire ;)

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

Indices :
• Il y a peut-être un piège… Ce n'est pas parce qu'on vient de voir nextFrame et prevFrame qu'il faut forcément vous jeter dessus ^^
• Parmi les opérateurs mathématiques il y en a un qu'on a tort de négliger.

Tout petit jeu

L"extension Adobe Flash Plugin est nécessaire pour afficher ce contenu.
Ici ce swf illustre la consigne toute entière : vous savez faire en sorte que la partie démarre ou reprenne via majuscule-clic.

Euhhh… nan, il ne se passe rien quand on a gagné… C'est prématuré pour compter les points :(


C'est une cas de figure où on peut trouver préférable d'écrire le code “dans” le symbole, plutôt qu'associer un écouteur à chaque instance.

this.addEventListener(MouseEvent.MOUSE_DOWN,explose);
 
function explose(me:MouseEvent):void {
	this.stop();
	this.removeEventListener(MouseEvent.MOUSE_DOWN,explose);
	ballon.gotoAndPlay("paf");
}

currentFrameLabel et currentLabel

En ce qui concerne ces deux propriétés, je ne peux que vous renvoyer à la doc et attirer votre attention sur le fait qu'elles ne sont disponibles que pour lecteurs 10 et supérieurs.

Si l'explication vous reste confuse faites le test suivant :
image 1 : stop()
image 2 : une étiquette : “etiquette image 2”
image 5 : une étiquette : “etiquette image 5”

un bouton sur la scène et ce code associé :

bt.addEventListener(MouseEvent.CLICK,qdClic);
 
function qdClic(me:MouseEvent) {
	nextFrame();
	trace("currentFrame :           "+this.currentFrame);
	trace("currentFrameLabel :      "+this.currentFrameLabel);
	trace("currentFrame :           "+this.currentLabel);
	trace("---");
}



currentFrame :           2
currentFrameLabel :      etiquette image 2
currentFrame :           etiquette image 2
---
currentFrame :           3
currentFrameLabel :      null
currentFrame :           etiquette image 2
---
currentFrame :           4
currentFrameLabel :      null
currentFrame :           etiquette image 2
---
currentFrame :           5
currentFrameLabel :      etiquette image 5
currentFrame :           etiquette image 5
---
currentFrame :           6
currentFrameLabel :      null
currentFrame :           etiquette image 5
---




Notez qu'elles sont en lecture seule, ce qui implique que vous ne pouvez pas définir des étiquettes d'image dynamiquement (à la volée)

Retrouver une instance par son nom : getChildByName

Vous le savez, quand on veut (s') adresser (à) un clip posé sur l'animation, on utilise le nom de l'instance tout bonnement (leClip.play(); par exemple).
La question qui se pose maintenant c'est comment faire quand on dispose d'une chaine de caractère, pour, par exemple, piloter ballon1 ou ballon2 en reconstituant le nom depuis une variable qui vaudrait le suffixe (le chiffre).

Il ne vous viendrait pas à l'esprit d'écrire :

var suffixe:int=1
var leBallon:String="ballon"+suffixe
leBallon.play(); // Aïe !! depuis quand la classe String expose-t-elle une méthode play ? O.O

C'est la méthode getChildByName qui renvoie l'objet d'affichage (DisplayObject) correspondant à une chaîne.

var suffixe:int=1
trace(getChildByName("ballon"+suffixe))
trace(getChildByName("ballon"+suffixe).name)
[object Mv_BallonVole]
ballon1


Notez que s'il n'existe pas d'instance du nom considéré getChildByName renvoie null


Erreurs 1118 et 1061

Je viens d'illustrer la méthode getChildByName dans un trace et en utilisant la propriété name, si de votre côté vous vous y êtes essayé avec un play ou un stop vous voilà confronté à l'erreur 1118 ou 1061, très célèbres sur le forum ;)

C'est le moment de tirer l'embrouille au clair.

Voilà ce qu'on obtient si on a une instance nommée leBallon et qu'on a le front d'écrire :

getChildByName("leBallon").play();
1061: Appel à la méthode play peut-être non définie, via la référence de type static flash.display:DisplayObject



Si vous essayez de passer par une variable, c'est pas mieux :

var b:MovieClip= getChildByName("leBallon");
1118: Contrainte implicite d'une valeur du type statique flash.display:DisplayObject vers un type peut-être sans rapport flash.display:MovieClip




Chaque fois il est question de DisplayObject… De fait si vous consultez la doc, vous constatez que getChildByName renvoie du DisplayObject.



“Euhh… oui et alors”, grommèle le Ronchon de service.

Eh bien, c'est là qu'il devient nécessaire de comprendre l'arbre d'héritage des classes d'affichage.

Reprenons :

Quand on code en AS3 on utilise des objets - puisque tout est Objet - et il existe des objets de genre différent : clips, boutons, images bitmap, sons…
On sait que tous les objets d'un même genre s'utilisent pareil. Je veux dire, on leur applique les mêmes méthodes ou propriétés et - partageant les mêmes caractéristiques et compétences6) - on les classe dans la même catégorie.

Eh bien voilà, le mot est lâché, les objets qui ont le même “mode d'emploi”, sont classés dans la même catégorie qu'on appelle classe.

Attention, une classe c'est plus qu'une catégorie, qu'une étiquette pour identifier un objet, c'est aussi ce qui permet de fabriquer les objets en question. Une classe c'est à la fois un “genre” (on dit type vous vous souvenez) et une usine, une fabrique, un moule…

Les objets de même type sont issus de la même classe (au sens où ils sont fabriqués par la même classe).

La classe d'un objet c'est à la fois la catégorie dans laquelle le “ranger” et le moule qui permet de le fabriquer.


Ce qui est pratique, c'est que les classes héritent les unes des autres et voilà comment ça peut se comprendre vite fait pour ce qui nous intéresse (la POO c'est l'objet d'un autre tuto) :

Ça fonctionne un peu comme dans la vraie vie : il y a des parents et des enfants ; en fait des mères et des filles - puisqu'on parle de classes - et les filles héritent de leur mère, génétiquement pour les humains, “codesquement” pour les classes.
Comme dans la vie biologique les filles héritent de leur mère certaines caractéristiques et compétences et y ajoutent des facultés propres. Ma fille, par exemple, a hérité de mon caractère et de la couleur de mes yeux, mais en plus elle est sportive (caractéristique qui me fait parfaitement défaut ;)). En AS3 c'est pareil si ce n'est qu'il est question de propriétés et de méthodes.

L'arbre d'héritage des classes d'affichage

Les classes qui nous intéressent ici, ce sont les classes des objets affichables7).

D'un point de vue AS3 voilà comment se présente l'arbre généalogique d'héritage des classes d'affichage :



Attention métonymie
Souvent pour aller vite on opère un glissement sémantique qui nous fait parler de l'objet issu d'une classe en utilisant le nom de la classe elle même. Comme lorsqu'on dit boire un verre ou manger un cornet de frites. Ce n'est pas le verre qu'on boit (mâche ?:mrgreen:) mais bien son contenu, de même que vous n'avalez pas le carton du cornet de frites mais les frites elles mêmes. C'est ce que je fais ici pour les besoins de la métaphore, quand je dis qu'un objet hérite certaines de ses propriétés de son parent, c'est pour aller vite, c'est bien la classe
dont il est issu qui hérite de sa classe mère.



• L'aïeule c'est DisplayObject, qui est la classe dont héritent tous les objets affichables, qu'il s'agisse d'une image (Bitmap), d'un objet de dessin (Shape), d'instances de symboles (Sprite, SimpleButton, MovieClip), ou même de chargeurs d'images externes (Loader), de vidéos (Video) ou encore de champs texte (TextField).
Si vous consultez la doc vous trouverez toutes les méthodes et propriétés qui s'appliquent aux objets d'affichage quels qu'ils soient. name, par exemple, ou encore x et y8)

• Ensuite il y a les enfants de DisplayObject, au nombre des quels les objets interactifs (InteractiveObject), qui non contents d'être affichables, d'avoir des coordonnées et tout ce qu'on sait, permettent l'interaction. Dit autrement, ils diffusent les célèbres “événements souris” : MouseEvent

• Les enfants des objets interactifs sont les boutons, les champ texte, et les objets d'affichage pouvant en contenir d'autres (DisplayObjectContainer).

• Héritant de DisplayObjectContainer, vous trouvez la classe Loader (pour charger des fichiers image), la classe Sprite (une seule image donc pas de scénario) et la classe Stage (la scène, qui pour le coup est un conteneur).

• Enfin, tout en bas de l'arbre d'héritage, l'objet le plus aboutis de l'évolution : le (fameux) MovieClip qui est donc : un objet d'affichage avec toutes ses méthodes et propriétés, interactif, pouvant en contenir d'autres, et équipé d'un scénario.

Pour reprendre ma métaphore familiale, ça dit de qui l'enfant en question “tient” ses caractéristiques (il a le don de la musique de sa grand mère, la main verte de sa bisaïeule mais ses talents de cuisiniers il ne les doit qu'à lui).


cliquer pour grossir

Certaines classes (type d'objets) ne sont pas instanciables, comprendre elles ne peuvent pas générer un objet (via le mot clé new, on y arrive très bientôt), je ne vais pas pouvoir fabriquer un objet de type DisplayObjet “tout court”. Ces classes n'existent que pour transmettre à leur descendance les méthodes et propriétés qui leurs seront communes.


Cet arbre d'héritage explique les parenthèses qu'on trouve dans le volet latéral du panneau action à côté de certaines méthodes ou propriétés. Elles précisent pour chacune, la classe “dont elle proviennent”.

Ici j'ai développé MovieClip, depuis flash/DisplayObject :



Oui, bon, ronchonne le toujours même, et quel rapport avec l'erreur ?

J'y viens :

Une dernière chose à savoir en ce qui concerne l'héritage, c'est que puisque les enfants savent faire tout comme leurs parent et mieux, partout où on attend la mère on peut envoyer la fille9) (puisqu'elle sait assurément faire la même chose que sa mère).

Quand on dit de la méthode getChildByName qu'elle renvoie un objet de type DisplayObject, il faut comprendre “au minimum”.
Dans notre exemple, on reçoit un clip, c'est bien un DisplayObject (par ascendance), mais on tente d'utiliser la méthode play, qui n'est pas une méthode de la classe en question, le compilateur lui, n'en sait rien si c'est un clip ou un loader ou un TextField ou n'importe quel autre objet d'affichage, et il râle que la méthode play n'existe pas (peut-être non définie), via la la classe DisplayObject, normal.

Oui mais voilà, nous, dans ce contexte, parce que c'est nous humains qui programmons, on le sait que “leBallon” c'est un clip. On en est sûr, là, voilà !
On va donc “rassurer Flash”, lui dire “écoute gars, je suis sûre de mon coup, cet objet que je reçois est un MovieClip”.
En langage Objet on dit qu'on transtype (par delà le type) et on s'y prend comme suit :

MovieClip(getChildByName("leBallon")).play();
// Ou :
var ballon:MovieClip=MovieClip(getChildByName("leBallon"));
ballon.play();



Et du coup vous comprenez pourquoi l'exemple que j'avais pris avec la propriété name fonctionnait, lui. Eh oui, name est une propriété de la classe DisplayObject10).


Exercice

Maintenant que vous savez piloter la tête de lecture d'une instance dont vous connaissez le nom, vous pouvez sans doute, armés de vos récentes connaissances sur les champs texte, lâcher le ballon de votre choix…

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

Remarquez qu'on peut saisir la couleur du ballon en majuscule, minuscule, voire avec l'initiale seulement en majuscule, ou un peu comme on veut (rOuGe, ça marche aussi).





Conclusion (provisoire)

Vous l'avez constaté : il existe encore nombre de méthodes et propriétés, dont certaines absolument primordiales. On va les voir, mais pas tout de suite.
Ce n'est pas que je tienne à ménager un suspens insoutenable ;) c'est que pour en comprendre au mieux l'intérêt et la mise en œuvre on va avoir besoin de quelques billes supplémentaires, à commencer par les structures de contrôle répétitives (les boucles).

Et c'est par là [lien à venir] que ça se passe… A tout de suite, donc ! :)

1) tout ce qu'on peut en faire (méthodes) et tout ce qu'on peut en savoir (propriétés)
2) Graphics oui, mais c'est autre chose
3) potentiellement
4) image qui contient le clip, bien sûr…
5) F6 au besoin
6) propriétés, méthodes
7) qu'on peut afficher, donc voir
8) effectivement, si un truc peut être affiché, il faut bien qu'on puisse en préciser coordonnées…
9) celle-là je l'ai volée à T.Imbert :)
10) hé hé c'est que je m'étais appliquée de l'exemple ;)