|
|
| Tutoriaux : Création d'un diaporama avec un effet de masque |
|
1. Introduction |
| Ce tutoriel vous permettra de comprendre la réalisation du diaporama ci-dessus réalisé uniquement avec ActionScript ce qui vous permettra de l'adapter à vos besoins en modifiant simplement quelques paramètres (dimensions des photos, nombre de photos, rapidité des transitions, interactivité, forme du masque). Mon goût pour le code me pousse souvent à ne rien mettre dans la bibliothèque de l'animation et à créer dynamiquement les formes géométriques dont j'ai besoin. C'est pour cette raison que les étoiles utilisées pour obtenir les transitions entre les images sont tracées à l'aide des fonctions lineTo, moveTo et beginFill. |
|
|
| 2. Dans la bibliothèque |
| - Ouvrez le logiciel flash et créez un nouveau document. Dans le panneau "document" du menu "modification" définissez les dimensions de l'animation : 600 pixels de largeur et 400 pixels de hauteur. Ces dimensions ont été choisies pour être adaptées aux dimensions des images qui ont respectivement 600 et 400 pixels de largeur et de hauteur. - Définissez la cadence de l'animation à 25 images par seconde. - Pour une fois, ce qui se trouve dans la bibliothèque est simple à détailler : rien. Il n'y a rien dans la bibliothèque ! Dans le même répertoire que celui qui contient votre animation, créez un nouveau répertoire et nommez le "mesphotos". Placez dans ce répertoire les photos que vous voulez présenter. Pour suivre ce tutoriel vous pouvez télécharger l'ensemble des 6 photos de Takeshi Kitano (dont je suis fan :=)) présentées dans l'animation ci-dessus. Détail d'une extrême importance, vous devez nommer "correctement" vos images : photo0.jpeg, photo1.jpeg,...., photo5.jpeg ! |
| 3. Sur la scène principale |
| Tout comme la bibliothèque, la scène principale est vide ! |
| 4. Le code |
| Dans le panneau "action" de l'image clé n°1, placez le code ci-dessous. |
nbrDePhotos = 6; largeur = 600; hauteur = 400; coefficient = 0.02; vitesseDeRotation = 5; nbrMin = 4; nbrMax = 10; dscale = 0.02; rayon = Math.sqrt(largeur*largeur + hauteur*hauteur); MovieClip.prototype.tracerUneEtoile = function(r1, r2, n, c1, c2) { var da = Math.PI/n; this.lineStyle(0, c1, 100); this.moveTo(r2, 0); this.beginFill(c2, 100); for(var i = 1; i < 2*n + 1; i++) { var a = da*i; var r = (i % 2 == 0) ? r2 : r1; var x = r*Math.cos(a); var y = r*Math.sin(a); this.lineTo(x, y); } this.endFill(); } monFormatDeTexte = new TextFormat(); with (monFormatDeTexte) { size = 12; font = "Comic Sans MS"; color = "0xFF0000"; align = "center"; } this.createEmptyMovieClip("chargement", 1); chargement._x = 0.5*largeur; chargement._y = 0.5*hauteur; chargement.createTextField("texte", 0, - 0.5*largeur, 0, largeur, 20); chargement.texte.selectable = false; this.createEmptyMovieClip("diaporama", 0); diaporama._visible = 0; for(var i = 0; i < nbrDePhotos; i++) { var mc = this.diaporama.createEmptyMovieClip("photo" + i, i); mc.loadMovie("mesphotos/photo" + i + ".jpeg"); } this.onEnterFrame = function() { var total = 0; var charge = 0; for(var i = 0; i < nbrDePhotos; i++) { total += this.diaporama["photo" + i].getBytesTotal(); charge += this.diaporama["photo"+ i].getBytesLoaded(); } if(total != 0) {var prc = Math.round(charge/total*100);} else {prc = 0;} chargement.texte.text = "chargement : " + prc + " %"; chargement.texte.setTextFormat(monFormatDeTexte); if(prc == 100) { delete this.onEnterFrame; diaporama._visible = true; chargement.vx = 0; chargement.onEnterFrame = function() { this.vx += 1; this._x += this.vx; if(this._x > largeur) { creerLeMasque(); this.removeMovieClip(); } } } } numPhoto = nbrDePhotos - 1; creerLeMasque = function() { numPhoto--; if(numPhoto < 0) {numPhoto = nbrDePhotos - 1;} this.createEmptyMovieClip("masque", 2); masque._x = largeur - _xmouse; masque._y = hauteur - _ymouse; var n = Math.round(nbrMin + (nbrMax - nbrMin)*Math.random()); masque.tracerUneEtoile(rayon, rayon*(1.5 + Math.random()), n, 0, 0); this.diaporama["photo" + numPhoto].setMask(masque); var depth = this.diaporama.getNextHighestDepth(); this.diaporama["photo" + numPhoto].swapDepths(depth); masque.scale =masque._xscale = masque._yscale = 0; masque.drotation = 2*vitesseDeRotation*(Math.random() - 0.5); masque.onEnterFrame = animerLeMasque; } animerLeMasque = function() { this.scale += dscale; this._xscale = this._yscale += this.scale; this._rotation += this.drotation; this._x += coefficient*(_xmouse - this._x); this._y += coefficient*(_ymouse - this._y); if(this._xscale > 100) { this.removeMovieClip(); creerLeMasque(); } } |
| 5. Le code avec ses commentaires |
| Ce paramètre permet de définir le nombre de photos présentées dans le diaporama. |
| nbrDePhotos = 6; |
| On indique les dimensions des photos en pixels. |
| largeur = 600; hauteur = 400; |
| Regardez attentivement le diaporama et déplacez votre souris sur les images : les étoiles suivent le déplacement du curseur avec une inertie qui dépend de la valeur du paramètre "coefficient". Pour des valeurs proches de 1, les étoiles suivront parfaitement le déplacement de votre souris tandis que pour des valeurs proches de zéro, elles se déplaceront lentement vers le curseur. Une fois de plus, c'est la technique du easing qui est utilisée pour ajouter un peu d'interactivité. |
| coefficient = 0.02; |
| Les étoiles tournent autour de leur centre : ce paramètre permet de définir la vitesse maximale de rotation. |
| vitesseDeRotation = 5; |
| Les étoiles ne sont pas toutes identiques : elles peuvent avoir un nombre variable de branches qui sera défini aléatoirement entre nbrMin et nbrMax. |
| nbrMin = 4; nbrMax = 10; |
| dscale est un paramètre qui définit la vitesse de grossissement des étoiles : plus ce paramètre est grand, plus les étoiles grossiront vite et plus les images se succèderont rapidement. |
| dscale = 0.02; |
| On utilise le théorème de Pythagore (et oui les connaissances de collège peuvent être utiles !) pour calculer la longueur de la diagonale d'une image. Cette longueur sera égale au plus petit des deux rayons qui définissent la forme des étoiles. |
| rayon = Math.sqrt(largeur*largeur + hauteur*hauteur); |
| On utilise un prototype qui permet de tracer une étoile. Cette fonction utilise 4 arguments : les deux premiers sont des rayons, le troisième correspond au nombre de branches et les deux derniers sont des couleurs. Pour obtenir plus de commentaires sur ce prototype, lisez le tutoriel "tracer dynamiquement une étoile". |
| MovieClip.prototype.tracerUneEtoile = function(r1, r2, n, c1, c2) { var da = Math.PI/n; this.lineStyle(0, c1, 100); this.moveTo(r2, 0); this.beginFill(c2, 100); for(var i = 1; i < 2*n + 1; i++) { var a = da*i; var r = (i % 2 == 0) ? r2 : r1; var x = r*Math.cos(a); var y = r*Math.sin(a); this.lineTo(x, y); } this.endFill(); } |
| On crée un objet TextFormat afin de pouvoir formater le texte que nous placerons dynamiquement au début de l'animation au moment du chargement des images. On définit ainsi la taille, la police, la couleur et l'alignement du texte. |
| monFormatDeTexte = new TextFormat(); with (monFormatDeTexte) { size = 12; font = "Comic Sans MS"; color = "0xFF0000"; align = "center"; } |
| La fonction createEmptyMovieClip permet de créer un clip vide (comme son nom l'indique). Ce clip s'appelle "chargement" et contiendra le champ de texte dynamique permettant de suivre le chargement des images. |
| this.createEmptyMovieClip("chargement", 1); |
| On définit l'abscisse et l'ordonnée du clip "chargement" afin de le placer au centre de la scène. |
| chargement._x = 0.5*largeur; chargement._y = 0.5*hauteur; |
| A l'intérieur du clip "chargement", on place un champ de texte nommé "texte". Les arguments suivants permettent de définir l'abscisse, l'ordonnée, la largeur et la hauteur du champ de texte. En procédant ainsi, on s'assure de placer le texte au centre de la scène. |
| chargement.createTextField("texte", 0, - 0.5*largeur, 0, largeur, 20); |
| On rend le texte dynamique non sélectionnable. |
| chargement.texte.selectable = false; |
| On place à nouveau un clip vide sur la scène. Ce dernier s'appelle "diaporama" et sera placé "sous" le clip "chargement". Ce nouveau clip contiendra l'ensemble des photos. |
| this.createEmptyMovieClip("diaporama", 0); |
| On rend le clip "diaporama" invisible. Nous le rendrons visible lorsque toutes les images auront été chargées dans l'animation. |
| diaporama._visible = 0; |
| Nous utilisons une boucle for pour créer 6 clips vides à l'intérieur du clip diaporama. Puis dans chacun de ses clips nous chargeons une des photos du répertoire "mesphotos". |
| for(var i = 0; i < nbrDePhotos; i++) { var mc = this.diaporama.createEmptyMovieClip("photo" + i, i); mc.loadMovie("mesphotos/photo" + i + ".jpeg"); } |
| Nous définissons une fonction qui sera exécutée à chaque image. Dans un premier temps nous allons suivre le chargement des photos. Lorsque celui-ci sera terminé nous mettrons en route le diaporama. |
| this.onEnterFrame = function() { |
| Nous définissons deux variables "total" et "charge" qui représentent respectivement le poids total de l'ensemble des photos et le nombre d'octets chargés. |
| var total = 0; var charge = 0; |
| Une boucle for permet de calculer le poids total de l'ensemble des images ainsi que le nombre d'octets chargés à cet instant. |
| for(var i = 0; i < nbrDePhotos; i++) { total += this.diaporama["photo" + i].getBytesTotal(); charge += this.diaporama["photo"+ i].getBytesLoaded(); } |
| La variable "prc" est le pourcentage d'octets chargés par rapport au poids total des images. |
| if(total != 0) {var prc = Math.round(charge/total*100);} else {prc = 0;} |
| On remplit le champ de texte "texte" qui se trouve dans le clip "chargement" en affichant le pourcentage calculé précédemment. Chaque fois que le contenu d'un champ de texte est modifié, il faut penser à le formater à nouveau (utilisation de la fonction setTextFormat). |
| chargement.texte.text = "chargement : " + prc + " %"; chargement.texte.setTextFormat(monFormatDeTexte); |
| Si la valeur de "prc" est égale à 100, autrement dit si toutes les photos ont été chargées... |
| if(prc == 100) { |
| ... alors on annule l'exécution de cette fonction... |
| delete this.onEnterFrame; |
| ... on rend visible le clip "diaporama" contenant les photos... |
| diaporama._visible = true; |
| ... on définit une variable "vx" à l'intérieur du clip "chargement" : cette variable représente une vitesse (v) horizontale (x) d'où le choix de cette notation. Initialement, cette vitesse est nulle... |
| chargement.vx = 0; |
| ... et enfin on définit une fonction qui sera exécutée à chaque image (dans la "timeline" du clip "chargement"). Cette fonction incrémente "vx" d'une unité, ajoute la valeur de "vx" à l'abscisse du clip "chargement". Le clip "chargement" aura donc un mouvement horizontal uniformément accéléré. Lorsque l'abscisse du clip "chargement" devient supérieure à la largeur de l'animation, on fait un appel à la fonction "creerLeMasque" puis on enlève le clip "chargement" de la scène. |
| chargement.onEnterFrame = function() { this.vx += 1; this._x += this.vx; if(this._x > largeur) { creerLeMasque(); this.removeMovieClip(); } } |
| fin du "if" et de la fonction "onEnterFrame". |
| } } |
| numPhoto est une variable qui permet de définir la photo qui est actuellement visible dans le diaporama. |
| numPhoto = nbrDePhotos - 1; |
| Comme vous pouviez le deviner, ce diaporama utilise les calques de masque. La fonction suivante, permet de construire ce masque en définissant les paramètres de l'étoile, de sélectionner la photo à masquer et de la mettre au premier plan. |
| creerLeMasque = function() { |
| On enlève une unité à la variale "numPhoto" et on s'assure que sa valeur reste comprise entre 0 et 5. |
| numPhoto--; if(numPhoto < 0) {numPhoto = nbrDePhotos - 1;} |
| On place un nouveau clip vide sur la scène nommé "masque" dont l'abscisse et l'ordonnée dépendent de la postion de la souris... |
| this.createEmptyMovieClip("masque", 2); masque._x = largeur - _xmouse; masque._y = hauteur - _ymouse; |
| On détermine aléatoirement un entier "n" compris entre "nbrMin" et "nbrMax". Ce nombre représente le nombre de branches de l'étoile. |
| var n = Math.round(nbrMin + (nbrMax - nbrMin)*Math.random()); |
| A l'intérieur du clip "masque", on trace une étoile : le plus petit rayon de l'étoile est égal à la longueur de la diagonale de l'animation tandis que le deuxième rayon est choisi aléatoirement tout en restant supérieur au premier rayon. |
| masque.tracerUneEtoile(rayon, rayon*(1.5 + Math.random()), n, 0, 0); |
| On masque la photo qui se trouve dans le clip diaporama. |
| this.diaporama["photo" + numPhoto].setMask(masque); |
| On place la photo qui vient d'être masquée au premier plan, autrement dit au sommet de la pile de calques du clip "diaporama". |
| var depth = this.diaporama.getNextHighestDepth(); this.diaporama["photo" + numPhoto].swapDepths(depth); |
| On définit une variable "scale" à l'intérieur du clip "masque". On redimensionne le clip masque en modifiant ses propriétés _xscale et _yscale. Ainsi, le clip" masque" a des dimensions nulles et la photo qu'il masque est invisible. |
| masque.scale =masque._xscale = masque._yscale = 0; |
| On définit une deuxième variable "drotation" dans le clip "masque" : celle-ci correspond à la vitesse de rotation de l'étoile. Cette vitesse est choisie aléatoirement entre - vitesseDeRotation et vitesseDeRotation. Les étoiles pourront ainsi tourner dans les deux sens selon des vitesses variées. |
| masque.drotation = 2*vitesseDeRotation*(Math.random() - 0.5); |
| A chaque image de la "timeline" du clip "masque" on fera un appel à la fonction "animerLeMasque". |
| masque.onEnterFrame = animerLeMasque; |
| fin de la fonction "creerLeMasque". |
| } |
| J'aime bien donner des noms assez explicites à mes fonctions. La fonction "animerLeMasque" permettra d'animer le masque :=). Elle permettra de gérer le grossissement de l'étoile, sa rotation et ses déplacements horizontaux et verticaux.. |
| animerLeMasque = function() { |
| La fonction "animerLeMasque" augmente la valeur de la variable "scale" en lui ajoutant celle du paramètre "dscale" défini dans les premières lignes. |
| this.scale += dscale; |
| On ajoute la valeur de "scale" aux propriétés d'échelle _xscale et _yscale du clip "masque". Ainsi, la taille du clip "masque" augmentera en suivant une accélération uniforme rendant progressivement l'image visible. |
| this._xscale = this._yscale += this.scale; |
| On modifie ensuite l'angle de rotation du clip qui tourne autour de son centre avec une vitesse angulaire constante. |
| this._rotation += this.drotation; |
| On utilise la technique du easing pour gérer les déplacements du clip "masque" en fonction de la position du curseur. |
| this._x += coefficient*(_xmouse - this._x); this._y += coefficient*(_ymouse - this._y); |
| Si l'échelle du clip "masque" est supérieure à 100 (la photo est alors entièrement visible) on enlève le clip "masque" de la scène et on fait un appel à la fonction "creerLeMasque". |
| if(this._xscale > 100) { this.removeMovieClip(); creerLeMasque(); } |
| fin de la fonction "animerLeMasque". |
| } |
|
|