Voici un petit album photo rigolo.
Il nous permettra d'aborder divers sujet comme XML, remplir un tableau en utilisant les Objets, les preloaders avec MovieClipLoader, setInterval, le déplacement exponentiel…
Soulignons toutefois que sur certains navigateurs, l'animation “rame” à cause du fond transparent…
Tout d'abord le fichier “albumPhoto.xml”, qui sera enregistré au même niveau que le swf, et strucuré comme suit:
<?xml version="1.0" encoding="utf-8" ?> <album> <image src="album/maPhoto01.jpg" desc="photo n°01"/> <image src="album/maPhoto02.jpg" desc="photo n°02"/> <image src="album/maPhoto03.jpg" desc="photo n°03"/> <image src="album/maPhoto04.jpg" desc="photo n°04"/> <image src="album/maPhoto05.jpg" desc="photo n°05"/> <image src="album/maPhoto06.jpg" desc="photo n°06"/> <image src="album/maPhoto07.jpg" desc="photo n°07"/> <image src="album/maPhoto08.jpg" desc="photo n°08"/> <image src="album/maPhoto09.jpg" desc="photo n°09"/> <image src="album/maPhoto10.jpg" desc="photo n°10"/> </album>
Un petit rappel de maths sur le glissement exponentiel:
c'est un déplacement dans lequel on parcourt à chaque fois la moitié de la distance à parcourir, ce qui donne un effet de décélération ou de glissement, par exemple:
var destination:Number = 500; var vitesse:Number = 2; this.monClip.onEnterFrame = function(){ var distance:Number = destination - this._x; this._x += distance/vitesse; }
Et puis…c'est tout ! On va pouvoir rentrer directement dans le code.
Ah non, quand même, par souci esthétique j'ai placé un MC contenant une image d'appareil photo en haut à droite de la scène (fond noir, 800×600). Comme c'est original… ![]()
Allez, zou !
//==> échelle de départ vos photos (ici 20%, 5x plus petites) var startScale:Number = 20; //==> grossissement max de la photo var maxScale:Number = 500; /* attention apres le chargement des photos, startSale devient l'echelle de référence, donc vos photos réduites auront pour _xscale et _yscale 100, ce qui revient à dire que maxScale = echelleVoulue*(100/startScale), où echelleVoulue est l'echelle d'arrivée désirée... */ //==>les vitesses des différentes transformations` //attention plus la vitesse augmente plus la transformation est lente... var vitesseRotationIn:Number = 12; var vitesseRotationOut:Number = 8; var vitesseZoomIn:Number = 12; var vitesseZoomOut:Number = 8; //==> les identifiants de nos setIntervals qui vont effectuer les fonctions en boucle.. var nZoom:Number; var nDeZoom:Number; //==> la marge de l'image par rapport au background var marge:Number = 1; //==> le tableau qui contiendra les propriétés des images à charger var aPhotos:Array = new Array(); //==>on crée le clip qui va contenir tout ça ! var Album:MovieClip = this.createEmptyMovieClip("album_mc",this.getNextHighestDepth()); //==>et enfin on crée le champ de texte dynamique qui va nous servir à afficher les descriptions, this.createTextField("desc_txt",this.getNextHighestDepth(),20,550,760,40); this.desc_txt.multiline = true; this.desc_txt.selectable = false; //ainsi que son TextFormat associé var tfFormat:TextFormat = new TextFormat(); tfFormat.font = "Arial"; tfFormat.size = 20; tfFormat.color = 0xffffff; tfFormat.align = "center";
Voilà, passons maintenant à la récupération des données de notre fichier XML…
//on crée l'objet xml var listePhotos:XML = new XML(); listePhotos.ignoreWhite = true; //lorsque le xml est chargé listePhotos.onLoad = function(success:Boolean) { //si le chargement est réussi if (success) { //on associe une variable au noeud racine du xml (<album>...</album>) var noeudRacine:XMLNode = this.firstChild; //la propriété chidNodes est un tableau contenant tous les noeuds enfants du noeud appelé //donc là n est égal au nombre de noeuds enfants de noeudRacine var n:Number = noeudRacine.childNodes.length; //on effectue une boucle à chaque noeud for (var i:Number = 0; i < n; i++) { //à chaque noeud// //on crée un nouvel objet nommé image var image:Object = new Object(); //on définit une propriété src de l'objet image qui va contenir l'adresse de l'image… image.src = noeudRacine.childNodes[i].attributes.src; //…et une propriété desc qui va contenir la description de l'image image.desc = noeudRacine.childNodes[i].attributes.desc; //et on place cet objet dans notre tableau… aPhotos.push(image); } /*donc à partir de maintenant si je veux l'adresse de l'image 1, je n'ai plus qu'a faire: trace(aPhotos[0].src); et si je veux la description de l'image 8: trace(aPhotos[7].desc); Efficace, non ? */ //==> Maintenant on peut lancer la fonction qui va créer l'album photo, // en lui passant en parametres le clip Album et le tableau qui contient toutes les propriétés createAlbum(Album, aPhotos); //si le chargement a échoué... } else { //on envoie un message d'erreur throw new Error("erreur au chargement du XML"); } }; listePhotos.load("albumPhoto.xml");
Tout d'abord celle qui entraine toutes les autres:
Rappel: “cible” fait référence au clip “Album” et “tableau” au tableau “aPhotos”
function createAlbum(cible:MovieClip, tableau:Array):Void { for (var i:Number = 0; i < tableau.length; i++) { //on crée le conteneur qui va subir toutes les transformations var conteneur:MovieClip = cible.createEmptyMovieClip("conteneur" + i, cible.getNextHighestDepth()); //_x aléatoire entre 50 et (50+270) (pour éviter qu'elles n'empiètent sur la photo à gauche de la scène) conteneur._x = 50 + 270 * Math.random(); //_y aléatoire entre 100 et (100+200) (pour éviter qu'elles n'empiètent sur le textField en bas de la scène) conteneur._y = 100 + 200 * Math.random(); //rotation aléatoire entre -30 et 30 degrés, que l'on stocke en créant la propriété "startRoto" conteneur.startRoto = -30 + 60 * Math.random(); conteneur._rotation = conteneur.startRoto; //actions de bouton conteneur.onPress = cliquer; conteneur.onRelease = conteneur.onReleaseOutside = relacher; //creation du conteneur pour l'image var mcImage:MovieClip = conteneur.createEmptyMovieClip("image" + i, conteneur.getNextHighestDepth()); //chargement de l'image loadJpeg(tableau[i].src, mcImage); //on associe notre clip à sa description en créant la propriété "desc" conteneur.desc = tableau[i].desc; } }
Le gros morceau: celle qui va se charger de charger les images !
function loadJpeg(urlImage:String, cible:MovieClip) { //nouvelle instance de MovieClipLoader var mclLoader:MovieClipLoader = new MovieClipLoader(); //objet qui va écouter le chargement de l'image var oEcouteur:Object = new Object(); //on assigne oEcouteur à mclLoader mclLoader.addListener(oEcouteur); //au début du chargement (mcContent est une référence au clip chargé)... oEcouteur.onLoadStart = function(mcContent:MovieClip) { //on crée un preloader... var loader:MovieClip = mcContent.createEmptyMovieClip("loader", 0); //dans lequel il y a une barre de fond ... var loaderBg:MovieClip = loader.createEmptyMovieClip("loaderBg", 0); with (loaderBg) { beginFill(0x666666, 50); lineTo(50, 0); lineTo(50, 5); lineTo(0, 5); lineTo(0, 0); endFill(); } //et une barre de chargement de mêmes dimensions... var loadBar = loader.createEmptyMovieClip("loadBar", 1); with (loadBar) { beginFill(0xffffff, 100); lineTo(50, 0); lineTo(50, 5); lineTo(0, 5); lineTo(0, 0); endFill(); } }; //pendant le chargement... oEcouteur.onLoadProgress = function(mcContent:MovieClip, loaded:Number, total:Number) { //on calcule le pourcentage de bytes chargés... var pourcentage:Number = Math.round(100 * (loaded / total)); //et on l'assigne au _xscale de la barre de chargement mcContent.loader.loadBar._xscale = pourcentage; }; //à la fin du chargement... oEcouteur.onLoadInit = function(mcContent:MovieClip) { //on suprime le preloader... removeMovieClip(mcContent.loader); //on met nos images à l'echelle de départ... mcContent._xscale = mcContent._yscale = startScale; //conteneur fait référence au conteneur crée dans createAlbum(); var conteneur:MovieClip = mcContent._parent; //on crée un MC qui va se placer derrière l'image chargée (mcContent.getDepth() - 1)... var backGround:MovieClip = conteneur.createEmptyMovieClip("backGround", mcContent.getDepth() - 1); //on dessine le backGround... var bgWidth:Number = mcContent._width + marge * 2; var bgHeight:Number = mcContent._height + marge * 2; backGround.beginFill(0xffffff, 100); backGround.lineTo(bgWidth, 0); backGround.lineTo(bgWidth, bgHeight); backGround.lineTo(0, bgHeight); backGround.lineTo(0, 0); backGround.endFill(); //et on repositionne l'image... mcContent._x = mcContent._y = marge; }; //enfin on dit à mclLoader de charger l'image en question (tableau[i]...rappelez-vous !) mclLoader.loadClip(urlImage, cible); }
Celles qui gèrent le onPress et le onRelease:
Rappel: dans un gestionnaire d'évènement, le this fait référence à l'objet qui emet l'évènement !
(qui donc dans ce cas-là ?)
//Au clic (onPress) function cliquer() { //on appelle la description this._parent._parent.desc_txt.text = "Description:" + newline + this.desc; //on applique le TextFormat this._parent._parent.desc_txt.setTextFormat(tfFormat); //on cache la souris... Mouse.hide(); //on stoppe l'éxécution de la fonction deZoom clearInterval(nDeZoom); // this._x0 = _xmouse - this._x; this._y0 = _ymouse - this._y; //on fait passer le clip au-dessus de tous les autres this.swapDepths(Album.getNextHighestDepth()); //et on appelle la fonction zoom() toutes les 25millisecondes nZoom = setInterval(zoom, 25, this); } //onRelease,onReleaseOutside... function relacher() { //on montre la souris Mouse.show(); //on tue la fonction zoom clearInterval(nZoom); //on assigne une nouvelle valeur d'arrivée à la rotation du clip this.startRoto = -30 + (60 * Math.random()); //appelle la fonction deZoom toutes les 25ms nDeZoom = setInterval(deZoom, 25, this); }
Et enfin celles qui s'occupent du redimensionnement des images !
//ZOOM function zoom(cible:MovieClip) { //on fait suivre la souris par l'image cible._x = _xmouse - cible._x0; cible._y = _ymouse - cible._y0; //on rétablit la rotation du clip cible._rotation += -cible._rotation / vitesseRotationIn; //et on Zoome (cf le rappel sur le déplacement exponentiel !) cible._xscale += (maxScale - cible._xscale) / vitesseZoomIn; cible._yscale += (maxScale - cible._yscale) / vitesseZoomIn; //si on est très proche de l'arrivée, if (cible._xscale > maxScale - 1) { //on y va directement, sans quoi on y arrive jamais... cible._xscale = cible._yscale = maxScale; cible._rotation = 0; } updateAfterEvent(); } //DéZOOM function deZoom(cible:MovieClip) { //on refait tourner le clip cible._rotation += (cible.startRoto - cible._rotation) / vitesseRotationOut; //on dézoome cible._xscale += (100 - cible._xscale) / vitesseZoomOut; cible._yscale += (100 - cible._yscale) / vitesseZoomOut; //si on est très proche de l'arrivée, if (cible._xscale < 101) { //on y va directement, sans quoi on y arrive jamais... cible._rotation = cible.startRoto; cible._xscale = cible._yscale = 100; } updateAfterEvent(); } //
Et voilà !
Si ce code vous a plu, que vous y avez apporté des améliorations, tant au niveau du script qu'au niveau graphique, ou que vous bloquez sur un passage du tutoriel, n'hésitez pas à me le faire savoir !
— par JulesB , le 08/10/2006 22:31
Encore des questions? Besoin d'aide? Venez en discuter sur les forums Programmation Dynamique ou Programmation Actionscript.