Classe associée à un symbole de bibliothèque
Introduction
Classe de base (#1)
Classe de base (#2)
Héritage et surcharge (#1)
Héritage et surcharge (#2)
Diffuser des événements
Classe liée
Classe de document
Classe externe : une visionneuse (#1)
Classe externe : une visionneuse (#2)
Classe externe : méthodes statiques
Classe de base (#1)
Nous allons commencer notre randonnée découverte avec la classe de base, c'est de mon point de vue la plus utile des deux, même si c'est souvent à tort la classe liée qui est donnée en exemple.
On écrit ce type de classe, je le rappelle, quand on veut étendre (enrichir) les fonctionnalités d'un clip donc lui ajouter des méthodes et/ou des propriétés et/ou des événements.
Fabriquer le clip
Je vous propose, pour nous simplifier la vie dans un premier temps, de dédier un dossier (répertoire) à nos essais et d'y enregistrer un fichier .fla (DemoClasseBase.fla
chez moi).
Puisqu'on est dans le cadre 'étendre les capacités d'un symbole Clip', fabriquons-en un (un simple rectangle suffira).
Dans l'idée d'associer à ce symbole une future classe, avant de valider, il faut prendre soin de cocher la case exporter pour ActionScript. Si vous avez procédé par conversion d'une forme, appelez la fenêtre propriétés d'un clic droit dans la bibliothèque.
Que se passe-t-il quand on coche la fameuse case ?
D'abord le champ Classe
est automatiquement rempli du nom du symbole et le champ Classe de base
contient flash.display.MovieClip
Ensuite quand on valide un avertissement surgit (sauf à ce que vous ayez coché depuis longtemps la case Ne plus afficher) :
Une définition sera générée automatiquement dans le fichier swf lors de l'exportation… Diantre !
Une définition de quoi ?
De classe.
Hé oui en cochant cette brave case, une classe se fabrique dans l'arrière boutique de flash sans que nous en sachions trop rien.
Et cette classe (Mv_Truc
dans l'exemple) a pour classe de base flash.display.MovieClip.
Comprendre : la classe Mv_Truc
sait faire tout ce que sait faire un MovieClip (méthodes : stop, play, nextFrame…) dispose de toutes ses caractéristiques (propriétés : currentFrame, enabled…), diffuse les mêmes événements (removed…), et en plus a ses propres bidules ; des formes, des champs texte, des animations et autres clips, graphiques ou boutons, voire même du code. Je dis 'bidules', vous m'en excuserez : sur ce coup là le parler juste ne ferait que semer l'embrouille
Vite dit : notre classe Mv_Truc (avec son malheureux rectangle) c'est une classe MovieClip en mieux, elle sait faire tout ce que sait faire un MovieClip et en plus affiche un rectangle. On dit qu'elle étend (les capacités) de la classe MovieClip. (je me répète ? )
On dit aussi que Mv_Truc hérite de MovieClip ou encore la classe MovieClip est la classe mère de Mv_Truc. Un peu comme ronchon qui a hérité son caractère de sa mère et y a ajouté son propre goût pour l'informatique.
Ce qu'on se propose de faire, c'est fabriquer une classe à nous qui étendra la classe MovieClip et sera elle même étendue par Mv_Truc. Ainsi toutes les instances de Mv_Truc seront elles douées des mêmes capacités/caractéristiques que les MovieClip, plus celles de notre classe, plus celles propres à Mv_Truc.
Fabriquons donc cette classe !
(Tel que nous l'abandonnons -provisoirement- le .fla dispose seulement d'un symbole dans sa bibliothèque et la scène est vide)
Fabriquer la classe
Créer le fichier
Créons un fichier .as dans le même répertoire que le fla (j'y tiens) il portera le nom de la classe (chez moi DemoBase.as).
Et voilà : l'angoisse de la page blanche !
Le code
Bon… Le début c'est toujours pareil, ça ne se comprend pas ça s'apprend c'est comme ça : toute classe doit être déclarée au sein d'un paquetage - pour des questions d'organisation mais on y reviendra - un paquetage ça se dit package en anglais alors zou !
package { }
Ça c'est fait.
Ensuite il s'agit d'y déclarer une classe qui s'appelle DemoBase et qui étend la classe MovieClip (je vous ai suffisamment bassinés avec le verbe pour qu'on n'y revienne pas). En anglais/AS ça s'écrit comme ça :
package { public class DemoBase extends MovieClip { } }
Traduit : voici une classe publique (visible et utilisable par tous) qui s'appelle DemoBase qui étend la classe MovieClip.
Attention à bien écrire class (sans majuscule) et non Class
Ce à quoi il va falloir être vigilant à partir de maintenant, c'est à l'import des classes (les autres). Aussi longtemps que l'on écrit dans l'IDE de flash on n'a pas à s'en préoccuper (ou rarement), les classes les plus fréquemment utilisées sont importées par défaut. Quand on écrit image 1 de la scène stop()
, on utilise bien une méthode de MovieClip mais on ne se préoccupe pas de demander à flash de nous mettre le gros outil MovieClip à disposition, c'est fait.
Quand on écrit une classe, plus rien d'implicite, il faut se charger de tout.
Qu'à cela ne tienne, importer la classe MovieClip, c'est une pauvre ligne qu'on ajoute dans la foulée avant la déclaration de classe.
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { } }
Ayé ! On a une classe
Qui ne fait rien, qui n'a aucune caractéristique propre, et qui est aussi muette qu'un poisson
Ajouter une méthode
On va donc lui ajouter une méthode - qu'on ait quelque chose à tester - disons test
, au hasard.
Quand nous aurons associé la classe à un clip, nous pourrons appliquer la méthode test
à n'importe quelle instance de ce clip, avec la syntaxe qu'on connait par cœur :
// le fla monClip.test();
La méthode test
n'est rien d'autre qu'une fonction qui doit être déclarée dans la classe et accessible depuis l'extérieur, donc publique.
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { public function test():void { trace("je passe dans test"); } } }
Et voilà, la classe DemoBase sait faire tout ce que sait faire un objet de classe MovieClip, et en plus sait écrire “je passe dans test” dans la fenêtre de sortie quand on utilise sa méthode test
.
Vérifions…
Associer la classe et le symbole
Pour vérifier, il faut associer cette classe DemoBase au symbole qui s'ennuie dans la bibliothèque du .fla.
Ne vous y trompez pas : tout à l'heure on n'a rien associé. On a regardé ce qui se passait quand on coche la case Exporter pour ActionScript et conclu qu'il nous fallait une classe à glisser entre MovieClip dont le clip hérite naturellement et lui même pour l'enrichir des fonctionnalités de la dite classe.
Retour au fla, donc → propriétés du clip → dans le champ classe de base on saisit DemoBase (sans l'extension le compilateur s'en doute).
Notez le crayon à droite, si vous cliquez dessus et que vous avez ôté les moufles (pas de faute de frappe) vous devez être dirigé sur le code as, sinon il crie :
Validez, posez une instance du clip sur la scène, nommez la.
Dans la fenêtre action appliquez la toute fraiche méthode test à l'instance (leClip.test()
), exécutez… Parfait.
je passe dans test
Ça ne surprend personne : quand on pose une instance d'un clip quelconque sur la scène et qu'on utilise la méthode play
, hop ça marche ! Je veux dire ça lit…
Et bien pareil pour une instance de classe personnelle, on la pose sur la scène, elle dispose d'une méthode supplémentaire -test
- qu'on utilise et hop ça marche ! Enfin, ça trace…
Juste pour jouer, ajoutons un bouton à la scène :
btMarche.addEventListener(MouseEvent.CLICK,jeTeste) function jeTeste (me:MouseEvent) { leClip.test() }
Une méthode marche
Ronchon qui se sent moins seul d'un coup émerge de derrière on écran.
Ok…
Je vous propose de transformer la méthode test qui ne sert à rien en méthode marche qui fera avancer le clip d'autant de pixels que passés en paramètre (comme là ↓).
Si vous tracez this
et this.name
dans la nouvelle méthode marche
, vous constatez qu'il s'agit bien d'un clip de type Mv_Truc
et qu'il porte le nom que vous lui avez donné :
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { public function marche():void { trace(this); trace(this.name); } } }
[object Mv_Truc] leClip
… du coup ajouter un paramètre à la méthode marche
et modifier la propriété x (ou y ou les deux, zetes grands), vous n'avez besoin de personne…
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { public function marche(pX:int=10):void { x+=pX; } } }
Comme on est des malins on a défini une valeur par défaut pour le paramètre : pX:int=10
. Ça permet d'utiliser la méthode sans argument et sans déclencher d'erreur…
Pas plus, et vous pouvez faire avancer différentes instances à des vitesses différentes :
btMarche.addEventListener(MouseEvent.CLICK,marche) function marche (me:MouseEvent) { leClip.marche(30) leClip2.marche() }
Ne confondez pas
Ah… Les raisons de l'agitation de Ronchon ne sont pas celles que je croyais.
“Je le savais bien que c'était pareil !” triomphe-t-il.
Il l'a vu partout : on aurait pu aussi bien renseigner le champ Classe du panneau de propriétés. Il vient de vérifier : c'est pareil, ça marche aussi !
Effectivement, ça marche aussi, mais ce n'est pas pareil
Pour preuve : suivons l'idée de Ronchon et renseignons le champ Classe du panneau de propriétés comme reproduit ci-dessus. On dispose d'un rectangle qu'on peut instancier autant qu'on veut et chacune des instances peut “marcher”.
Parfait, ça nous plait bien et on veut la même chose non pas seulement pour un rectangle rouge, mais aussi pour une pastille jaune ou un éléphant rose…
On crée un nouveau symbole avec tiens, une pastille jaune, et puis la routine : appeler ses propriétés, cocher la case exporter pour ActionScript, saisir DemoClasse
dans le champ Classe… Valider… Et on se fait crier
On l'a vu (ici) : cocher la case Exporter pour ActionScript génère automatiquement une définition dans le fichier swf lors de l'exportation.
Maintenant qu'on sait comment se construit définit une classe, on peut se représenter ce qui se passe dans l'arrière boutique : une classe que nous aurions écrite comme suit a été générée :
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { } }
Mais comme nous en avons nous même défini une, c'est cette dernière qui est prise en considération.
Tant que nous ne l'avions associée qu'au clip Mv_Truc, DemoBase héritait de MovieClip et en plus affichait un rectangle. Si nous recommençons avec un autre clip (Mv_Pastille par exemple) Alors cette même classe devra hériter de MovieClip et en plus afficher un cercle… Ben ?! 'Faut savoir !! Un rectangle ou un cercle ?!
Alors que si nous associons DemoBase à la classe de base, la définition de Mv_Truc est celle-ci :
package { import flash.display.MovieClip; public class Mv_Truc extends DemoBase { } }
Et rien ne nous empêche d'avoir une
public class Mv_Pastille extends DemoBase {...}
C'est ce que nous avions compris depuis le début
function marche(me:MouseEvent) { leClip.marche(30); leClip2.marche(); laPastille.marche(20) }
La fonction constructeur
J'en vois un qui s'impatiente et voudrait bien du concret. On y vient, juste encore un peu de théorie, pour parler de la fonction constructeur et on aura tout ce qu'il faut pour s'y attaquer - au concret.
Le constructeur, donc, c'est une fonction particulière qui est automatiquement invoquée quand on crée une instance de la classe en question.
Elle doit avoir le nom de la classe et être publique.
package { import flash.display.MovieClip; public class DemoBase extends MovieClip { public function DemoBase():void { trace("constructeur DemoBase "+ this.name); } // ... suite ... } }
Enregistrez et testez : la fenêtre sortie affiche un trace par clip présent sur la scène. En effet dans l'arrière cuisine de flash, le fait que nous ayons posé un clip sur la scène a été traduit par ce que nous aurions écrit :
var clip:Mv_Truc= new Mv_Truc() clip.name="leClip" // clip.x= ... // etc. addChild(clip)
A la ligne var clip:Mv_Truc= new Mv_Truc()
une instance est crée, le constructeur invoqué.
C'est donc dans la fonction constructeur qu'auront lieu les initialisations et tout ce qui doit se faire quoiqu'il arrive…
Mise en œuvre
Maintenant qu'on a les idées bien claires, et avant d'aller plus loin, voyons ce qu'on peut faire de qui a été vu jusque là.
Imaginons qu'on soit en situation de fabriquer un nombre certain de clips qui auront tous en commun un clip contenant une image (photo
) masqué par un autre clip (masque
), le masque étant affligé d'un filtre flou. Les images peuvent être animées ou pas et les masques de formes différentes.
Ça nous oblige à chaque fois à trois lignes de codes, toujours les mêmes, placées sur la première image du clip en question… ce qui défrise Ronchon, à l'initiative de qui nous sommes là (je tiens à le rappeler, toutes doléances devant lui être directement adressées )
Le comment du pourquoi est détaillé ici
Les trois lignes donc on les connait :
masque.filters=[new BlurFilter(_flouX,_flouY,BitmapFilterQuality.HIGH)]; photo.mask=masque; photo.cacheAsBitmap=true;
En assumant le fait qu'il existe un clip photo et un clip masque (pour le masque).
Donc tous les clip “sauront” appliquer masque
à photo
et auront leurs bidules propres (des photos spécifiques entre autres). On est en plein dans le cadre de la classe. Classe de base donc, puisque plusieurs clips différents devront en hériter.
Cette classe ne dispose d'aucune méthode ou propriété (pour l'instant) mais quoi qu'il arrive elle appliquera un filtre au clip masque, et le reste…
Donc ça s'écrit dans le constructeur.
Parfait vous savez tout ce qu'il faut pour vous débrouiller tous seuls, si ce n'est les classes à importer. Pour cette fois je vous les donne :
import flash.display.MovieClip; import flash.filters.BitmapFilterQuality; import flash.filters.BlurFilter;
Ensuite vous n'aurez plus qu'à construire autant de clips que vous voudrez, les associer à cette classe et sans plus une ligne de code vous obtiendrez des choses comme ça. En mieux… N'est-ce pas Ronchon ?
[illustr]
Allez ! Je vous laisse faire, ma série télé commence
On se retrouve là pour la suite (et le corrigé).
