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 externe : une visionneuse (#1)
Nous voici bientôt arrivés au terme de la randonnée au pays de Poo, et ce nouveau chapitre va être une excellente excuse à mettre en œuvre tout ce qui a été vu jusqu'alors.
L'idée c'est de construire une classe visionneuse ou diaporama, ce qui revient au même…
Justement peut-être nos rangs sont ils grossis de quelques nouveaux arrivés via un moteur de recherche. Bienvenue à vous, sachez seulement que je considère comme acquis (ou en voie d'acquisition, on s'énerve pas) les points précédemment développés.
• Ce qu'est une classe, comment ça se construit et les syntaxes dédiées
• Comment définir des méthodes, un constructeur ou des accesseurs
Je vous invite à vous reporter aux pages précédentes pour ces différents points.
Il vous faut aussi savoir appliquer dynamiquement un masque à un clip, et lui appliquer un flou.
On utilisera les classes loader et loaderInfo pour charger les images, mais ça n'a pas à voire directement avec la visionneuse, vous pouvez vous contenter d'admettre les quelques lignes concernées si d'aventure vous n'en êtes pas familiers.
intro
Ça, c'est ce qu'on imagine obtenir à terme : des visuels qui s'enchainent avec une transition animée via un masque selon le principe illustré là. Vous le constatez, les images sont affichées en boucle, mais la première ne l'est qu'une fois.
Les boutons qui changent le sens de défilement ne font pas partie de la classe mais du fichier de mise en œuvre qui permet d'utiliser l'objet Visionneuse, même chose pour la légende.
La classe ne fait rien d'autre, donc, qu'afficher des visuels dans un clip vide et leur appliquer un masque. On ne va pas créer un symbole de bibliothèque vide juste pour lui associer une classe… On pourrait, mais 'faut rien exagérer non plus, il suffit que la classe s'en charge. Nous pouvons donc rêver d'une classe qu'on utiliserait comme suit :
// .fla visio=new Visionneuse(); visio.addEventListener(MouseEvent.CLICK,marcheArret); addChild(visio); [...]
Elle mettrait à notre disposition une méthode marche, une méthode arrêt (ainsi que diverses petites choses qu'on inventera en cours de route), et n'aurait besoin pour fonctionner que d'un clip (animation de transition) et d'une série de visuels qu'on lui passerait sous forme d'un tableau. Du coup on l'initialiserait à la construction comme suit :
var visio:Visionneuse=new Visionneuse(tabPhotos,leMasque);
Ce qui est sympa avec le code, c'est que du rêve à la réalité il n'y a qu'un clavier, dont je vous propose de vous saisir sans plus attendre. C'est parti pour la visionneuse !
Côté .fla
Il nous faudra un fichier .fla de mise en œuvre et un fichier .as pour la classe, les deux étant considérés comme enregistrés dans le même répertoire.
Créons le fla pour commencer.
Charger les images
On sera amenés à utiliser la classe Visionneuse soit avec des visuels sous forme de symboles de la bibliothèque, soit sous forme de fichiers externes. Alors pour le plaisir de frimer qu'on sait tout faire, je vous propose de faire un mixte : charger une première image qui sera un symbole de bibli (la page de garde), les autres seront des images externes.
Mon point de vue étant qu'il vaut mieux écrire cinq fois dix lignes en les testant au fur et à mesure, qu'écrire une fois cinquante lignes qui plantent à l'exé (et qu'on sait même pas où, et qu'on se retrouve à poster deux écrans de code dans le forum sur le mode “au secours ça marche pô chépa pourquoi…” ) on va procéder par étapes en vérifiant régulièrement que “jusque là, ça va…”
Avant même d'attaquer la classe, occupons nous donc de fabriquer un tableau qui contiendra les visuels : un symbole de bibliothèque et des photos externes.
Je vous laisse fabriquer le clip pour le premier visuel, pensez à cocher la case exporter pour actionScript (pour en créer une instance dynamiquement), de mon côté je le nomme Mv_Photo0
.
Charger les fichiers et fabriquer le tableau
On considère ici des images dans le même répertoire que les deux fichiers .fla et .as, nommées P1.jpg, P2.jpg, P3.jpg…
// .fla var ldrFichier:Loader; var ldrInfo:LoaderInfo; var tabPhotos:Array=new Array(); var nbPhotos:int=3; var visio:VisioPazapa; var visuelDep:Mv_Photo0= new Mv_Photo0(); tabPhotos.push(visuelDep); charge("P1.jpg"); function charge(pNom:String):void { ldrFichier= new Loader(); ldrInfo=ldrFichier.contentLoaderInfo; ldrInfo.addEventListener(Event.COMPLETE, Fini); ldrFichier.load(new URLRequest(pNom)); } function Fini(e:Event) { // remplir le tableau et compter le nb d'éléments var nb:int=tabPhotos.push(e.target.loader); if (nb<=nbPhotos) { // charger le suivant charge("P"+nb+".jpg"); } else { // On a tout trace("prêt à déclencher les hostilités : "+ tabPhotos) } }
prêt à déclencher les hostilités : [object Mv_Photo0],[object Loader],[object Loader],[object Loader]
Fabriquer le masque
La technique mise en œuvre pour la transition c'est une animation, un clip utilisé comme masque pour dévoiler la photo suivante. Vous pouvez réutiliser celui que vous avez construit ici, pensez seulement à supprimer les images après les interpolations qui n'étaient destinées qu'à permettre un temps d'exposition entre deux photos, on va bien sûr se faire une joie de coder une propriété temps_de_pause
La Classe
Préparer la classe et vérifier que "jusque là, ça va".
On a tout ce qu'il faut pour agencer les premières briques de notre gros lego perso. Je vous laisse construire la structure de base de la classe : un constructeur qui trace ses deux paramètres (pTabVisuels
, et pMasque
) et les deux méthodes marche
et arret
.
Ici elle se nomme VisioPazapa
, faites bien comme vous voulez de votre côté.
// .as package { import flash.display.MovieClip; public class VisioPazapa extends MovieClip { public function VisioPazapa(pTabVisuels:Array, pMasque:MovieClip):void { trace("constructeur visio : " + pTabVisuels + "\nmasque : "+pMasque); } public function marche():void { trace("Marche"); } public function arret():void { trace("Arrêt"); } } }
… et on vérifie immédiatement que tout se déroule comme prévu : une fonction nouvelleVisionneuse
(appelée dans fini
) qui crée et ajoute une instance de notre classe toute neuve.
// .fla var ldrFichier:Loader; var ldrInfo:LoaderInfo; var tabPhotos:Array=new Array(); var nbPhotos:int=3; // déclarer un objet VisioPazapa var visio:VisioPazapa; var visuelDep:Mv_Photo0= new Mv_Photo0(); tabPhotos.push(visuelDep); for (var i:int=1; i<=nbPhotos; i++) { ldrFichier= new Loader(); ldrInfo=ldrFichier.contentLoaderInfo; ldrInfo.addEventListener(Event.COMPLETE, fini); ldrFichier.load(new URLRequest("P"+i+".jpg")); } function fini(e:Event) { var nb:int=tabPhotos.push(e.target.loader); if (nb>nbPhotos) { trace("prêt à déclencher les hostilités : " +tabPhotos); // création de la visionneuse nouvelleVisionneuse(); } } // function nouvelleVisionneuse() { // créer un objet Mv_Masque0 var leMasque:Mv_Masque0=new Mv_Masque0(); // nouvelle instance initialisée avec le tableau et le masque visio=new VisioPazapa(tabPhotos,leMasque); // ajouter à la liste d'afichage addChild(visio); }
prêt à déclencher les hostilités : [object Mv_Photo0],[object Loader],[object Loader],[object Loader] constructeur visio : [object Mv_Photo0],[object Loader],[object Loader],[object Loader] masque : [object Mv_Masque0]
Ajouter le masque
Pas très visuel tout ça… Oui on dispose bien de tout l'attirail nécessaire : un clip futur masque et un tableau d'images, mais bon… on en fait quoi ?
Dans un premier temps on ajoute le masque, ensuite on s'occupera des couples de visuels.
Comme on imagine bien qu'on aura besoin du masque et du tableau d'un peu partout dans la classe (pas uniquement depuis le constructeur à l'initialisation), on sort deux globales privées : masque
et tabVisuels
. On applique un flou au masque, on l'ajoute à la liste d'affichage.
import flash.display.MovieClip; import flash.filters.BlurFilter; import flash.filters.BitmapFilterQuality; public class VisioPazapa extends MovieClip { private var tabVisuels:Array; private var masque:MovieClip; public function VisioPazapa(pTabVisuels:Array, pMasque:MovieClip):void { trace("constructeur visio : " + pTabVisuels + "\nmasque : "+pMasque); tabVisuels=pTabVisuels; masque=pMasque; masque.gotoAndStop(2); masque.filters=[new BlurFilter(10,10,BitmapFilterQuality.HIGH)]; addChild(masque); }
Ça c'est fait.
Qu'on prenne soin d'arrêter la lecture du clip masque dès tout de suite ça ne vous surprend pas, en revanche que j'utilise un gotoAndStop(2), là vous vous dites : elle fatigue la malheureuse !…
Et bien non ! Pour l'instant le stop que vous avez probablement écrit convient tout à fait, mais plus tard il risque de nous envoyer droit dans le mur… On y reviendra… (suspens… tada ! )
Afficher les visuels
Le masque c'est fait, il ne reste plus qu'à afficher une paire de visuels, un pour le fond, un autre qui sera dévoilé (masqué par masque
). On va s'en débrouiller dans une fonction chargeVisuels
, appelée dans le constructeur.
public function VisioPazapa(pTabVisuels:Array, pMasque:MovieClip):void { tabVisuels=pTabVisuels; masque=pMasque; masque.gotoAndStop(2); masque.filters=[new BlurFilter(10,10,BitmapFilterQuality.HIGH)]; addChild(masque); // les visuels chargeVisuels() }
La fonction chargeVisuels
C'est le même principe que détaillé ici, je ne recommence pas ^^
private function chargeVisuels():void { var idxTmp:int=idxSup; try { removeChild(photoFond); removeChild(photoRecouvre); } catch (e:Error) { } //au premier passage idxSup = 1 et idxInf = 0; photoRecouvre=tabVisuels[idxSup]; photoFond=tabVisuels[idxInf]; photoRecouvre.mask=_masque; photoRecouvre.cacheAsBitmap=true; addChildAt(photoRecouvre,0); addChildAt(photoFond,0); // incrémenter pour le prochain passage idxSup++; // idxSup vaut 1 si supérieur à numPhotoMax idxSup=idxSup>numPhotoMax?1:idxSup; idxInf=idxTmp; }
Bien sûr, il faut avoir déclaré et valorisé les variables :
private var idxSup:int=1; private var idxInf:int=0; private var numPhotoMax:int; private var photoFond:DisplayObject; private var photoRecouvre:DisplayObject; //[.....] public function VisioPazapa(pTabVisuels:Array, pMasque:MovieClip):void { trace("constructeur visio : " + pTabVisuels + "\nmasque : "+pMasque); NumPhotoMax=pTabVisuels.length-1; //[.....]
… et avoir importé la classe.
import flash.display.DisplayObject;
On devine bien le visuel d'index 1 derrière l'instance de Mv_Photo0
.
La transition
C'est le moment de faire en sorte que les méthodes marche
et arrêt
fassent autre chose que tracer une bête ligne.
public function marche() { masque.play(); } public function arret() { masque.stop(); }
Dans l'absolu, il suffit maintenant d'ajouter un écouteur à visio
et d'écrire une jolie bascule :
function nouvelleVisionneuse() { visio=new VisioPazapa(tabPhotos,leMasque); visio.addEventListener(MouseEvent.CLICK,marcheArret); addChild(visio); } // function marcheArret(me:MouseEvent) { if (visio.enMarche) { visio.arret(); } else { visio.marche(); } }
Râle pas Ronchon ! Non il n'y a pas de propriété enMarche
définie dans la classe, mais il faut bien anticiper : puisqu'il est évident qu'on en aura besoin on considère qu'elle existe et, tout de suite derrière, on file dans la classe l'ajouter d'un couple d'accesseurs comme on sait les faire.
public function set enMarche(pB:Boolean):void { _enMarche=pB; } public function get enMarche():Boolean { return _enMarche; }
Avec la globale :
private var _enMarche:Boolean=false;
Puis on s'occupe de modifier la valeur de cette variable dans les méthodes marche
et arret
:
public function marche(e:Event=null) { trace("marche"); masque.play(); _enMarche=true; } public function arret() { trace("arret"); masque.stop(); _enMarche=false; }
Et là, youpi ! Ça dévoile
Enchainer les images
La belle affaire… Ce qu'on veut c'est qu'à chaque fois que la lecture du masque boucle (revient image 1), un nouveau couple d'image soit chargé…
Il faudrait un petit script image 1… il faudrait ajouter à l'instance masque
, image 1, un script qui appèlerait chargeVisuels
… ! addFrameScript, bien sûr (vous vous souvenez, page précédente ?).
En se souvenant que la première image est numérotée zéro, ça donne :
masque.addFrameScript(0,chargeVisuels);
On ajoute la ligne dans le constructeur.
public function VisioPazapa(pTabVisuels:Array, pMasque:MovieClip):void { NumPhotoMax=pTabVisuels.length-1; tabVisuels=pTabVisuels; masque=pMasque; masque.gotoAndStop(2); masque.filters=[new BlurFilter(10,10,BitmapFilterQuality.HIGH)]; // ajouter du code image 1 de masque masque.addFrameScript(0,chargeVisuels); addChild(masque); chargeVisuels(); }
Et c'est là qu'on est content d'avoir anticipé le gotoAndStop(2).
Hé oui, la méthode addFrameScript recèle bien des surprises quand on l'applique à une image de clip qui se trouve être l'image courante… Je ne vous cache pas que j'ai bien failli y laisser mon intégrité mentale (je synthétiserai plus loin). Pour éviter de nous compliquer la vie, avoir pris soin d'arrêter la tête de lecture image deux, est une ruse qui vaut ce qu'elle vaut, mais garantit un déroulement des choses sur lequel on a vraiment la main
Du coup, soit on appelle chargeVisuels
comme ci-dessus, soit on renvoie la tête de lecture image 1 et la fonction chargeVisuels
fraichement associée est invoquée (c'est la version des sources).
masque.gotoAndStop(1);
Et voilà une visionneuse, spartiate, mais tout à fait fonctionnelle…
Bien sûr on peut souhaiter quelques sophistications supplémentaires : changer le sens de défilement, paramétrer le temps de pause entre deux visuels, atteindre directement un visuel, disposer d'événements pour intercepter le moment où le diaporama boucle, où le changement d'image à lieu…
