Version en ligne

Tutoriel : Introduction à l'ActionScript

Table des matières

Introduction à l'ActionScript
Flash bien / pas bien
Flash sous toutes ses coutures
Flash c'est pas bien
Flash c'est bien
Deux architectures classiques
L'Architecture Flashocentriste
L'architecture Flashoponctuelle
L'IDE de macromedia
Se familiariser avec l'interface
Le Scénario
Formes et Symboles
Où je le mets ce fichu code ?
Notion de "clip"
Créer un clip
Les zones de texte
La solution pratique
Ma première animation !
Un nouveau document
Dessine moi une balle
Interpolation de mouvement
Un soupçon d'ActionScript
Fil rouge
Cahier des charges
Architecture globale
Variables et fonction trace()
Structure et commentaires
Fonction trace()
Les numériques : int et Number
Les chaines de caractères : String
Les tableaux : Vector
MovieClip
_root , this et _parent
Positionnement
Taille absolue
Agrandissement
Rotation
Transparence
Visibilité
Les Conditions
Un nouveau type : Boolean
Opérateurs de test
Opérations sur les booléens
La structure conditionnelle
Récapitulatif
Les Boucles
Qu'est-ce qu'une boucle
Boucle while
Boucle for
Petits exercices de style
Les Fonctions
Déclarer une fonction
Des arguments
Retour de valeur
Méthodes et fonctions
Les Evénements
Vous avez dit "événement" ?
Evénements souris localisés
Evénements souris globaux
Evénements à tout faire !
Récapitulatif
Fil rouge - le logo animé
Point de départ
Bonnet de noël
Rotation des yeux
Contenu de la bulle
Récapitulatif
Créer et enlever des Clips
Clips dynamiques, statiques et profondeur
Créer un clip vide
Dupliquer un clip de la scène
Attacher un clip à la scène
Supprimer un clip
Une astuce en profondeur
La variable dans la variable
Publication et variables
Paramètres de publication Html
Le code Html expliqué
Envoie des variables
Réception des variables
Les caractères spéciaux
Dessiner avec Actionscript
Couleurs d'un clip
Dessinons sur des clips
Gribouillons un peu
Un peu de coloriage !
Gommez moi tout ça !
Utiliser le clavier
Les écouteurs
La touche enfoncée
Les raccourcis des touches
Une condition bien pratique !
Trichons avec les écouteurs
Les collisions
Approche des collisions
Collision rectangulaire
Collision circulaire
Collision ponctuelle
Collision bourrine
Fil rouge - On The Road Again
Point de départ
Faire mumuse avec la voiture
Les goals
Collisions inside
Fignolages
Des améliorations
Sécurité et Flash
crossdomain.xml
Structure de crossdomain.xml
Nouveautés de FlashPlayer 8
Contourner la protection
Images et Animations
Dans un clip ou un niveau
Un chargeur
Redimensionner l'image
Particularité du chargement des animations
Transfert de variables
La vieille technique
Chargement avec LoadVars
Envoyer des variables
Exercice : Zozor dynamique
Musique !
Préparation du terrain
Lecture
Curseur de lecture
Chargement dynamique
Vidéos
Riva FLV Encoder
Un nouvel objet
Trois classes pour le prix d'une
Contrôle du flux
Fil Rouge - Radio-Blog
Du côté de PHP
Chargement de la Playlist
Gestion de la musique
Le volume - startDrag() notre ami
L'ascenceur
Gestion du XML
Rappel sur le XML
Chargement
Une grande famille !
Types et attributs
XML tabulaire
Rotation d'un clip vers la souris
Création du clip
Explication géométrique
Le code

Introduction à l'ActionScript

Image utilisateur

Bonjour futurs flasheurs :D .

Depuis plusieurs années, vous pouvez voir fleurir sur les sites de la galaxie Web des petites animations colorées et interactives. Que ce soit des petits jeux, des radios, ou encore simplement de la publicité : Flash est maintenant omniprésent !

Dans Flash, on trouve deux parties distinctes : le graphisme et le scripting. Ce que ce tuto vous propose de faire c'est d'apprendre l'ActionScript, c'est-à-dire toute la partie dynamique d'une animation Flash !

Je vous souhaite bonne chance, et j'espère que vous prendrez autant de plaisir dans la lecture de ce tutoriel que moi pour l'écrire ;) .

Flash bien / pas bien

Flash sous toutes ses coutures

Nous allons dans ce chapitre apprendre à déjouer les pièges de Flash. Ces pièges qui entraînent de nombreux webmestres avides de rendre leur site flashy à leur perte !

Oui, car l'utilisation de Flash dans un site est souvent chaotique et mal organisée. C'est pour cela que de nombreuses personnes considèrent Flash comme l'arme du Malin ^^ .
Alors qu'en fait, si Flash commence à avoir une si mauvaise réputation c'est seulement parce qu'il est mal utilisé :) .

On va donc déjà voir les arguments des uns et des autres. Puis nous essayerons de tirer la première conclusion de ce tutoriel : pourquoi certains sites en Flash sombrent dans les abîmes du Web alors que d'autres atteignent des sommets ?

Flash sous toutes ses coutures

Flash bien / pas bien Flash c'est pas bien

Flash sous toutes ses coutures

Tout d'abord il me paraît impératif de resituer Flash pour pouvoir bien comprendre comment fonctionne ActionScript.

Le Flash est un format de fichier d'extension swf (=schockwave Flash) pouvant contenir de la vidéo, des images vectorielles ou bitmaps, du son, et encore du code pour l'interaction avec l'utilisateur. Depuis sa version 4, les spécifications SWF ont été rendues publiques, ce qui a conduit à la création de programmes comme Swish, ou des modules pour Eclipse permettant de créer une animation flash simple ou gratuite (impossible d'avoir les deux à la fois :D ). Mais l'outil le plus puissant (et le plus cher ! ) pour créer du Flash reste Macromedia Flash, et surtout sa dernière version 8 que nous utiliserons au cours de ce tutoriel !

SWF est un format de fichier binaire. On définit un fichier binaire comme ce qui n'est pas un fichier texte ;) . L'intérêt du binaire par rapport au texte, c'est qu'il prend beaucoup moins de place, et c'est justement le grand avantage des animations Flash : leur compacité. Le problème, c'est qu'un fichier SWF une fois compilé ne peut plus être modifié (du moins pas directement) !
C'est pourquoi vous enregistrez votre projet Flash au format FLA, binaire lui aussi et dépendant de votre version de Macromedia Flash, qui contient la source de votre animation que vous pouvez modifier.

Le langage de script de Flash est l'ActionScript, un dérivé de l'ECMAscript (= nom standardisé du javascript). Les connaisseurs retrouveront donc certains éléments, mais je vous garantis que la non-connaissance du Javascript n'est en aucun cas un frein à l'apprentissage de l'ActionScript ! Par contre vous devriez être capable de faire du Javascript une fois que vous connaîtrez l'AS ;) .


Flash bien / pas bien Flash c'est pas bien

Flash c'est pas bien

Flash sous toutes ses coutures Flash c'est bien

Flash c'est pas bien

Les démons de Flash sont en gros :

Pour toutes ces raisons, importantes dès qu'on rentre dans le cadre d'une application web (= ensemble des pages web, scripts, bases de données, contenus...) professionnelle ou semi-professionnelle, il faut savoir utiliser la technologie Flash avec parcimonie !


Flash sous toutes ses coutures Flash c'est bien

Flash c'est bien

Flash c'est pas bien Deux architectures classiques

Flash c'est bien

Mais Flash permet tout de même :

Et puis surtout Flash, comme son nom l'indique, attire l'oeil !
Si votre site comporte un petit jeu en accord avec le thème général ou des petits éléments rigolos, ça ne pourra être que du bon :D .

Comme vous pouvez le constater, Flash est en fin de compte une technologie à double tranchant. Pour résumer on peut énoncer 2 lois :

Flash ne doit pas être utilisé à outrance dans un site de type communautaire et sujet à de nombreuses évolutions

Flash est très adapté aux sites vitrines ou comme contenu semi-dynamique (affichage de graphiques, musiques, vidéos ...)

Voilà, j'espère que je ne vous ai pas trop démoralisé pour un premier chapitre, mais il me paraissait indispensable de vous donner tous les éléments avant de commencer la programmation :) .


Flash c'est pas bien Deux architectures classiques

Deux architectures classiques

Flash c'est bien L'Architecture Flashocentriste

Nous avons pu voir les 2 lois à ne pas enfreindre pour réaliser un site Web potable utilisant Flash. Nous allons maintenant voir que chaque loi conduit à un type possible d'architecture.

Ce sont les deux principales architectures utilisées impliquant Flash.

L'Architecture Flashocentriste

Deux architectures classiques L'architecture Flashoponctuelle

L'Architecture Flashocentriste

Vous vous demandez sûrement ce qui se cache sous ce nom pompeux que je viens d'inventer pour le besoin :p . Et bien en fait, il s'agit de l'architecture dans laquelle Flash est au centre du site web.
Voici donc l'architecture à ne surtout pas reproduire si on souhaite créer un site communautaire selon la première loi :
Flash ne doit pas être utilisé à outrance dans un site de type communautaire et sujet à de nombreuses évolutions.
Et selon la seconde loi :
Flash est très adapté aux sites vitrines ou comme contenu semi-dynamique.
Cette architecture est très intéressante dans le cas d'un site galerie/vitrine/portfolio

Image utilisateur

Flash est au centre de l'application Web. L'utilisateur ne navigue pas à travers différentes pages web mais dans un seul objet Flash, qui affichera le contenu en fonction des requêtes de l'utilisateur. Pour aller chercher des données, flash à travers son langage de script, l'ActionScript que nous verrons plus loin dans ce tuto, peut charger des pages et en récolter le contenu. Flash est donc capable d'aller formuler une requête à un script côté serveur, de type PHP, et d'afficher les données formatées (que nous appellerons des informations, terminologiquement les informations ce sont les données une fois triées et formatées).


Deux architectures classiques L'architecture Flashoponctuelle

L'architecture Flashoponctuelle

L'Architecture Flashocentriste L'IDE de macromedia

L'architecture Flashoponctuelle

Une toute autre approche dans l'utilisation de Flash n'est plus son utilisation comme fournisseur de contenu, mais comme contenu lui même. Bien entendu, l'utilisation en sera complètement différente.
En fait, si on suit les deux lois, cette architecture est à privilégier dans le cas d'un site fournisseur de contenu riche, ou communautaire.

Image utilisateur

Cette fois les animations Flash sont considérées non pas comme l'unique moyen d'afficher les informations, mais plutôt comme des images. On peut voir sur le schéma qu'il existe alors 2 principaux moyens pour transmettre une donnée à l'animation qui devra l'afficher. Soit comme précédemment l'animation va chercher toute seule les données et les met en forme, soit dans le code xhtml de la page on complète le lien vers l'animation par la transmission de une ou plusieurs variables au format GET ( mavar1=salut&mavar2=comment+ca+va ).
Mais rien n'empêche de combiner les deux pour indiquer à l'animation son rôle dans la page et la laisser ensuite chercher elle même ce qu'il manque ! :D

Voilà j'espère que vous avez pu choisir quelle architecture était la plus adaptée pour votre site Web.

En résumé pour les feignants, voici la conclusion du second tutoriel :

Flash en tant que site web complet dans le cadre d'un site vitrine/galerie. Flash en tant que "images" incluses dans le site web.


L'Architecture Flashocentriste L'IDE de macromedia

L'IDE de macromedia

L'architecture Flashoponctuelle Se familiariser avec l'interface

IDE (= Integrated Development Environment) est une abréviation caractérisant les logiciels qui facilitent le développement d'applications sur ordinateur.
Dans ce chapitre, nous nous intéresserons au plus connu des IDEs pour le Flash : il s'agit d'Adobe Flash 8 (plus connu sous le nom de Macromedia Flash 8, mais Macromedia s'est fait racheter il y a quelques temps maintenant par Adobe).

Se familiariser avec l'interface

L'IDE de macromedia Le Scénario

Se familiariser avec l'interface

Pour que vous puissiez convenablement suivre ce tutoriel, on va essayer de se mettre d'accord sur la disposition des différentes fenêtres de Flash.

Utilisez le menu Fenêtre dans la barre des menus du haut, pour disposer les fenêtres de la façon suivante :

Image utilisateur

En plein milieu, le gros carré blanc, représente la Scène. C'est ce que verra l'utilisateur de votre animation, et c'est là que nous dessinerons et jouerons avec des formes.

On remarquera le panneau Actions tout en haut, dans lequel nous écrirons le code ActionScript.
Juste en dessous se trouve le Scénario (souvent appelé timeline en anglais). Il permet de naviguer dans le temps et dans les calques, nous reviendrons dessus plus loin.

Tout en bas, deux panneaux très importants :
- L'aide de Flash, qui est extrêmement claire et détaillée. Quand je vous présente une nouvelle fonction ou une nouvelle classe, n'hésitez pas à aller voir ce qu'en dit l'aide qui apportera un complément d'informations ainsi que des exemples pratiques.
- Les propriétés, qui permettent de modifier justement les "propriétés" des objets que l'on peut manipuler dans Flash.

A gauche vous trouvez comme d'habitude la classique barre d'outils, très similaire à celle de logiciels comme photoshop, par exemple.

Et enfin à droite encore d'autres fenêtres. Celle qui nous intéresse étant la Bibliothèque.

Ainsi se termine le petit tour d'horizon des différentes fenêtres de Flash.


L'IDE de macromedia Le Scénario

Le Scénario

Se familiariser avec l'interface Formes et Symboles

Le Scénario

Image utilisateur

Maintenant, mettez votre casquette, Spielberg n'a qu'à bien se tenir ! :p
Nous allons attaquer le scénario ! Le gros bloc plein de carrés noirs et blancs en haut.

Nous avons vu que la scène permettait de dessiner en deux dimensions : largeur et hauteur.

Le scénario rajoute deux dimensions :

La profondeur

La profondeur se gère à l'aide des Calques, à gauche dans le scénario. Vous pouvez en créer autant que vous le souhaitez, mais vous devrez toujours en garder un au minimum.

En fait, leur utilisation est toute simple : vous pouvez dessiner sur chacun, mais les formes(=les dessins) de chaque calque sont indépendantes entre elles. Elles ne peuvent donc pas "s'écraser" mutuellement. Essayez donc de dessiner un carré plein dans un calque et un disque dans un autre et superposez les deux formes. Elles se chevauchent sans problème et ne s'effacent pas comme elles l'auraient fait si elles avaient été sur un seul calque.

Vous remarquerez aussi que la forme qui est dans le calque du dessus, est aussi au dessus dans la scène. L'ordre dans lequel vous rangez vos calques permet donc de gérer la profondeur de vos formes les unes par rapport aux autres.

Si vous mettez un calque au dessus de tous les autres, alors les dessins placés sur ce calque seront au dessus de tous les autres dans la scène.

Le temps

Chaque petite case que vous voyez est une image, que nous appellerons quelques fois frame ("trame" en anglais) pour éviter les confusions. Le curseur rouge contrôlable à la souris permet de se déplacer dans le scénario : c'est à dire dans le temps.
Il existe plusieurs types de frames.

Image utilisateur

Dans l'image ci-dessus, vous pouvez voir en position 1 ce qu'on appelle une image-clé pleine. Je sais qu'elle est clée parce qu'elle a un petit point noir et qu'elle est pleine parce qu'elle est grisée.
Je suppose que vous avez compris que pleine signifie que dans cette frame on a dessiné quelque chose. Cette image-clé continue jusqu'en position 16, le carré blanc en indiquant la fin. Toutes les images entre le point noir et le carré blanc sont donc les mêmes.

Quel type d'image avons-nous en position 32 ?

Une image-clé vide ! Qui se termine en position 40.

Il faut bien comprendre que chaque image correspond à la scène à un instant donné.

On va prendre l'exemple d'un petit dessin-animé avec un bonhomme en fil de fer :
Mettez vous à la position 1 (avec une image-clé vide) et dessinez un personnage à tête jaune.
Créez une nouvelle image-clé en position 6 et changez la couleur de la tête du personnage pour du rouge. Ajoutez une image simple à la position 10 pour que le personnage rouge reste quelques instants et ne s'en aille pas tout de suite à cause de la lecture en boucle de l'animation.

Si vous exécutez l'animation (Contrôle->Tester l'animation), vous verrez que chaque personnage reste affiché le temps de 5 frames.

Si vous avez un peu de mal au début, vous pouvez vous aider du mode Aperçu du scénario. Il faut cliquer sur le petit bouton en haut à droite du scénario comme ci-dessous et sélectionner Aperçu. Vous devriez obtenir un scénario semblable à celui ci :

Image utilisateur

Ce mode est pratique pour débuter, mais pas vraiment pour travailler ;) .

J'en profite pour vous parler des ips (images par secondes) ou encore en anglais : fps (frames per seconds).
Sur la photo ci-dessus, on peut lire en bas : 12.0 ips.
Cela signifie, que durant 1 seconde, Flash lira 12 images. En clair une frame durera 1/12 = 0.083 seconde !

On estime la durée de la persistance rétinienne à 50ms, ce qui donne 40 images par secondes pour avoir une fluidité quasi-optimale.
Personnellement j'utilise souvent 24 ips dans mes animations, c'est d'ailleurs la fréquence utilisée à la télévision.
Pour modifier cette valeur dans votre animation, il vous suffit de double-cliquer dessus.


Se familiariser avec l'interface Formes et Symboles

Formes et Symboles

Le Scénario Où je le mets ce fichu code ?

Formes et Symboles

Tous les objets présents dans la scène sont :

Les formes

Je passerai rapidement dessus, car je pense que vous savez déjà dessiner ;) . La particularité des formes dans Flash, c'est qu'elles sont vectorielles.

Les images Bitmaps

Prenons un exemple : ouvrez paint, dessinez une droite, puis zoomez à fond dessus !

Image utilisateur

Vous remarquez que la droite est "crénelée", ou "pixelisée" : on peut distinguer chaque pixel aisément.
C'est ce qu'on appelle une image bitmap, qu'on peut traduire par "carte de bit" en français.
C'est vrai que ce n'est pas beaucoup plus parlant ;) . En fait, il faut se représenter l'image comme une grille, où chaque case possède des coordonnées. Ensuite dans votre image Bitmap, à chaque case, c'est à dire à chaque pixel, on associe une couleur.

Donc en clair, plus on zoom, plus c'est moche :p

Les images vectorielles
Image utilisateur

On peut bien sûr importer des images Bitmaps dans Flash, mais non seulement c'est moche quand on zoom dessus, mais en plus ça prend beaucoup de place, car il faut stocker la couleur de chaque pixel de l'image !
A la base, les animations Flash sont censées être très légères, car elles sont faites pour le Web, et tout le monde ne possède pas du 100Mbit/s comme connexion internet :D .
En Flash on dessine donc avec des vecteurs. Vous pouvez dessiner une droite dans Flash, et vous verrez que même en zoomant à fond, elle reste lisse !

Dans une image vectorielle on ne stocke donc pas la couleur de chaque pixel, mais seulement les coordonnées d'un vecteur et de son origine. Si vous regardez le schéma à côté, le vecteur est représenté par la flèche orange. Son origine correspond au point A.
On a juste besoin d'enregistrer la position du point A et les coordonnées (la longueur et l'orientation si vous préférez) du vecteur. Ensuite, le lecteur Flash interprétera les données et dessinera une droite partant de A et suivant le vecteur.

Le principe reste le même si vous dessinez des courbes ou des formes complexes, les vecteurs permettent alors d'indiquer en plus la "courbure" d'une droite.

A vous de jouer

Maintenant que vous savez ce qu'est une image vectorielle, je vais vous laisser jouer avec les pinceaux et stylos de la barre d'outils. Ils se manipulent presque comme ceux de Paint ou de Photoshop, mais vous devez garder à l'esprit qu'ils fonctionnent avec des vecteurs, vous ne pourrez donc pas faire de Pixel-Art dans Flash :D .

Les symboles

Tout ce qui n'est pas une forme est nécessairement un symbole. Première particularité des symboles : ils sont tous listés dans la bibliothèque.

Prenons un exemple. Dessinez un carré rouge sur la scène avec l'outil rectangle, sélectionnez votre joli carré et cliquez dans les menus sur Modification -> Convertir en Symbole.

Image utilisateur

Vous pouvez donner un nom à votre symbole. Ce nom permettra de le retrouver dans la bibliothèque, on l'appellera donc nom de bibliothèque.
La fenêtre vous demande aussi l'alignement de la forme sélectionnée dans le symbole. Soit vous centrez le symbole avec la forme, soit vous mettez la forme dans un des coins du symbole. A vous de choisir pour l'instant.

Image utilisateur

Comme vous pouvez le voir, il existe 3 types de symboles. Nous allons les détailler plus bas.
Pour l'instant votre nouveau symbole apparaît dans la bibliothèque.
Ce qu'il y a sur votre scène n'est donc plus une forme, mais un symbole, vous ne pouvez donc plus le modifier directement avec les outils.
En fait la forme est maintenant contenue dans le symbole. Pour la modifier, il faut rentrer dans le symbole. Vous pouvez pour cela double-cliquer soit sur l'occurrence du symbole dans la scène soit sur son nom dans la bibliothèque.

Maintenant, glissez-déplacez plusieurs fois le symbole de la bibliothèque vers la scène. Vous remarquez qu'on peut en mettre autant qu'on veut ! En fait, le symbole dans la bibliothèque est le "modèle" et tous ceux sur la scène sont des occurrences de ce modèle.
D'ailleurs si vous modifiez un seul de ces symboles, la modification se répercute sur tous les autres !

Il est possible de placer un symbole dans un autre, puis dans un autre, puis dans un autre etc..., à l'infini ! Par contre, n'essayez pas de placer un symbole dans lui même : ça ne fonctionnera pas !

Voyons maintenant les différences entre les différents symboles :

Le graphique

Le graphique est le symbole le plus simple ! Il permet de convertir une forme en symbole et de le réutiliser le nombre de fois voulu sur la scène. Un graphique n'apporte aucune interactivité et doit donc être utilisé décorativement seulement.
Les graphiques peuvent aussi être animés, il faudra alors préciser s'ils doivent l'être en boucle ou pas dans les propriétés de l'occurrence. (Vous sélectionnez l'occurrence sur la scène et vous pouvez modifier ses propriétés dans le panneau justement nommé Propriétés).

Le bouton

Les boutons permettent de rajouter un peu d'interactivité dans votre animation, en permettant à l'utilisateur de cliquer dessus. On peut ensuite lier le bouton à un Script.

Vous pouvez remarquer que le scénario d'un bouton est différent de celui de la scène ou d'un graphique. On ne peut y mettre que 4 images, qui correspondent aux 3 états du bouton plus sa zone de réactivité.

Image utilisateur

Le premier état Haut correspond à l'aspect du bouton quand on n'y touche pas. Dessus correspond à la forme du bouton quand on passe la souris dessus, et Abaissé c'est tout bêtement quand on clique dessus. Vous pouvez ainsi créer 3 images-clés pour chaque état et constater par vous même.

La dernière image : cliqué, ne sera jamais visible par l'utilisateur, elle permet de spécifier la zone cliquable. Ainsi, si vous n'avez que du texte dans votre bouton, pour cliquer dessus, il faudra viser une lettre précisément, pas à côté ! Alors que si vous rajoutez un rectangle qui encadre le texte dans l'image-clé Cliqué, alors il suffira de passer la souris sur ce rectangle (invisible dans l'animation) pour que le bouton s'active !

Les boutons ne peuvent pas être directement "animés" (avec une seule image, ça va être dur). Mais rien ne vous empêche de créer un graphique animé, et de le placer dans un des états du bouton :) .

Les Clips

Aussi appelés quelquefois MovieClip, il sont la crème des symboles ! (c'est pour ça que je les garde pour la fin).
Il est en tout point commun avec la scène (d'ailleurs, la scène est un clip par convention...) et c'est celui qu'on utilise le plus. Si on le souhaite, il peut se comporter comme un bouton, on peut aussi lui adjoindre du code, et en plus il peut être animé !

Bref, le symbole à tout faire. Pour l'instant je n'en dit pas plus, vous le découvrirez vous même plus tard.

Vous connaissez maintenant les bases du maniement de Flash. Maintenant, essayez de vous débrouiller tout seul et surtout : expérimentez ! Touchez à tous les boutons, et si vous ne comprenez pas l'utilité de l'un d'eux, allez voir dans l'aide de Flash !

Pareil pour le dessin, je ne vais pas vous montrer comment manier ces outils. C'est à vous de les essayer et de comprendre leur maniement.


Le Scénario Où je le mets ce fichu code ?

Où je le mets ce fichu code ?

Formes et Symboles Notion de "clip"

La principale difficulté du flasheur débutant est la position de son code dans l'application.

On va donc déjà aborder la notion de clip chère à Flash pour ensuite s'attarder sur la meilleure posture à adopter. :D

Notion de "clip"

Où je le mets ce fichu code ? Créer un clip

Notion de "clip"

On appelle la scène principale de votre application, le carré blanc au centre de l'écran quand vous créez un nouveau document.
Retenez que son nom est _root.

Il faut considérer les clips comme les "briques" d'une animation Flash. Les clips sont des petites animations à part entière, dans la mesure où ils ont leur propre scénario indépendant du scénario de la scène principale.

Il est possible de créer des clips sur la scène (Insertion->Nouveau symbole ou Modification->Convertir en symbole). Les clips présents sur scène sont des symboles auxquels on peut donner un nom d'occurrence.

Chaque clip peut lui même comprendre d'autres clips, qui peuvent eux aussi avoir des clips, qui peuvent... Enfin bref, vous m'avez compris. :D On peut imbriquer des clips les uns dans les autres !

Voyons maintenant comment se place le code par rapport aux clips, il est possible de placer de l'ActionScript :

Par convention, _root (la scène principale) est un clip, on peut donc lui assigner du code en sélectionnant une image clé dans le scénario et en codant dans l'onglet action (et c'est ce qu'on fera ;) ).

Et le cauchemar ne s'arrête pas là !
Car si on peut mettre du code sur une image clé d'un clip, ça veut dire qu'on peut mettre du code différent sur chaque image clé dans un même clip... :D

Bref que de réjouissances en perspective. :p


Où je le mets ce fichu code ? Créer un clip

Créer un clip

Notion de "clip" Les zones de texte

Créer un clip

Nous allons brièvement voir comment créer un clip.

Dans la barre des menus, cliquez sur "Nouveau Symbole" ou alors utilisez le raccourci Ctrl+F8 :

Image utilisateur

Une boîte de dialogue apparaît pour vous demander le nom que vous souhaitez donner au nouveau clip. Le nom qu'on donne là n'a pas d'influence en ActionScript, ce nom n'est là que pour "décorer", c'est à dire vous faciliter la vie pour retrouver ce clip qui va s'ajouter dans la bibliothèque. Au cours de ce big-tuto, on appellera ce nom nom de bibliothèque. La plupart du temps, ça sera à vous de choisir ce nom, dans la mesure où il n'a pas d'utilité en ActionScript.

Image utilisateur

Maintenant toujours dans cette même boîte de dialogue, si vous cliquez sur avancé, vous obtiendrez de nouvelles options, dont une qui nous intéressera plus particulièrement par la suite : le nom de liaison. Pour pouvoir donner un identifiant à notre clip, il va falloir cocher la case "Exporter pour ActionScript". Le nom que vous donnez là est très important, car il permettra de créer le clip sur la scène en utilisant ActionScript. Au long de ce tuto nous appellerons cet identifiant : nom de liaison.

Image utilisateur

Une fois le clip créé, il apparaît dans la bibliothèque où tous les clips sont classés par ordre alphabétique suivant leur nom de bibliothèque.

Image utilisateur

Vous pouvez ensuite glisser un clip sur la scène ce qui va créer une occurrence de ce clip.

Il peut y avoir un nombre virtuellement infini d'occurrences d'un même clip. Et chaque occurrence possède un nom d'occurrence que vous devez assigner dans les propriétés de l'occurrence. Pour cela vous devez sélectionner l'occurrence du clip et aller changer la zone Nom de l'occurrence dans l'onglet Propriétés.

Image utilisateur

Chaque occurrence de clip peut contenir d'autres occurrences d'autres clips (mais pas de lui même). On retrouve une structure arborescente. Le premier de tous les clips, c'est à dire celui qui contient tous les autres, est appelé dans ce tuto scène principale ou encore par son petit nom : _root

Pour rentrer dans un clip : vous double-cliquez dessus.
Pour sortir d'un clip : vous double-cliquez dans une zone vide.
Vous savez en permanence où vous êtes en regardant le scénario, par exemple dans l'image ci-dessous, je suis dans une occurrence de a_monclip qui est lui même dans une occurrence de c_monclip qui est lui-même dans la scène principale !

Image utilisateur

Notion de "clip" Les zones de texte

Les zones de texte

Créer un clip La solution pratique

Les zones de texte

Deux notions à comprendre pour la suite du cours. Nous avons vu que quand je vous demanderai de nommer un clip, je parlerai toujours de son nom d'occurrence. Une occurrence d'un clip possède un nom d'occurrence qui permet d'y accéder par ActionScript, il possède aussi comme nous l'avons vu un nom dans la bibliothèque qui n'a aucune utilité en ActionScript, ainsi qu'un nom de liaison que nous étudierons plus tard.

Il existe trois types de zone de texte :

Nom d'occurrence d'une zone de texte

Les zones de texte, à l'instar des clips, possèdent un nom d'occurrence, qu'on peut modifier exactement de la même façon (sauf pour les zones de texte statiques qui n'ont pas besoin d'identifiant).
Je le rappelle, vous pouvez le modifier ici :

Image utilisateur
Les zones de texte

Les champs de texte possèdent aussi une variable associée. Cette variable permet d'accéder au contenu textuel de la zone de texte.
On peut modifier cette variable comme cela :

Image utilisateur

Créer un clip La solution pratique

La solution pratique

Les zones de texte Ma première animation !

La solution pratique

Comme vous l'avez vu : c'est un peu le bordel. :euh:

Donc nous on va simplifier tout ça grâce à quelques conseils simples :

Jamais de code sur un clip tu ne mettras.
En effet, ça complexifie énormément la gestion du code, et la façon de coder sur un clip diffère de celle dans un clip.

Toujours dans la scène principale _root tu coderas.

Alors là, c'est quand même fort ! On peut mettre du code où on veut, et toi tu nous dis de ne le mettre que dans la scène principale !

Mais non, vous allez voir, ça va vous simplifier la vie ! Parce que comme cela, vous aurez tout votre code au même endroit !

Sur la scène principale, un calque "action" tu créeras, où tout ton code tu mettras.
Eh oui, non seulement on va mettre tout le code sur la scène principale, mais en plus on le mettra dans un calque à part. ActionScript se fiche royalement des calques, on pourrait donc mettre le code n'importe où : ça ne changerait rien. C'est juste une question de propreté de mettre toujours son code dans un endroit facilement accessible.

Ces 3 conseils de base sont très très importants, et j'essayerai (je dis bien "essayerai") de m'y tenir dans mes tutoriels. :D

Alors, il était facile ce QCM, non ? ;)


Les zones de texte Ma première animation !

Ma première animation !

La solution pratique Un nouveau document

Nous allons créer votre toute première animation avec un soupçon d'ActionScript. Je vous guiderai surtout pas à pas avec un maximum d'images pour que vous ne vous perdiez pas.
Ce premier tuto vous permettra donc de vous familiariser de façon concrète avec Macromedia Flash 8.

Un nouveau document

Ma première animation ! Dessine moi une balle

Un nouveau document

Commencez par ouvrir Flash. :)

Nouveau document

Si vous n'avez pas devant vous une nouvelle scène vierge, nous allons nous même créer une nouvelle animation.
Allez donc dans Fichier->Nouveau...
Cette boîte de dialogue devrait s'ouvrir :

Image utilisateur

Sélectionnez Document Flash dans la liste si ce n'est pas déjà fait, puis cliquez sur OK.

Propriétés du document

Normalement, en cliquant sur un espace vide de votre scène, vous devriez avoir un panneau Propriétés ressemblant à celui ci-dessous :

Image utilisateur

Il contient plusieurs informations importantes sur votre animation. Déjà vous trouvez sa taille. Ça tombe bien, j'aimerais bien la réduire un peu. Cliquez donc sur le bouton indiquant la taille de l'animation pour ouvrir la boîte de dialogue suivante :

Image utilisateur

Vous pouvez mettre un titre si vous le souhaitez, je me suis contenté de mettre 300pixels en largeur et 100pixels en hauteur pour mon animation.
Si vous le désirez vous pouvez aussi changer la couleur d'arrière-plan pour des tonalités plus exotiques. :p


Ma première animation ! Dessine moi une balle

Dessine moi une balle

Un nouveau document Interpolation de mouvement

Dessine moi une balle

Dessine moi une balle

Sélectionnez dans la barre d'outils à gauche l'outil ovale :

Image utilisateur
Image utilisateur

Ensuite avant de dessiner votre balle, choisissez les couleurs qui vous plaisent.

La couleur du haut, avec le petit crayon à côté, représente la couleur de la bordure de votre futur cercle. Dans notre exemple nous prendrons un bleu foncé.

La couleur du bas, avec le seau de peinture à côté, représente la couleur de remplissage, c'est à dire de l'intérieur de votre cercle. Prenez un bleu clair/turquoise. ;)

Maintenant, vous pouvez dessiner votre ovale sur la scène, si vous enfoncez la touche Majuscule pendant que vous tracez l'ovale, celui-là deviendra un cercle. :)

Voilà à quoi ressemble notre balle :

Image utilisateur
Lui mettre un numéro
Image utilisateur

On va dessiner un petit numéro sur notre balle. Il faut donc utiliser l'outil texte juste au dessus à droite de l'outil ovale qu'on vient d'utiliser. Il est représenté par un A majuscule.

Vous pouvez alors écrire un 1 sur la balle, comme ci-dessous :

Image utilisateur

Sélectionnez votre champ de texte, vous pouvez modifier ses propriétés en bas. Comme dans n'importe quel éditeur de texte, vous pouvez choisir une police, une taille, une couleur... Je pense que vous êtes en terrain connu !

Image utilisateur
Transformation !

Par la suite, je voudrais que la balle puisse bouger sur la scène pendant l'exécution de l'animation. Une forme ne peut pas bouger, on va donc devoir transformer notre balle en symbole !

Sélectionnez donc la forme plus la zone de texte, et cliquez sur Modification->Convertir en symbole (ou faites F8 tout simplement).

Image utilisateur

Ici, un simple graphique suffira pour ce que nous voulons faire ! Cliquez sur OK.


Un nouveau document Interpolation de mouvement

Interpolation de mouvement

Dessine moi une balle Un soupçon d'ActionScript

Interpolation de mouvement

Imaginez que vous ayez un clip dans une position à un moment puis dans une autre plus tard, et que vous vouliez créer une transition entre les deux états ? Oui, vous avez deviné, c'est l'interpolation de mouvement qui va s'occuper de ça !

Placez votre graphique "balle" tout à gauche de votre animation.
Votre scénario devrait ressembler à ça pour l'instant :

Image utilisateur

Il n'y a qu'une seule image clé, nous allons en créer une seconde en position 10.
Pour cela, cliquez sur la case 10 avec le bouton droit de la souris et cliquez sur Insérer une image-clé.
Voilà à quoi ressemblera votre scénario :

Image utilisateur

Pour l'image-clé 1, laissez votre balle à gauche de la scène. Pour l'image-clé 10 mettez la balle complètement à droite.

Maintenant, cliquez avec le bouton droit sur l'espace grisé entre les deux images-clés, et dans le menu sélectionnez Créer une interpolation de mouvement. L'espace devrait devenir bleu avec une flèche continue, comme ci-dessous :

Image utilisateur

Si vous appuyez sur Entrée, vous pourrez voir le déplacement de la balle de gauche à droite ! :D

Tester l'animation

Flash possède un outil complet pour tester votre animation. Pour compiler puis prévisualiser l'animation, vous pouvez soit cliquer sur Contrôle->Tester l'animation soit utiliser la combinaison de touches Ctrl+Entrée.

Image utilisateur

Comme vous pouvez le constater, la lecture de l'animation se fait en boucle. ;)


Dessine moi une balle Un soupçon d'ActionScript

Un soupçon d'ActionScript

Interpolation de mouvement Fil rouge

Un soupçon d'ActionScript

Il serait dommage de ne pas parler d'ActionScript dans ce chapitre d'introduction. Je vais donc montrer les deux, trois trucs à absolument connaître.

Arrêter la lecture

On va voir comment arrêter la lecture en boucle de l'animation. Placez-vous sur la dernière image-clé (en position 10).

Ouvrez le panneau Action en haut de votre IDE si vous l'avez placé comme moi.
C'est là que l'on va taper notre code :

Image utilisateur

Tapez ce code tout simple ;) :

stop();

Et lancez votre animation (Ctrl+Entrée).
Vous devriez voir que la balle arrête sa course une fois à droite.

C'est normal, stop() est une fonction d'ActionScript qui arrête la lecture de l'animation. Vous remarquez aussi que la ligne se termine par un ;

Pour l'instant, ne vous attardez pas sur les détails, ça sera le contenu des prochains chapitres. Essayez seulement de retenir comment on écrit du code et de comprendre son domaine d'action.

Un bouton pour la suite

Créez un second calque "Action" dans votre scénario et créez une seconde image-clé aussi en position 10.

Image utilisateur

Vous remarquez au passage la présence du petit a sur l'image-clé où nous avons écrit le code.

Supprimez le stop(); de là où il est, et mettez le sur l'image-clé 10 du calque "Action", car c'est là que nous mettrons tout le code.

Image utilisateur

Bien entendu, cette manipulation n'a strictement rien changé dans l'animation. Elle permet juste de centraliser le code pour une meilleure organisation.

Sélectionnez l'image-clé 10 du claque "Action" et dessinez sur la scène un petit carré.

Image utilisateur

Transformez ce carré en bouton :

Image utilisateur

Puis retournez sur la scène principale en double-cliquant sur un espace vide de la scène.
Et donnez à ce bouton un nom d'occurrence, en le sélectionnant puis en allant regarder dans ses propriétés. Appelez le : monbouton

Image utilisateur

Maintenant, allez dans l'onglet Action où vous aviez déjà écris stop();.
En dessous rajoutez ce code :

monbouton.onRelease = function() {
        play();
};

Vous ne pouvez pas encore comprendre tout le code. Sachez que monbouton.onRelease va exécuter le code entre les crochets { } quand on cliquera sur monbouton.
Entre les crochets on a la fonction play() que vous devez connaître, qui va reprendre la lecture de l'animation.

En gros, ce qui se passe si vous exécutez l'animation :
- lecture de l'animation
- arrêt à l'image 10 car rencontre du stop();
- apparition du bouton rouge car positionné sur une image-clé en position 10
- si on clique sur le bouton, exécution de play(), qui reprend la lecture. :D

Voilà, c'est tout pour ce court, mais très imagé, mini-tuto.
Ce que vous devez avoir absolument retenu, c'est comment écrire du code dans Flash !
Vous devriez aussi savoir, de façon très rapide et sans explication, créer un nouveau symbole : graphique, bouton ou clip. Je ne l'expliquerai plus. ;)


Interpolation de mouvement Fil rouge

Fil rouge

Un soupçon d'ActionScript Cahier des charges

Et voilà le début de notre Fil Rouge, à savoir l'élaboration de petites animations incluant les fonctionnalités les plus usuelles utilisant la technologie Flash. :D

Si vous avez bien suivi les deux précédents tutoriels, nous avons en gros deux possibilités :
- soit un site uniquement en Flash
- soit un site constitué de pages Web Xhtml classiques avec intégration d'objets Flash.

Et bien certains seront peut-être déçus, mais pour des raisons bassement pédagogiques, on va prendre la deuxième solution. :) Mais ne me huez pas ! :p
Car si un site tout en Flash empêche l'intégration d'éléments Xhtml (ou du moins presque, nous verrons cela par la suite), un site en Xhtml classique n'empêche pas l'intégration d'applications Flash complètes. Il vous suffira alors d'extrapoler un peu le cours pour faire votre site Flashocentriste. :D

Cahier des charges

Fil rouge Architecture globale

Cahier des charges

Eh oui, comme dans tout projet qui se respecte, la première chose à faire est la laborieuse et lassante, mais néanmoins inévitable, rédaction du célèbre cahier des charges. ;)

Définition du cahier des charges (pour nos Zéros analphabètes comme leurs pieds :D ) :
Document qui décrit en terme de fonctions, d'aptitudes de qualité ce que l'on attend d'un produit.

C'est plus clair pour tout le monde ? Ça reste tout de même très théorique.

On va donc dans un premier temps rédiger tout ce que nous allons demander à nos petites animations :

L'ordre dans lequel on va le faire est l'ordre dans lequel je l'ai écrit, et vous allez voir que vous allez vite progresser. :)


Fil rouge Architecture globale

Architecture globale

Cahier des charges Variables et fonction trace()

Architecture globale

On a le cahier des charges, alors maintenant il va falloir se demander comment on va agencer tout ça d'un point de vue liaisons entre interface (=côté utilisateur) et serveur.

Le Logo

Le logo ne nécessite aucune donnée externe, ce sera donc une bête animation flash sans liaison.
Il faudra penser à l'intégrer en haut de chaque page grâce à la fonction include() de PHP.

Un jeu de voiture basique

Ça sera un tout petit jeu vraiment basique, mais il permettra une première synthèse de vos connaissances en les utilisant toutes dans un projet comportant quelques lignes de codes. :D

Un lecteur Mp3

Dans le cas d'une playlist de dizaines de Mp3, Flash va devoir se débrouiller lui même pour aller chercher d'abord la liste des musiques, puis ensuite les charger bien entendu pour pouvoir les écouter. :D
Il faudra donc prévoir une page PHP qui sera appelée par l'application Flash et qui retournera une Playlist.

Une galerie d'images

Bon, à priori pas de grandes différences entre un lecteur mp3 et une galerie d'images... Sauf que les musiques du lecteur sont présentées sous la forme d'une liste textuelle, alors que dans une galerie il faudra afficher des miniatures.
Et pour la déconnade, on fera vite fait un script d'upload des images conjuguant PHP côté serveur et la toute nouvelle fonction d'upload de Flash côté client (aïe va falloir que je me documente, je connais pas encore :p ).

Le Mini-jeu

Vous l'attendiez : vous l'avez !
Le mini jeu permettra une synthèse de vos connaissances. Il nous faudra donc une bonne idée de jeu sympathique et un système de high-score (pour toute idée de jeu sympa et pas trop dure à réaliser, envoyez moi un MP ou laissez un commentaire).

Voilà, on a donc une idée des liaisons que chaque application Flash nécessitera. :)

Schéma fonctionnel des liaisons :

Image utilisateur

Dans ce chapitre, nous avons donc délimité les champs d'application de Flash, et nous avons vu d'un point de vue très théorique ce qu'allait être notre travail tout au long de notre Fil Rouge


Cahier des charges Variables et fonction trace()

Variables et fonction trace()

Architecture globale Structure et commentaires

Nous allons regarder sur des exemples simples comment fonctionnent les variables en AS 3.0

Structure et commentaires

Variables et fonction trace() Fonction trace()

Structure et commentaires

Tout langage informatique repose sur la gestion des variables, AS ne déroge pas à la règle.
Les variables sont là pour qu'on leur affecte des valeurs, numériques, textuelles, graphiques, ...
Il faut aussi savoir que chaque instruction en AS se termine par un ; ce qui permet de préciser à l'interpréteur AS que la ligne est finie, et qu'une nouvelle instruction commence.

En AS 3.0, il est obligatoire de déclarer les variables, ce qui était très optionnel à l'époque de l'AS 1.0. Il est aussi nécessaire de faire attention aux majuscules et minuscules, car l'AS est sensible à la casse. Ainsi si vous écrivez mavar et Mavar, Flash comprendra deux instructions différentes.
Voilà comment attribuer la valeur 5 à la variable mavar

var mavar = 5;

Vous noterez que c'est l'opérateur = qui permet d'attribuer une valeur à une variable. On l'appelle opérateur d'assignement : il assigne la valeur de droite à la variable de gauche. :)

Vous constatez aussi qu'il est tout à fait autorisé en AS d'ajouter des espaces entre les différentes expressions, ainsi tous ces codes reviennent au même :

var mavar = 5;
var mavar=5;
var mavar= 5 ;

Autre point important, il est possible de commenter votre code, et c'est même recommandé.
Deux techniques possibles, utiliser /* mon commentaire */ sur plusieurs lignes ou // mon commentaire sur une seule ligne.

var mavar = 5; // On assigne 5 à mavar
/* Je blablate sur
plusieurs lignes */

Variables et fonction trace() Fonction trace()

Fonction trace()

Structure et commentaires Les numériques : int et Number

Fonction trace()

Avant de faire quoique ce soit il faut que je vous présente la fonction trace(). C'est, à mon sens, la fonction la plus utile de AS ;)
Grâce à elle vous pourrez aisément construire, vérifier et déboguer vos scripts. trace() va nous permettre de savoir à tout moment ce qu'il y a dans nos variables !

Pour commencer créez un nouveau fichier Flash et tapez dans l'onglet action :

trace("Hello World !");

Si vous exécutez cette animation (Ctrl+F11), vous constaterez que Flash ouvre une fenêtre nommée Sortie. C'est dans cette fenêtre que s'affichera le contenu de tous les arguments que vous passerez à la fonction trace.

Abordons dans la suite les trois types de variables les plus simples !


Structure et commentaires Les numériques : int et Number

Les numériques : int et Number

Fonction trace() Les chaines de caractères : String

Les numériques : int et Number

Type int

int est la contraction du mot anglais integer se traduisant par entier en français. Pour les moins aguerris d'entre vous en mathématiques, les nombres entiers sont les nombres de la forme ... -4, -3, -2, -1, 0, 1, 2, 3, 4 ...

En mathématiques, il y en a bien entendu une infinité, mais nos pauvres ordinateurs auront du mal pour aller si loin ;) Le type int peut en fait stocker tous les nombres entre - 2 147 483 648 (-231) et 2 147 483 647. En clair on a de la marge :D

Voici trois possibilités pour déclarer notre variable de type int et pour lui donner une valeur (bien entendu ne mettez pas les trois lignes d'un coup dans Flash, mais l'une après l'autre) :

var monEntier:int = new int(123); // La totale
var monEntier:int = 123;          // Plus court
var monEntier     = 123;          // Trop court

Comment est-il possible que la troisième ligne fonctionne alors qu'on ne précise pas le type de la variable ? En fait, Flash va détecter tout seul que 123 est un nombre et va lui même rajouter le :int. Malheureusement, dans certain cas, il risquerait de choisir un type qui ne convient pas : bref vous l'avez compris, on va préférez la solution intermédiaire :)

var monEntier:int = 666;
trace(monEntier);                 // Affiche 666 dans la fenêtre Sortie

Voyons ce qu'on peut faire avec ces variables...
Commençons avec les opérations simples :

var monEntier:int = 10;      //On déclare monEntieret on lui assigne 10 comme valeur
monEntier = monEntier + 5;    // on rajoute 5 à la variable
trace(monEntier)             // ce qui donne ... 15 !

monEntier = 10;              // Une fois déclarée, surtout ne pas remettre :int !
monEntier = monEntier - 5;   // En toute logique ...
trace(monEntier)             // ... ca donne 5

monEntier = 10;               // Remettons encore à 10 la variable
monEntier = monEntier * 5 ;   // on multiplie par 5 la variable
trace(monEntier)              // affiche 50

monEntier = 10;               // Remettons encore à 10 la variable
monEntier = monEntier / 2 ;   // On divise par 2
trace(monEntier)              // affiche 5

monEntier = monEntier / 2 ;   // On divise encore par 2
trace(monEntier)              // affiche ... 2 !!!

Mais, mais, mais ... :o Comment 5/2 peut-il faire 2 ?
Souvenez-vous, monEntier est une variable qui est typée int. Le résultat de la division doit donc être converti en entier avant d'être stocké dans monEntier. Pour cette conversion, Flash fait simple : il prend les chiffres qui sont avant la virgule !

var monEntier:int = 1.6;
trace(monEntier);            // Renvoie 1
monEntier = -1.6;
trace(monEntier);            // Renvoie -1

Il existe d'autres opérateurs très intéressants, il permettent d'éviter de répéter monEntier dans le membre de droite.
Prenons un exemple :

var monEntier:int= 10;
monEntier += 5;           // Ca revient au même que monEntier = monEntier + 5;
monEntier *= 5;           // Même chose que monEntier = monEntier * 5;

Ça va quand même plus vite, non ? :D
Bien entendu vous trouverez aussi les opérateurs -= et /=, opérateurs d'affectation de soustraction et d'affectation de division.

Type Number

Nous avons vu comment enregistrer des entiers (naturels et relatifs), malheureusement beaucoup de quantités s'expriment avec des chiffres après la virgule dont les nombres décimaux (ceux avec un nombre fini de chiffres après la virgule). Le type correspondant à ces derniers est Number.

Bien entendu, tous les opérateurs vus jusque là s'appliquent encore :

var monDecimal:Number = 5;
monDecimal /= 2;             // On divise 5 par 2
trace(monDecimal);           // et miracle, on trouve 2.5 !

Fonction trace() Les chaines de caractères : String

Les chaines de caractères : String

Les numériques : int et Number Les tableaux : Vector

Les chaines de caractères : String

Le type String permet d'enregistrer des chaînes de caractères, c'est-à-dire du texte.

Déclarons un String, comme toujours dans l'ordre du plus académique au plus fainéant :D

var maChaine:String = new String("Salut la compagnie"); // Académique
var maChaine:String = "Salut la compagnie";             // Pratique
var maChaine        = "Salut la compagnie";             // indécent ;)

Pour les nombres, nous avions des opérateurs mathématiques permettant d'effectuer des calculs.
Ici pas de maths (snifff :( ), mais un opérateur de concaténation. La concaténation permet de "coller" deux chaînes de caractères, en Flash on utilise le +.

Exemple :

var maChaine:String = "";              // On ne met rien pour l'instant
maChaine = "Salut" + " la compagnie";  // On concatène
trace(maChaine);                       // Ce qui donne "Salut la compagnie"

On aurait aussi pu donner la valeur "Salut" à machaine puis rajouter le reste après :

var maChaine:String = "Salut";
maChaine += " la compagnie";

Supposons maintenant que vous vouliez mettre dans votre texte le caractère ". Ça risque d'être embêtant puisqu'on l'utilise déjà comme caractère délimitant la chaîne...
Encore une fois, on a plusieurs solutions.

On peut utiliser le caractère d'échappement\, en le plaçant devant le guillemet à échapper. On aurait donc :

var maChaine:String = "Il m'a dit \"Bonjour !\" ";

Ou alors on peut utiliser l'apostrophe pour délimiter le texte, dans ce cas là il faudra échapper les apostrophes ;) :

var maChaine:String = 'Il m\'a dit "Bonjour !" ';

Une petite question pour vous, que se passe-t-il si j'exécute le code suivant ?

var maChaine:String = "Vive le pastis ";
var monEntier:int = 51;
maChaine = maChaine + monEntier;
trace(maChaine);

Comme Flash est malin, il va convertir automatiquement le type monEntier en chaine de caractères puis fait la concaténation. Cela-dit, il aurait été possible de faire cette opération explicitement grâce à la méthode toString() qui permet de convertir un nombre en texte :

var maChaine:String = "Vive le pastis ";
var monEntier:int = 51;
maChaine = maChaine + monEntier.toString();
trace(maChaine);

Ne vous inquiétez pas si vous ne comprenez pas toute la syntaxe, nous y reviendrons :)


Les numériques : int et Number Les tableaux : Vector

Les tableaux : Vector

Les chaines de caractères : String MovieClip

Les tableaux : Vector

Créer un objet Vector contenant des entier :

var monVecteur:Vector.<int> = new Vector.<int>(); // Déclaration et instanciation de notre vecteur contenant des entiers

Comme vous pouvez le constater, la création de l'objet utilise une syntaxe particulière qui permet de préciser le type des données qui seront contenues dans le vecteur.

La construction de l'instance peut en fait être plus détaillée, puisqu'il est possible de préciser si le vecteur doit être fixé (c'est à dire si le nombre total d'éléments qu'il peut contenir doit être limité) :

var monVecteur:Vector.<int> = new Vector.<int>(10, true); // On créé un vecteur étant limité à 10 entiers

Comment affecter des valeurs aux cellules du tableau ?

Dans tous les cas, la syntaxe avec les crochets [] fonctionne :

var monVecteur:Vector.<int> = new Vector.<int>(3, true);
monVecteur[0] = 5;
monVecteur[1] = 10;
monVecteur[2] = 15;
trace(monVecteur);

Dans le cas des vecteurs à taille variable, il est possible d'utiliser la méthode push() qui rajoute un élément à la fin :

var monVecteur:Vector.<int> = new Vector.<int>();
monVecteur.push(5);
monVecteur.push(10);
monVecteur.push(15);
trace(monVecteur);

Comment connaître le nombre d'entrées dans un tableau ?

Il vous faut utiliser la propriété length

var monVecteur:Vector.<int> = new Vector.<int>();
monVecteur[0] = 5;
monVecteur[1] = 10;
monVecteur[2] = 15;
trace(monVecteur.length); // Affiche 3

On remarquera que dans le cas d'un tableau dont la taille est fixée, la longueur est constante. Même si des cellules sont vides, elles existent quand même !

var monVecteur:Vector.<int> = new Vector.<int>(3, true);
trace(monVecteur.length); // Affiche 3 quand même !

Comme vous avez pu le constater dans cette partie, l'AS 3.0 diffère assez peu pour des exemples aussi simples des langages modernes comme Java ou C#.
Je ne peux donc que vous conseiller de souvent visiter l'aide, qui vous permettra de vous en sortir souvent sans aller demander du secours sur les forums. :p


Les chaines de caractères : String MovieClip

MovieClip

Les tableaux : Vector _root , this et _parent

Les MovieClip étaient les structures de bases de Flash à l'époque de l'AS 1.0 ainsi qu'en 2.0. Maintenant il pourrait presque s'agir d'une classe comme une autre, cependant en connaissant quelques-unes de ses propriétés nous allons pouvoir très rapidement nous amuser avec Flash :D

_root , this et _parent

MovieClip Positionnement

_root , this et _parent

_root

Nous avons déjà vu dans le premier chapitre que le clip parent à tous les autres clips, qu'on appelle la scène principale, se nommait _root.

Maintenant que nous avons quelques notions d'ActionScript, intéressons-nous à la signification de ce _root.

var monnombre:Number = 10;
trace(monnombre);
trace(_root.monnombre);

La fenêtre de sortie va vous afficher deux fois 10.
Cela signifie que sur la scène principale, _root.monnombre = monnombre
C'est logique, puisque vu qu'on est dans _root, on a pas besoin de le repréciser !

Le . entre _root et monnombre, permet de dire au compilateur que l'un est inclus dans l'autre. En effet la variable appartient à l'objet _root (en Mathématiques on parlerait d'ensemble).

Maintenant, on va faire une chose ignoble, mais nécessaire à l'apprentissage : on va mettre du code dans un clip ! :p

Créez une nouveau clip, mettez-le sur la scène principale et nommez le monclip (oui, je sais, l'originalité n'est pas mon fort :-° et au passage, je précise que je parle de son nom d'occurrence).

Allez dans une image clé de ce clip (double-cliquez sur le clip), et tapez dans l'onglet action :

trace(" monnombre => "+monnombre);
trace(" _root.monnombre => "+_root.monnombre);

Et laissez seulement ça sur la scène principale :

var monnombre:Number = 10;

Voyons ce que nous affiche la fenêtre de sortie :

monnombre => undefined

 _root.monnombre => 10

Et là on constate en effet qu'essayer d'afficher la variable qui est déclarée dans _root, mais pas dans le clip, ne fonctionne pas si on ne précise pas que cette variable se trouve sur _root. Le undefined signifie que la variable n'est pas définie, car elle n'existe pas dans le clip monclip.

En clair, la variable monnombre existe dans _root.
Mais elle n'existe pas dans _root.monclip.
Pour y accéder à partir de _root.monclip, il faut préciser où elle se trouve : _root.monnombre.

this

Voilà une propriété que nous allons TOUT LE TEMPS utiliser.

this permet de préciser au compilateur qu'on travaille sur l'objet qui contient le script.

Bah, ça sert à rien, il suffit de rien mettre ! o_O

Souvent, en effet, this est optionnel. Mais vous verrez par la suite, quand on abordera les évènements, que cette propriété se révèle fort utile, pour préciser au compilateur que malgré que le code soit dans _root, il s'applique à un autre clip.

Il est en effet possible d'écrire du code dans l'onglet action de _root qui se rapporte pourtant à un autre clip. Dans ce cas, si on ne met pas this, la variable appartiendra à _root, et si on précise this, la variable appartiendra au clip dont on parle (pour l'instant c'est normal que ça vous paraisse abstrait, nous prendrons des exemples par la suite).

_parent

_parent, renvoie au clip parent.

Et si on reprend l'exemple précédent, en remplaçant le _root.monnombre par this._parent.monnombre, que se passera-t-il ?

Et bien ça fonctionnera ! :D En effet le clip parent de _root.monclip c'est la scène principale (_root).

Vous vous demandez peut-être si _root._parent.monnombre fonctionnerait ? La réponse est : non. En effet, il n'existe pas de niveau "en dessous" de root. _root._parent renvoie donc à un objet qui n'existe pas !

_parent devient donc intéressant en cas d'imbrication d'un clip, dans un clip, dans un clip ...
Et c'est pour éviter d'utiliser cette propriété en spaghetti qu'on met tout le code au même endroit. ;) En effet, si vous commencez à mettre du code un peu partout dans des clips, vous devrez utiliser _parent plus souvent, et votre code deviendra rapidement incompréhensible, aussi mal "ordonné" qu'un plat de spaghettis. :p


MovieClip Positionnement

Positionnement

_root , this et _parent Taille absolue

Positionnement

Maintenant que nous savons comment accéder aux clips, nous allons apprendre à manipuler leurs propriétés, commençons par les propriétés _x et _y des clips, qui permettent de positionner un clip au pixel près sur la scène.

Positionnement d'un clip sur _root

Dans un nouveau document créez un nouveau clip que vous nommerez dans l'onglet propriétés monclip (ce qui nous intéresse ici c'est le nom d'occurrence du clip, pas son nom dans la bibliothèque qui lui ne sert à rien en ActionScript. Mais ça vous le savez déjà ;) allez voir ici pour un rapide rappel).
Tapez dans l'onglet action (si je ne donne pas d'indication c'est que le code doit être placé dans la scène principale) :

monclip._x=0;
monclip._y=0;

En exécutant l'animation vous verrez que le clip se placera en haut à gauche de l'écran.

Pour ceux qui n'auraient pas compris, la syntaxe à point permet de séparer le nom du clip de sa propriété, ici on utilise deux propriétés du clip. Sa position sur l'axe horizontal (axe des abscisse) est la propriété _x et _y est sa position sur l'axe vertical (axe des ordonnées).

Image utilisateur

Voilà un petit schéma simple expliquant comment Flash et la plupart des langages que je connaisse conçoivent le placement d'un clip dans un plan, c'est-à-dire sur l'écran.

Vous pouvez ainsi donner n'importe quelle position au clip que vous souhaitez en utilisant ce système.

Positionnement d'un clip dans un autre

Complexifions un petit peu la chose, entrez dans le clip monclip et créez à l'intérieur un second clip que vous nommerez clipdansleclip.

Maintenant retournons dans le code et voyons comment faire pour bouger ce clip à l'intérieur de l'autre.

monclip._y = 50;
monclip._x = 50;
monclip.clipdansleclip._y = 25;
monclip.clipdansleclip._x = 50;
Image utilisateur

A votre avis, où va être placé le clip clipdansleclip ?
Eh bien, il sera à 50 pixels à droite du point d'ancrage de monclip.
Et monclip lui même sera à 50 pixels à droite du point d'ancrage de la scène principale.

Donc par rapport au point d'ancrage de la scène principale, le clip clipdansleclip sera à 50+50=100 pixels à droite et à 75 pixels vers le bas.


_root , this et _parent Taille absolue

Taille absolue

Positionnement Agrandissement

Taille absolue

Les clips possèdent aussi les propriétés _width et _height (respectivement largeur et hauteur en français).
Ces propriétés permettent d'indiquer la taille des clips en pixels. Le clip sera alors redimensionné par le lecteur Flash.
N'oubliez pas que _width représente la largeur sur l'axe horizontal. Et donc que la hauteur _height correspond à l'axe horizontal.

Reprenez l'exemple précédent, et rajoutez :

monclip._width = 300; // Largeur : 300px
monclip._height = 100; // Hauteur : 100px

Comme vous le constatez, la figure devient très allongée.
Si on voulait rendre le clip carré, il suffirait de prendre la même largeur et hauteur :

monclip._width = 100; // Largeur : 100px
monclip._height = 100; // Hauteur : 100px

Voilà, le clip est carré.

Imaginons maintenant que nous voulions agrandir le clip de façon à garder ses proportions, c'est-à-dire conserver le rapport largeur/hauteur d'origine.

Il faudrait alors suivre cette bête règle de trois :

_width/*de départ*/ / _height/*de départ*/ = _width/*d'arrivée*/ / _height/*d'arrivée*/

Il s'agit là d'une équation qui n'a rien de mathématique, arrangeons-la pour que Flash la comprenne. Prenons l'exemple d'une boîte de largeur 100px et de hauteur 50px. Nous voulons que cette boîte deviennent large de 200px, en conservant les proportions. On cherche donc la hauteur (x sur le schéma) qu'on va devoir lui donner pour conserver ce rapport.

Image utilisateur

Bon là, c'est facile, on voit qu'il suffit de multiplier par deux, mais dans des cas plus complexes, voilà le code qui permettrait d'assigner la bonne hauteur à monclip :

monclip._height = 200*monclip._height/monclip._width;

Vous avez donc brièvement vu comment assigner une taille absolue à un clip, et même comment conserver ses proportions lors d'un agrandissement.


Positionnement Agrandissement

Agrandissement

Taille absolue Rotation

Agrandissement

Pourquoi s'embêter avec des calculs pour conserver la proportion d'une image ou d'un clip ? Utilisons les propriétés _xscale et _yscale.

Ces deux propriétés permettent d'agrandir en pourcentage un clip sur l'axe horizontal _xscale ou vertical _yscale.

La valeur d'origine pour un clip est _xscale = _yscale = 100 puisque l'agrandissement se fait en pourcentage.

Reprenez l'exemple précédent, supprimez tout le code et tapez :

trace("Agrandissement horizontal avant changement : "+monclip._xscale); // Affiche 100
monclip._xscale = 200; // on agrandit 2 fois en longueur le clip (100*2=200)
trace("Agrandissement horizontal après changement : "+monclip._xscale); // Affiche 200

Intéressant, n'est-ce pas ? :D
Maintenant, réduisons ce clip en conservant ses proportions, c'est-à-dire que son agrandissement horizontal et vertical doivent être les mêmes.

monclip._xscale = 50; // on réduit la taille de moitié (100 / 2 = 50)
monclip._yscale = monclip._xscale; // on conserve les proportions

On peut encore plus compresser ce code comme ça :

monclip._xscale = monclip._yscale = 50;

Taille absolue Rotation

Rotation

Agrandissement Transparence

Rotation

Avant dernière propriété que nous allons étudier : _rotation

_rotation s'exprime en degrés, et ses valeurs vont de -180 à 180 degrés. Si vous donnez une valeur supérieure, Flash fera la transformation qu'il faut pour que ça tombe juste.
En effet n'oubliez pas qu'une rotation de 360° équivaut à une rotation de 0 degré, puisque 360° c'est un tour complet.

Reprenons encore et toujours l'exemple précédent, mais je vous conseille de mettre une photo dans le clip, pour mieux voir l'effet de _rotation en faisant Ficher->Importer->Importer dans la scène quand vous êtes en train d'éditer le clip.
Supprimez tout le code précédent, et essayez les différents codes suivants ligne après ligne (ne mettez pas tout d'un coup, sinon, seule la dernière ligne aura un effet ;) ) :

monclip._rotation = 180 ; // On le retourne complétement
monclip._rotation = 90 ; // La tête en bas
monclip._rotation = -90 ; // La tête en haut
monclip._rotation = 45 ; // En biais

C'est bien beau tout ça, mais on va passer à plus complexe et surtout à plus utile ! On va demander à notre clip d'effectuer une rotation dans la direction d'un autre clip :D

Pour ce faire, créez une nouvelle scène, un clip monclip et un clip cible, mettez ce que vous voulez dedans.

Image utilisateur

Tapez ce code :

_root.monclip._rotation = Math.atan2(_root.cible._y-_root.monclip._y, _root.cible._x-_root.monclip._x)/(Math.PI/180);

Et si vous exécutez l'animation, vous devriez obtenir cela :

Image utilisateur

Bon expliquons cette petite formule. :p
_root.cible._y-_root.monclip._y => renvoie la distance verticale entre les deux clips
_root.cible._x-_root.monclip._x => renvoie la distance horizontale entre les deux clips
La fonction Math.atan2 inclue dans Flash, va renvoyer l'angle que le clip doit adopter en Radians. Or on cherche cet angle en degrés.

La classe Math de Flash contient non seulement cette magnifique fonction atan2, mais aussi la valeur approchée de pi : Math.PI

Surtout gardez cette formule dans un coin, elle nous servira par la suite. :D
Si vous ne l'avez pas compris, ce n'est pas bien grave. Mais suivez bien vos cours de Maths qui parlent de trigonométrie et vous devriez en saisir le fonctionnement !


Agrandissement Transparence

Transparence

Rotation Visibilité

Transparence

Dernière des propriétés importantes que nous allons voir dans ce chapitre : _alpha

Flash est souvent utilisé pour ses effets visuels dynamiques. Or en voici un bien pratique : la transparence !

_alpha détermine la transparence d'un clip :

Allez faites donc quelques tests vous même. ;) Je suis sûr que vous avez compris le truc.


Rotation Visibilité

Visibilité

Transparence Les Conditions

Visibilité

Une propriété très intéressante : _visible
Vous pouvez lui assigner la valeur true (le clip est visible) ou false (le clip est invisible).

Par exemple :

monclip._visible = false; //Le clip va devenir invisible

Quelle est alors la différence entre _visible=false et _alpha=0 ?

En fait non seulement _visible peut rendre un clip invisible comme le ferait _alpha, mais en plus il désactive le clip. Imaginez un bouton sur la scène principale, si vous utilisiez _alpha=0, alors le clip serait invisible mais vous pourriez encore cliquer dessus. Mais si vous utilisez _visible=false alors le clip deviendra invisible et en plus il deviendra impossible de cliquer dessus.


Transparence Les Conditions

Les Conditions

Visibilité Un nouveau type : Boolean

Les conditions sont à la base de tout langage de programmation. En effet, la seule chose qu'on peut demander à une machine c'est de faire ça si telle ou telle condition et remplie.
On va donc voir dans ce chapitre comment "tester" une variable, et exécuter une action selon le résultat du test ! :D

Un nouveau type : Boolean

Les Conditions Opérateurs de test

Un nouveau type : Boolean

Vous m'excuserez de ne pas suivre un ordre "intuitif", mais avant de commencer à utiliser les conditions, je veux que vous les compreniez. Et pour cela nous allons faire appel à un nouveau type de variable : les variables booléennes, ou Boolean en anglais.

Vous avez dit booléen ?

C'est le type de variable le plus simple. Il n'a que deux valeurs possibles : true ou false (vrai ou faux en français).

Déclarons une variable booléenne, comme d'habitude, 3 techniques possibles :

var mabool:Boolean = new Boolean(true); //Méthode complète
var mabool:Boolean = false; //Méthode plus simple, mais correcte
mabool = true; //Méthode courte, moins stricte, car on ne donne pas le type de variable

Maintenant, imaginons que nous ayons deux variables numériques, et que nous voulions savoir si elles ont la même valeur ou non.

var mabool:Boolean = new Boolean(); // On définit une variable booléenne. En l'absence de valeur, elle prend d'elle même la valeur false
var nombre_a:Number = 100;
var nombre_b:Number = 50;
mabool = (nombre_a==nombre_b); // On assigne à mabool la valeur résultante du test
trace(mabool);

Et vous allez voir apparaître dans la fenêtre de sortie : false. Ce qui est tout à fait logique puisque 100 est différent de 50. :D
Vous avez pu constater qu'entre nombre_a et nombre_b on a intercalé l'opérateur ==. Cet opérateur permet de tester l'égalité entre deux variables.

Maintenant, refaisons le test de façon un peu plus rapide, sans passer par les variables :

var mabool:Boolean = new Boolean(); // On définit une variable booléenne. En l'absence de valeur, elle prend d'elle même la valeur false
mabool = (100==100); // On assigne à mabool la valeur résultante du test
trace(mabool);

Et là, miracle, la fenêtre sortie nous gratifie d'un beau true.

Conversion vers Number ou String

Chose utile à savoir, mais qui ne devrait pas nous gêner puisqu'on code proprement en indiquant le type de chaque variable, pour Flash true et 1 et false et 0 sont la même chose.

Ainsi, testez donc cette ligne :

var mabool:Boolean = true;
trace(mabool+mabool); // Horreur, on additionne deux booléens

Mais Flash ne se laisse pas démonter, et nous affiche 2. o_O
En effet Flash va adapter la variable selon les besoins. Là il s'agit d'un calcul numérique, il va donc modifier le true en 1. Ce qui explique le 2.

Et pour transformer le true en "true" et le false en "false" ?

Il faut utiliser la méthode toString() qui va transformer votre variable en chaîne de caractères.

Voilà ce qui ne marchera pas :

var mabool:Boolean = true;
var monstring:String = "valeur : ";
monstring+=mabool; // on concatène un String avec un Boolean -> aïe caramba
trace(monstring);

Un beau message d'erreur d'incompatibilité des types s'affichera à vous.

Voilà ce qui fonctionnera :

var mabool:Boolean = true;
var monstring:String = "valeur : ";
monstring+=mabool.toString(); // on concatène deux String -> no problemo
trace(monstring);

Les Conditions Opérateurs de test

Opérateurs de test

Un nouveau type : Boolean Opérations sur les booléens

Opérateurs de test

Nous avons donc vu le célébrissime == qui permet de tester l'égalité. Passons à du plus lourd :

1. "N'est pas égal à"

Voilà l'exact opposé à ==, je parle bien sûr de !=.
Cet opérateur permet de vérifier que les valeurs de deux variables sont bien différentes.

var mabool_a:Boolean = true;
var mabool_b:Boolean = false;
trace( mabool_a!=mabool_b);

Ce qui renvoie true, car true est différent de false.

On aurait pu aussi essayer cet opérateur avec des valeurs numériques ou des chaînes de caractères.

2. "Plus petit que" - "Plus grand que"

Il serait intéressant de pouvoir tester si un nombre est plus grand qu'un autre. Pas besoin de chercher dans le manuel de Flash l'opérateur, c'est le même que dans votre cours de Maths. :D

L'opérateur < correspond en français à "plus petit que" et à l'inverse, l'opérateur > correspond à "plus grand que".
Cela va nous permettre de comparer deux valeurs numériques. Testez chez vous ces différents lignes :

trace (100<50); // Renvoie false, car 50 n'est pas plus grand que 100 !
trace (50<100); // Renvoie true, car 50 est plus petit que 100
trace (100<100); // Renvoie false, car 100 n'est pas plus petit que 100, mais égal
trace (500>10); // Renvoie true

Intéressant, non ? ;)
Mais je suis sûr qu'un détail vous a plus intéressé que le reste : le test sur 100<100

3. "Plus petit ou égal à" - "Plus grand ou égal à"

Il s'agit cette fois de l'opérateur >= ou à l'inverse <=
Testons :

trace (100>=50); // Renvoie true, car 100 plus grand que 50
trace (100>=100); // Renvoie true, car 100 égal à 100

Et si on utilise > ou < avec des chaînes de caractères ?

Alors Flash comparera en fonction de la place de la lettre dans l'alphabet (en fait selon la place de la lettre dans la table des caractères ASCII (TABLE ASCII).
Quelques exemples enrichissants :

trace("A"<"B"); //true car A avant B dans l'alphabet
trace("a"<"B"); //false car pour Flash, les majuscules sont avant les minuscules.
trace("ab"<"ac"); //true car b avant le c dans l'alphabet
4. "Égalité stricte"

Voilà un opérateur qu'on utilise assez rarement, mais qui peut se révéler utile.
Pour comprendre son intérêt, testons cela :

var mabool:Boolean = true;
var monnombre:Number = 1;
trace(mabool==monnombre);

Ce qui nous renvoie true, car comme on l'a vu précédemment, pour Flash le booléen true équivaut au numérique 1.

Mais maintenant tapons :

var mabool:Boolean = true;
var monnombre:Number = 1;
trace(mabool===monnombre);

Ce qui nous renvoie false ! L'opérateur === (oui, ça en fait beaucoup ;) ) va non seulement comparer l'égalité des valeurs contenues dans les variables mais aussi l'égalité des types des variables. Or ici, le type Boolean est différent de Number, d'où le false.

Existe-il une inégalité stricte ?

Eh oui, elle est assez rarement utilisé : !==
Cet opérateur renverra true si les valeurs ou les types sont différents.

C'était le petit tour des opérateurs de conditions les plus usités. :)


Un nouveau type : Boolean Opérations sur les booléens

Opérations sur les booléens

Opérateurs de test La structure conditionnelle

Opérations sur les booléens

Eh oui, tout comme les nombres, les booléens ont leurs opérations.
Pour les nombres on a 4 opérations, qu'on peut réduire à 2 (la somme et le produit).
Eh bien chez les booléens c'est pareil, on a deux opérations : ET et OU.

La logique binaire (c'est-à-dire les opérations sur les booléens) pourrait faire l'objet de plusieurs chapitres, je vais donc faire simple et n'expliquerai pas toutes les possibilités de la logique binaire.
Nous nous en tiendrons aux bases, c'est-à-dire :

1. Opposé
2. ET
3. OU

1. "Opposé"

Celui là, il est bien pratique, il s'agit du petit !
Ce dernier inverse tout simplement la valeur d'une variable booléenne.
Par exemple :

var mabool:Boolean = false;
trace(!mabool); // Renvoie true

ou encore

var mabool:Boolean = true;
trace(!mabool); // Renvoie false
2. "ET"

Vous voulez vérifier qu'une variable est égale à telle valeur ET une autre est égale à telle autre valeur ?
Utilisez l'opérateur &&
Imaginez, vous êtes directeur d'une boîte branchée. A chaque client vous demandez la variable age et argent. Vous ne voulez laisser rentrer (true) que les majeurs et ceux qui ont plus de 50 ¬.

En semi-français on aurait :
(age PLUS GRAND OU EGAL 18) ET (argent PLUS GRAND 50)

Ce qui nous donne en Actionscript :
(age>=18) && (argent>50)

Un petit exemple :

var age:Number = 10;
var argent:Number = 100;
trace((age>=18) && (argent>50));

Le jeune garçon a bien l'argent, mais n'est pas majeur, donc éjection. :D Flash renvoie false.

3. "OU"

Opérateur : || (Ctrl+alt+6 pour les plus zéros d'entre nous).

Maintenant, imaginez-vous chef de casting :p pour la Zéros Académie. :lol:
Vous cherchez un Zéro qui soit possède un Q.I. inférieur au Q.I. d'une limace, ou alors un zéro qui possède une ancienneté supérieure à 3 ans sur le SDZ (un geek en somme ^^ ).

En semi-français :
(qi du zéro PLUS PETIT QUE qi de la limace) OU (ancienneté PLUS GRANDE QUE 3)

En Flash :
(zero_qi < limace_qi) || (zero_ancien > 3)

Et le petit exemple qui va bien :D :

var zero_qi:Number = 90;
var limace_qi:Number = 2;
var zero_ancien:Number = 3.5;
trace((zero_qi < limace_qi) || (zero_ancien > 3));

Cela nous renvoie true, car le Zéro a beau posséder un QI approchant de la moyenne mondiale, son ancienneté le sauve. :D

Voilà c'était tout sur les opérations de logique booléenne. Sachez que si vous aimez vous triturer les méninges, vous pouvez combiner toutes ces opérations et même démontrer que le ET possède les mêmes propriétés que la multiplication (distributivité...) et le OU les mêmes que la somme.


Opérateurs de test La structure conditionnelle

La structure conditionnelle

Opérations sur les booléens Récapitulatif

La structure conditionnelle

On arrive enfin au lourd. :D
Regardons maintenant comment utiliser tout ce que nous avons appris sur ses booléens !

1. if

Intéressons-nous à la structure conditionnelle la plus classique : if
(if veut dire si en français pour les plus anglophobes d'entre nous :) )

L'instruction if va vérifier si une variable booléenne est vraie, si c'est le cas, elle va effectuer une action.
Vous pouvez voir la structure dans l'exemple ci-dessous. Entre parenthèses, on met la variable booléeene qui va être testée : ici c'est mabool. Dans le bloc d'instructions délimité par les accolades, on va écrire l'action qui se produira, si la variable booléenne est vraie.

if (mabool) {
//l'action à effectuer si mabool vaut true
}

Petit exemple facile :

if (50<100) {
trace("en effet, 50 plus petit que 100");
}
2. if else

else signifie en français sinon
Il va nous permettre d'ajouter une action dans le cas où la condition renvoie false

if (50>100) {
trace("si la condition était vraie");
} else {
trace("mais en fait elle est fausse");
}

Ce code exécutera l'action contenue dans le else car la condition renvoie false

3. if else if

Et si on a plusieurs cas à éplucher ?

var monnombre:Number = 2;
if (monnombre==0) {
trace("monnombre vaut 0");
} else if (monnombre==1) {
trace("monnombre vaut 1");
} else if (monnombre==2) {
trace("monnombre vaut 2");
} else if (monnombre==3) {
trace("monnombre vaut 3");
} else {
trace("je sais pas ce que vaut monnombre");
}

Ce code affichera "monnombre vaut 2".
Mais amusez-vous à changer la valeur de monnombre pour comprendre le système.
La dernière action else sera exécutée si aucune condition précédente s'est révélée vraie.
N'oubliez pas que les tests s'effectuent dans l'ordre. Et Flash s'arrêtera à la première condition vraie, il n'ira pas voir plus loin.

4. les ternaires

Voilà une structure conditionelle qui va nous faire gagner du temps :p
Prenons cet exemple :

if (monnombre==0) {
trace("monnombre vaut 0");
} else { 
trace("monnombre ne vaut pas 0");
}

Ca nous fait : 5 lignes !

En ternaire :

(monnombre==0) ? trace("monnombre vaut 0") : trace("monnombre ne vaut pas 0");

Ca fait : 1 ligne :p

Voici comment se présente un ternaire structurellement :

Citation : Strucuture ternaire

CONDITION ? ACTION SI CONDITION VRAIE : ACTION SI CONDITION FAUSSE ;

Maintenant un petit exercice difficile. :diable:
Vous vous souvenez de l'opérateur ! qui permet d'inverser la valeur d'un booléen ?
Et bien je veux qu'on écrive une ligne de code qui fasse exactement la même chose. :p

Réponse :

var mabool:Boolean = false;
mabool = (mabool==true) ? false : true;
trace(mabool); // affiche true

Comment ça marche ?
Pour comprendre, il suffit de remonter d'un cran dans la simplification de l'expression, on va "développer" :

mabool = (mabool==true) ? false : true;
// Peut aussi s'écrire
(mabool==true) ? mabool=false : mabool=true;

Ce code a le même effet.

Ainsi que celui ci :

if (mabool==false) {
        mabool = true;
} else {
        mabool = false;
}

Voilà vous savez tout sur les conditions. J'ai omis de parler de l'instruction switch, car elle est rarement utilisée, et peut souvent s'éviter en utilisant un outil plus pratique : les boucles ! Que nous verrons au prochain chapitre. Cela dit, si vous tenez à comprendre le switch, allez lire les tutos sur les conditions avec les langages C++ ou PHP : le système est le même. L'aide de Flash vous sera aussi très utile. :)


Opérations sur les booléens Récapitulatif

Récapitulatif

La structure conditionnelle Les Boucles

Récapitulatif

Valeur Booléenne et correspondance numérique

Valeurs

Correspondance numérique

false

0

true

1

L'inverse n'est pas complètement vrai. Le 0 correspond bien à false, mais tous les autres chiffres correspondront à un true dans une condition.

Opérateurs de test

Opérateur

Signification

Vrai si ...

Faux si ...

==

égal à

les valeurs sont égales

les valeurs sont différentes

!=

non égal à

les valeurs sont différentes

les valeurs sont égales

===

strictement égal à

les valeurs ET les types sont égales

les valeurs sont différentes
les types sont différents

!==

strictement non égal à

les valeurs sont différentes
les types sont différents

les valeurs ET les types sont égales

A < B

plus petit que

si la valeur de A est plus petite que la valeur de B

si la valeur de A est plus grande que la valeur de B
si la valeur de A est égale à la valeur de B

A > B

plus grand que

si la valeur de A est plus grande que la valeur de B

si la valeur de A est plus petite que la valeur de B
si la valeur de A est égale à la valeur de B

A <= B

plus petit ou égal à

si la valeur de A est plus petite que la valeur de B
si la valeur de A est égale à la valeur de B

si la valeur de A est plus grande que la valeur de B

A >= B

plus grand ou égal à

si la valeur de A est plus grande que la valeur de B
si la valeur de A est égale à la valeur de B

si la valeur de A est plus petite que la valeur de B

Opérateurs booléens

Opérateur

Signification

Ce qui se passe ...

!A

opposé

A prend la valeur opposée. false devient true et true devient false

A && B

ET

Condition sur A ET sur B. Les deux doivent valoir true pour que le ET renvoie true

A || B

OU

Condition sur A OU sur B. Un des deux doit valoir true pour que le OU renvoie true

Structures
if (condition) {
//Si condition est vraie
} else {
// Si condition est fausse
}
if (condition) {
//Si condition est vraie
} else if (condition2) {
//Si condition2 est vraie
} else {
// Si condition et condition2 sont fausses
}
(condition) ? /*si vraie*/ : /* si faux */ ;

La structure conditionnelle Les Boucles

Les Boucles

Récapitulatif Qu'est-ce qu'une boucle

Nous avons vu les conditions et leur importance, nous nous intéressons maintenant à l'autre point commun à tous les langages de programmation, j'ai nommé : les boucles !

Qu'est-ce qu'une boucle

Les Boucles Boucle while

Qu'est-ce qu'une boucle

Comme vous le savez, Flash lit le code dans l'ordre : de haut en bas.
Une fois arrivé tout en bas : il s'arrête. :)

Image utilisateur

Eh bien avec une boucle, vous allez pouvoir demander à ce qu'une partie du code, un bloc d'instructions, soit répété un certain nombre de fois.
Et pour illustrer mes propos, je vais me permettre de ressortir sans autorisation, alors ne le répétez pas, une image d'un autre tuto du site que vous reconnaîtrez. :p

Le système de boucle de Flash est exactement le même que celui du C ou du Php, ceux qui savent déjà comment utiliser les boucles peuvent donc sauter ce chapitre.

Cela dit, les nouveaux en Flash font souvent une erreur importante. Ils pensent que en faisant une boucle qui déplace un clip sur la scène, l'utilisateur verra ce clip se déplacer. C'est faux ! Tant que Flash n'a pas fini d'exécuter tout le code qu'il voit, il n'affichera rien !


Les Boucles Boucle while

Boucle while

Qu'est-ce qu'une boucle Boucle for

Boucle while

Nous allons déjà regarder la boucle simple existante : la boucle while.

Tout comme if qu'on a vu précédemment, while va exécuter du code si une condition booléenne est remplie (retournez vite dans le chapitre précédent si vous n'avez pas compris les derniers mots :D ).

En français, voilà ce que donnerait une boucle while :

TANT QUE {CONDITION est VRAIE}

ALORS ...

Et en Flash :

while (condition) {
// actions à effectuer
}

Ainsi, tant que la condition est remplie, Flash réexécutera le code à l'intérieur de la boucle.

Et si la condition ne change pas et reste toujours égale à true ?

Là c'est le bordel. :D C'est ce qu'on nomme une boucle infinie. L'animation Flash restera figée un bon moment, mais au bout de quelques dizaines de (longues) secondes, Flash vous demandera si vous souhaitez continuer l'exécution du code, où si vous préférez arrêter tout. C'est un mécanisme de protection pour les utilisateurs.

Amusons-nous un peu. :p

var monnombre:Number = 10;

while(monnombre > 0) { // Tant que monnombre est strictement plus grand que 0
        trace(monnombre); // On affiche la valeur de la variable
        monnombre--; // On décremente la variable (on soustrait 1 )
}

Vous pouvez observer dans la fenêtre de sortie que l'effet est immédiat. Vous pouvez voir tous les chiffres de 10 à 1.

Maintenant, pour le plaisir, un exemple de ce qu'il ne faut pas faire :

while(true) {
        trace("boucle infinie");
}

Pour tester, vous pouvez exécuter ce code, vous pourrez ainsi voir la fenêtre de Flash demandant s'il est raisonnable de continuer d'exécuter le script. :)

C'est tout ce qu'il y a à savoir sur les boucles while.


Qu'est-ce qu'une boucle Boucle for

Boucle for

Boucle while Petits exercices de style

Boucle for

Voilà une boucle plus évoluée que while, il s'agit de for.
En fait, for est une boucle while condensée, tout comme les ternaires étaient des if condensés.

En français :

Déclaration de ma variable

Condition sur la variable pour que la boucle se fasse

Modification de ma variable pour que la boucle ne se fasse pas à l'infini

Tout à l'heure on a écrit :

var monnombre:Number = 10;

while(monnombre > 0) { // Tant que monnombre est strictement plus grand que 0
        trace(monnombre); // On affiche la valeur de la variable
        monnombre--; // On décrémente la variable (on soustrait 1)
}

Et maintenant la même chose avec for :

for (var monnombre:Number = 10; monnombre>0; monnombre--) {
        trace(monnombre);
}

Vous retrouvez tous les éléments, mais dans le désordre. :D
On initialise la variable, on écrit la condition nécessaire à l'exécution de la boucle, et dans cet exemple on décrémente la variable. On sépare tout ça par des points virgules ;

Pour les matheux, vous verrez une analogie avec ce qu'on appelle les démonstrations par récurrence.

Maintenant, voyons comment faire si on voulait que la fenêtre de sortie ne nous affiche pas 10 jusqu'à 1 mais 1 jusqu'à 10. :D

for (var monnombre:Number = 1; monnombre<=10; monnombre++) {
        trace(monnombre);
}

Comme vous avez remarqué, dans ce cas on déclare la variable égale à 1, pas zéro. Sinon, la première valeur affichée serait 0, car l'incrémentation ne s'effectuera qu'après la première lecture du bloc contenu dans la boucle. :) Il ne faut pas oublier de préciser la condition inverse, c'est-à-dire tant que monnombre strictement plus petit que 10 et changer la décrémentation en incrémentation.


Boucle while Petits exercices de style

Petits exercices de style

Boucle for Les Fonctions

Petits exercices de style

Je trouvais ça triste d'écrire un chapitre sur les boucles sans s'amuser un peu avec. Et pour cela je vous ai préparé un petit exercice sympathique et qui se révélera utile :

Vous souhaitez que la fenêtre de sortie vous affiche une fois "No problemo", une fois "Aïe caramba" et cela de façon alternée une vingtaine de fois :

No Problemo

Aïe Caramba

No Problemo

Aïe Caramba

...

Comment faire ? :D
Avant de regarder les solutions, cherchez un peu. :p

Il existe des dizaines de façons de répondre à cet exercice.
Moi j'ai décidé d'utiliser une boucle for dans les deux solutions que je vous propose.

La première solution

C'est la plus logique et la plus facile à comprendre.

var machaine:String = "No Problemo";
for (var monnombre:Number = 20; monnombre>0; monnombre--) {
machaine = (machaine=="No Problemo") ? "Aïe Caramba" : "No Problemo";
trace(machaine);
}

On déclare la variable machaine et on lui affecte la valeur "No Problemo".
Ensuite dans une boucle for qui va s'exécuter 20 fois, je place une condition avec structure ternaire histoire de gagner de la place :) (et de vous faire réviser la précédente leçon ^^ ).

Si machaine vaut "No Problemo", alors on lui affecte la valeur "Aïe Caramba"

Si machaine ne vaut pas "No Problemo", alors on lui affecte la valeur "No Problemo"

Et puisqu'il n'y a que deux possibilités de valeur, ça fonctionne très bien. :D

La seconde solution

Plus "mathématique", mais aussi plus courte, voici la seconde solution :

var machaine:String;
for (var monnombre:Number = 20; monnombre>0; monnombre--) {
        machaine = (monnombre%2 == 1) ? "No Problemo" : "Aïe Caramba";
        trace(machaine);
}

On utilise ici les modulos.
On déclare une chaîne de caractères vide : machaine
Et dans une boucle répétée 20 fois, on va utiliser les modulos.

Il faut savoir que la division euclidienne de n'importe quel nombre entier (sans virgule si vous préférez) par 2 ne donnera que deux restes possibles : 0 ou 1.

SI reste de la division de monnombre par 2 VAUT 1 ALORS machaine DEVIENT "No Problemo"

SI reste de la division de monnombre par 2 NE VAUT PAS 1 ALORS machaine DEVIENT "Aïe Caramba"

J'ai décidé pour que le code soit plus clair de passer encore une fois par la variable machaine.
Cela dit, elle n'est pas obligatoire avec la solution des modulos. On aurait pu mettre directement la condition dans la fonction trace et on aurait gagné 3 lignes. ;)

for (var monnombre:Number = 20; monnombre>0; monnombre--) {
        trace((monnombre%2 == 1) ? "No Problemo" : "Aïe Caramba");
}

J'espère que vous avez trouvé ce petit exercice sympathique. Sachez que pouvoir de façon simple échanger deux valeurs dans une variable se révèle souvent très utile, par exemple pour colorier de couleurs différentes une ligne sur deux d'un tableau. :D

Ce chapitre fut court mais très enrichissant. Ne l'oubliez donc pas, les boucles reviendront souvent dans notre code. :p


Boucle for Les Fonctions

Les Fonctions

Petits exercices de style Déclarer une fonction

Pour l'instant vous connaissez trois fonctions : stop(), play() et trace().

Maintenant, vous avez le droit à la définition honteusement pompée chez wikipedia :

Citation : Wikipedia

En informatique, une fonction est un ensemble d'instructions réalisant une certaine tâche.

Je ne pense pas pouvoir faire mieux. ;)

Ce chapitre sera très court, car la notion de fonction est très simple. ;)

Déclarer une fonction

Les Fonctions Des arguments

Déclarer une fonction

On a plusieurs moyens pour déclarer une fonction en AS. Imaginons que nous voulions créer une fonction mafonction qui afficherait dans la fenêtre de Sortie "Hello world".

On aurait soit cette solution :

function mafonction() {
        trace('hello world');   
}

soit cette autre méthode :

mafonction = function() {
        trace('hello world');   
}

Cette fonction ne fera rien par elle même, si on veut que son code soit exécuté il va falloir l'appeler. Comme ça :

mafonction();

Oui, c'est honteusement facile !

Vous pouvez même vous amuser à afficher 500 fois 'Hello World' dans la fenêtre de Sortie en utilisant une boucle par exemple.

On peut mettre la boucle à l'intérieur de la fonction :

function mafonction() {
        for (i=0; i<500; i++) {
                trace('hello world');
        }
}
mafonction();

ou à l'extérieur :

function mafonction() {
        trace('hello world');
}
for (i=0; i<500; i++) {
        mafonction();
}

Comme vous le voyez, tout ce que nous avons déjà appris est parfaitement compatible avec les fonctions.


Les Fonctions Des arguments

Des arguments

Déclarer une fonction Retour de valeur

Des arguments

Un argument

L'intérêt d'une fonction c'est de pouvoir exécuter une certaine tâche à chaque fois qu'on l'appelle. Mais il est encore plus intéressant de pouvoir lui passer des arguments, c'est-à-dire des variables qui vont influencer sur son fonctionnement.

Imaginons que je veuille faire une fonction bonjour() qui affiche dans la fenêtre de sortie 'Bonjour ' suivi du nom de la personne qu'on aura transmis comme argument.

On aurait un code de ce genre :

function bonjour(qui) {
        trace('Bonjour '+qui);
}
bonjour('toi');

On transmet la chaîne 'toi' comme argument. Dans la fonction, cet argument est stocké dans la variable qui.

On aurait pu utiliser un typage strict, pour obliger l'envoi d'une chaîne de caractères comme argument :

function bonjour(qui:String) {
        trace('Bonjour '+qui);
}
bonjour('toi');

Si vous aviez tapé ensuite bonjour(5);, votre animation aurait planté... :p

Des arguments

Bien entendu, on peut transmettre plus d'un argument à une fonction, il faut alors les séparer par des virgules.

function bonjour(prenom:String,nom:String) {
        trace('Bonjour '+prenom+' '+nom);
}
bonjour('Gérard','Bouchard');

Mais si on veut transmettre un nombre avec des virgules ? Par exemple 2,68 ?

Les nombres à virgule n'existent pas chez nos amis anglo-saxons ! Pour séparer la partie entière de la partie "sub-unitaire", les anglophones utilisent le point ..

Les français écrivent 2,68 et les anglais écriront 2.68
Or AS utilise le point anglophone, donc il n'y aura pas de problème. ;)


Déclarer une fonction Retour de valeur

Retour de valeur

Des arguments Méthodes et fonctions

Retour de valeur

Je suis sûr qu'en Mathématiques vous avez déjà vu des fonctions. Par exemple la fonction carrée multiplie le nombre qu'on lui transmet par lui même et retourne la nouvelle valeur.

Comment créer cette fonction ? Je vous donne la solution et nous allons la décortiquer :

function au_carre(nombre) {
return nombre*nombre;
}
trace(au_carre(5));

Ce morceau de code va nous afficher 25, le carré de 5.
En fait, la seule nouveauté pour vous, c'est l'instruction return. Elle retournera la valeur de la variable située à sa droite, c'est à dire ici 5*5.

Imaginons maintenant que je veuille une fonction qui calcule le pourcentage de lecteurs de ce tuto quand on lui transmet le nombre de lecteurs en cours sur le nombre de lecteurs total.

A vous de jouer. ;)

Voilà la solution la plus complète :

function pourcentage(encemoment:Number,total:Number) : String {
        var pourcent = (encemoment/total)*100;
        return pourcent.toString()+' %';
}
trace(pourcentage(2500,50000));

Vous remarquerez encore une nouveauté, c'est le : String que j'ai rajouté à la fin du nom de la fonction. Il permet de préciser que cette fonction renverra un chaîne de caractères. :)


Des arguments Méthodes et fonctions

Méthodes et fonctions

Retour de valeur Les Evénements

Méthodes et fonctions

Je parlerai souvent plus tard dans ce cours de "méthodes".
En fait une méthode n'est rien d'autre qu'une fonction, mais qui est rattachée à un objet.

Par exemple trace() n'est pas une méthode, car elle n'appartient à aucune classe.
play() et stop() sont des méthodes, car elle appartiennent à une classe. On pourra par exemple écrire : monclip.play();

Vous vous souvenez peut-être de la fonction toString() que je vous avais très brièvement montré ? Elle permet de transformer un nombre (et plein d'autres types de variables) en chaîne de caractères !
Cette fonction est-elle une méthode ?
Oui bien sûr, car elle appartient à des classes. Par exemple si vous voulez convertir une variable numérique en texte :

var nombre:Number = 5;
var texte:String = nombre.toString(); // On voit bien que toString() est portée par un objet

Retenez donc bien la spécificité des méthodes, pour mieux comprendre celles que nous verrons plus loin. ;)

Voilà c'est déjà fini pour ce très court, et pourtant très important, chapitre. :D


Retour de valeur Les Evénements

Les Evénements

Méthodes et fonctions Vous avez dit "événement" ?

Dans tout ce qu'on a vu jusque maintenant, vous ne trouverez aucun moyen d'ajouter de l'interactivité à votre animation.
C'est normal, c'est grâce aux événements que nous allons donner la possibilité à l'utilisateur d'interagir avec l'application.

Vous avez dit "événement" ?

Les Evénements Evénements souris localisés

Vous avez dit "événement" ?

Les événements sont des actions, tel un clic de souris de l'utilisateur ou la pression d'une touche du clavier, qui se produisent dans votre animation.
Quand l'utilisateur fera telle ou telle action, l'événement correspondant sera appelé et le code associé sera exécuté.

Dans ce chapitre je vais uniquement traiter des événements spécifiques au movieclips.
Pourquoi seulement ceux-là ? Parce que ces événements sont commun à de nombreuses classes d'objets dans Flash.
Pour des raisons de commodité, ce chapitre ne traitera que des événements courants qu'on utilisera lors du fil rouge de fin de chapitre.

Nous verrons dans les prochains chapitres des événements plus "poussés" utilisés par exemple dans la gestion des requêtes pour le transfert de variables entre Flash et un serveur.
De même nous ne verrons pas les événements en rapport avec la gestion des touches du clavier, ces derniers ne nous serviront en effet à rien pour l'instant. Nous les retrouverons plus tard dans ce chapitre pour l'élaboration d'un mini-jeu. :p

Voici la structure commune à tous les événements pour les Clips.

Version longue :

mafonction = function () {
     trace ("événement appelé");
}
monclip.monevenement = mafonction;

Version semi-longue :D :

function mafonction() {
     trace ("événement appelé");
}
monclip.monevenement = mafonction;

Version courte :

monclip.monevenement = function () {
     trace ("événement appelé");
}

A l'intérieur de l'événement, c'est comme si on écrivait le code dans le clip concerné.
C'est assez déroutant au début, mais il faut comprendre que l'événement appartient au clip.
Donc dans le bloc d'instructions à l'intérieur d'un événement appartenant à monclip, si on veut accéder à une propriété de monclip, il faudra écrire : this._propriete et non pas monclip.propriete. Car dans ce dernier cas, Flash chercherait le clip : monclip.monclip qui n'existe pas.

Vous remarquerez au long de ce chapitre que tous les noms d'événements commencent par "on" (qui pourrait se traduire approximativement par "lorsque").
C'est un bon moyen de les repérer dans l'aide de Flash.

Pour faciliter la compréhension, j'ai décidé de séparer en deux groupes les événements liés à la souris. Cela dit, ce regroupement est fait de façon arbitraire et personnelle. Ne parlez jamais à un Flasheur d'événements souris localisés et d'événements souris globaux. Il comprendra peut-être, mais ce n'est pas le vocabulaire "officiel".


Les Evénements Evénements souris localisés

Evénements souris localisés

Vous avez dit "événement" ? Evénements souris globaux

Evénements souris localisés

Commençons par les événements qui découlent de l'utilisation localisée de la souris.
C'est-à-dire les événements qui concernent les relations entre un clip (ou bouton) particulier et la souris.
Le clip associé à ces événements agira comme un bouton, et lorsque l'utilisateur passera la souris dessus, le curseur se transformera en petite main :p .

Nous ne verrons que les plus utiles :

1. onPress

Cet événement se déclenche lors du clic de la souris sur le clip.

Voilà la structure du code :

monclip.onPress = function () {
     trace ("Vous avez cliqué sur 'monclip' ");
}
2. onRelease

Plus courant que onPress, voici onRelease.
onRelease se déclenche lorsque que l'on relâche le bouton de la souris sur un clip. On peut le considérer comme l'inverse de onPress.
Il est préférable de l'utiliser, en effet lorsqu'un utilisateur clique sur un bouton, il faut lui laisser la possibilité d'annuler son choix, tout simplement en gardant le bouton appuyé et en relâchant ailleurs. D'ailleurs, vous remarquerez peut-être que l'immense majorité des boutons que vous utilisez ne s'activent pas lorsque vous cliquez dessus, mais quand vous relâchez le clic. ;)

monclip.onRelease = function () {
     trace ("Vous avez relâché le bouton de la souris sur le clip");
}
3. onReleaseOutside

Même chose que onRelease, mais n'est appelé que si le bouton de la souris est enfoncé sur le clip et relâché en dehors du clip.
C'est un événement peu utilisé.

4. onRollOver

Très utile celui là, il est appelé lors du passage de la souris sur le clip.
Il permet de changer l'aspect du clip quand on passe la souris dessus, par exemple ici :

monclip.onRollOver = function () {
     this._alpha=50; // Lors du passage de la souris, le clip se retrouve à moitié transparent
}

Vous remarquerez en testant cet exemple, qu'en sortant la souris du clip, ce dernier reste à moitié transparent... D'où l'utilité de l'événement suivant.

5. onRollOut

C'est l'inverse, cet événement se déclenche quand la souris sort du clip. Donc, pour compléter le code précédent, il faudrait écrire :

monclip.onRollOver = function () {
    this._alpha=50; // Lors du passage de la souris, le clip se retrouve à moitié transparent
}
monclip.onRollOut = function () {
    this._alpha=100; // Lors de la sortie de la souris, on remet le clip opaque
}

Voilà qui permet déjà un effet sympathique pour votre bouton.

Premier exemple avec les événements de souris localisés

Utilisons maintenant tout ce qu'on a vu jusque maintenant à propos des propriétés des Clips et des événements.
Reprenons le code précédent pour la transparence qui change au passage de la souris et, rajoutons-y un petit effet sans prétention quand on clique dessus avec la souris :

monclip.onRollOver = function () {
    this._alpha=50;
}
monclip.onRollOut = function () {
    this._alpha=100;
}
monclip.onPress = function () {
    this._xscale=125;
    this._yscale=125;
    this._rotation = 10;
}

Mais il y a un problème : une fois cliqué, le clip reste dans la position fixée...

Il suffit d'utiliser l'événement onrelease :

monclip.onRelease = function () {
    this._xscale=100;
    this._yscale=100;
    this._rotation = 0;
}

Mais là encore, il y a un problème. :D Si vous cliquez sur le clip, et que vous sortez du clip avant de relâcher, celui-là reste bloqué dans sa position "acrobatique".
Pour y remédier, il suffit de reprendre le code du onRelease et de l'adapter au onreleaseoutside. Comme ça, les deux cas seront couverts !
Hop, rajoutez ça à votre code :

monclip.onReleaseOutside = function () {
    this._xscale=100;
    this._yscale=100;
    this._rotation = 0;
}

Vous avez dit "événement" ? Evénements souris globaux

Evénements souris globaux

Evénements souris localisés Evénements à tout faire !

Evénements souris globaux

L'autre face de la lune. :D
Au nombre de 3, ces événements ne sont pas restreints au clip qui les porte, mais à toute la scène. Il n'y aura donc pas de petite main qui apparaîtra.
Nous allons voir :

1. onMouseDown

Il s'agit de l'équivalent global de onpress. Où que vous cliquiez dans la scène, cet événement sera appelé.

monclip.onMouseDown = function () {
     trace ("Bouton de la souris enfoncé");
}

Mais alors, quel est l'intérêt de le faire porter par un clip précis ? Et pas tout simplement le mettre pour _root ?

Aucun. :D Sauf peut-être pour la clarté du code quelques fois.
Taper cela revient exactement au même :

_root.onMouseDown = function () {
     trace ("Bouton de la souris enfoncé");
}

Et si je fais porter cet événement à deux clips à la fois ?

Il suffit de tester :

monclip.onMouseDown = function () {
     trace ("onMouseDown appartenant à monclip");
}
_root.onMouseDown = function () {
     trace ("onMouseDown appartenant à _root");
}

Et vous pourrez constater que la fenêtre de sortie affichera les deux. Les deux sont donc appelés. Évitez tout de même ce genre de code...

2. onMouseUp

onMouseUp est l'équivalent de onRelease. Il est exécuté lorsque le bouton de la souris est relâché.
Il n'existe pas d'équivalent à onReleaseOutside pour les événements globaux, dans la mesure où vous pouvez relâcher le bouton de la souris où vous voulez sur scène, ça sera toujours sur scène. Donc onRelease sera appelé.

3. onMouseMove

En voilà un très intéressant. :p
Il se déclenche dès que la souris est déplacée ! Même si la souris se déplace seulement de 1 pixel, l'événement sera exécuté ! Donc, de façon presque continue quand on bouge la souris.

Et là, on va pouvoir enfin utiliser un code que je vous avais montré dans les propriétés des clips et qui n'avait qu'une utilité limitée : le code permettant de faire tourner un clip sur lui même de façon à ce qu'il suive un clip.
Changez le clip en souris et vous avez un code qui fait tourner un clip en fonction de la souris.

Le code était :

_root.monclip._rotation = Math.atan2(_root.cible._y-_root.monclip._y, _root.cible._x-_root.monclip._x)/(Math.PI/180);

Maintenant, remplaçons les coordonnées du clip cible par les coordonnées de la souris, ce qui nous donne (en supprimant les _root qui ne servent à rien puisqu'on sait qu'on est sur la scène principale) :

monclip._rotation = Math.atan2(_ymouse-monclip._y, _xmouse-monclip._x)/(Math.PI/180);

Et maintenant mettons ce code dans un événement onMouseMove qui va être porté par _root :

_root.onMouseMove = function() {
monclip._rotation = Math.atan2(_ymouse-monclip._y, _xmouse-monclip._x)/(Math.PI/180);
}

Et là, miracle, ça marche. :D

Maintenant, petit exercice de style (vous savez que je les aime bien :p ).
Je veux faire la même chose, mais que l'événement onMouseMove soit porté par le clip monclip.
Voyez-vous les changements que cela va induire ?
Si vous n'avez pas trouvé, regardez la réponse :

monclip.onMouseMove = function() {
this._rotation = Math.atan2(_root._ymouse-this._y, _root._xmouse-this._x)/(Math.PI/180);
}

Eh oui, puisque qu'on se place dans le clip monclip, on change de référentiel.
On remplace donc monclip par this, quant aux coordonnées de la souris, il est conseillé de préciser qu'il s'agit des coordonnées par rapport à la scène _root, même si cela reste facultatif. En effet, si on ne précise pas à qui appartient un objet, Flash va supposer qu'il appartient non pas au clip qui porte le code, mais au clip dans lequel on a écrit le code.


Evénements souris localisés Evénements à tout faire !

Evénements à tout faire !

Evénements souris globaux Récapitulatif

Evénements à tout faire !

Dans cette dernière partie je traiterai des deux événements à tout faire :D :

1. onLoad

onLoad s'exécute dès que le clip est chargé. C'est-à-dire, de façon plus ou moins instantanée au démarrage.
Cela dit, j'utiliserai cet événement très rarement, car ces deux blocs de code reviennent au même :

monclip.variable = "variable quelconque";
monclip.onLoad = function() {
this.variable = "variable quelconque";
}

En effet, la variable sera initialisée au démarrage, que le code soit dans un onLoad ou pas...

En fait, onLoad sert principalement dans le cas où on place le code sur un script. Chose abominable que nous ne ferons jamais tout au fil de ce tuto, mais pour votre culture et compréhension de sources Flash de codeurs moins propres, je me devais de vous le montrer. ;)

2. onEnterFrame

Voilà un événement que nous utiliserons par contre très souvent. Surtout dans l'élaboration de jeux par exemple. :p
Cet événement se déclenche de façon constante et continue. :D Sa fréquence d'exécution correspond au nombre d'images par seconde de votre animation.

Plus vous avez un nombre d'images par seconde élevé, plus souvent sera appelé cet événement.

Exercice 1

Et pour illustrer mes propos, reprenons l'exemple précédent avec le clip qui tourne en suivant la souris.

Changeons le onMouseMove en onEnterFrame

_root.onEnterFrame = function() {
monclip._rotation = Math.atan2(_ymouse-monclip._y, _xmouse-monclip._x)/(Math.PI/180);
}

Ce qui conduira exactement au même effet !
En effet, que vous bougiez la souris ou pas, le code sera effectué.

Exercice 2

Maintenant, petit exercice facile. Comment faire pour que le clip suive la souris, non pas en se tournant sur lui-même, mais en bougeant ? En clair comment faire pour que le clip ait les mêmes coordonnées que la souris, et cela de façon continue ? ;)

Trouvé ? Voilà la réponse :

monclip.onEnterFrame = function() {
        this._x = _root._xmouse;
        this._y = _root._ymouse;
}

Vous remarquerez qu'en utilisant l'événement onMouseMove on aurait eu exactement le même résultat !

Exercice 3

Maintenant, un peu de code qui ne nécessite pas la souris.
Faites-moi tourner un clip sur lui même de 1 degré à chaque image !

Hop, résultat ci-dessous :

monclip.onEnterFrame = function() {
this._rotation ++;
}

Complexifions la chose. Je veux que la vitesse de rotation accélère à chaque fois que je clique sur le clip. :D
Aide : il va falloir utiliser une variable vitesse.

Correction :

var vitesse:Number = 1; // Déclaration de la variable vitesse
monclip.onEnterFrame = function() { // A chaque image
this._rotation += _root.vitesse; // On tourne de plus une fois la vitesse
}
monclip.onRelease = function() { // Quand on clique sur le clip
        _root.vitesse ++; // On augmente la vitesse de 1
}

Vous aviez trouvé ?... Pourtant c'était facile. :p


Evénements souris globaux Récapitulatif

Récapitulatif

Evénements à tout faire ! Fil rouge - le logo animé

Récapitulatif

Événement

Appelé si

onPress

l'utilisateur appuie sur le bouton gauche de la souris sur le clip portant l'événement

onRelease

l'utilisateur relâche le bouton gauche de la souris dans le clip en ayant précédemment cliqué sur le clip portant l'événement (toujours appelé après l'événement onPress)

onReleaseOutside

l'utilisateur relâche le bouton gauche de la souris en dehors du clip en ayant précédemment cliqué sur le clip portant l'événement (toujours appelé après l'événement onPress)

onrollover

l'utilisateur passe la souris sur le clip portant l'événement

onRollOut

l'utilisateur sort la souris du clip portant l'événement (toujours appelé après l'événement onRollOver)

onMouseDown

l'utilisateur appuie sur le bouton gauche de la souris n'importe où sur la scène

onMouseUp

l'utilisateur relâche le bouton gauche de la souris n'importe où sur la scène (toujours appelé après l'événement onMouseDown)

onMouseMove

l'utilisateur bouge la souris sur la scène

onLoad

le clip est chargé (appelé une seule fois)

onEnterFrame

appelé à chaque image (c'est à dire 12 par seconde pour une animation Flash normale)

Voilà un chapitre fort important que je vous conseille de relire souvent. :p

Si vous maîtrisez les propriétés des clips, les événements et la structure du langage comme les conditions et boucles, alors vous êtes déjà un champion. :D

Et parce que vous êtes champion, le prochain chapitre sera le dernier de cette partie et vous permettra de réaliser un beau logo pour le SDZ. ;)


Evénements à tout faire ! Fil rouge - le logo animé

Fil rouge - le logo animé

Récapitulatif Point de départ

Enfin la consécration de cette première partie ! Vous allez pouvoir appliquer tout ce que vous avez vu pour concevoir un logo animé pour le SDZ. :D

Et pour vous donner envie, voilà le résultat final. ;)

Point de départ

Fil rouge - le logo animé Bonnet de noël

Point de départ

Pour que vous ne perdiez pas de temps, voilà l'animation de base, avec tout sauf le code que nous allons ajouter. Il vous faut au minimum Flash Mx 2004 !

J'ai déjà donné aux clips et aux zones de texte un nom d'occurrence :

Image utilisateur

Notre but va être de rajouter de l'interactivité à chacun de ces objets.


Fil rouge - le logo animé Bonnet de noël

Bonnet de noël

Point de départ Rotation des yeux

Bonnet de noël

Vous avez vu le petit bonnet ? Il est pas mignon ? :lol:

Notre premier travail va être de faire en sorte que ce bonnet n'apparaisse que pendant le mois de décembre. Et pour cela, nous allons faire un très rapide détour du côté de la classe Date, qui permet de jouer avec les dates (comme son nom l'indique), les heures, ...

Avant tout nous allons déclarer un nouvel objet Date.

var date_noel:Date = new Date();

Maintenant, étudions la méthode getmonth() de la classe Date.
Cette fonction renvoie le numéro du mois courant, en commençant la numérotation à 0.
C'est-à-dire que janvier correspond à 0 et décembre à 11 (oui, les programmeurs n'ont jamais eu l'esprit très pratique... :D ).

Nous allons donc jouer avec une petite condition qui va rendre le bonnet visible ou non selon le numéro du mois renvoyé.

Comme ça :

if (date_noel.getMonth() == 11) { //En ActionScript, décembre est le mois n°11, car janvier est le mois n°0
        // Si on est en décembre
} else {
        // Si on n'est pas en décembre
}

Et maintenant rajoutons l'action permettant de rendre invisible le bonnet. Dans la mesure où le bonnet n'est pas un bouton, utiliser _alpha=0 ou _visible=false (_visible) revient exactement au même.
J'ai choisi pour vous : on va utiliser _visible.

Ce qui nous donne en totalité :

var date_noel:Date = new Date();
if (date_noel.getMonth() == 11) { //En ActionScript, décembre est le mois n°11, car janvier est le mois n°0
        bonnet._visible = true;
} else {
        bonnet._visible = false;
}

Et puisque vous êtes des pros avec les conditions, nous allons "compresser" tout ça en utilisant les ternaires :

var date_noel:Date = new Date();
bonnet._visible = (date_noel.getMonth() == 11) ? true : false;

Ca prend déjà moins de place, non ? ;)


Point de départ Rotation des yeux

Rotation des yeux

Bonnet de noël Contenu de la bulle

Rotation des yeux

Allez déjà faire un tour à l'intérieur des clips pupille1 et pupille2.
Zoomez un peu et vous pourrez constater que le point d'ancrage n'est pas au centre de la pupille mais légèrement à gauche.
Comme ça, si on fait tourner le clip, le point d'ancrage restant fixe, la pupille tournera autour.

Image utilisateur

Nous allons réutiliser le code que nous avions vu précédemment pour faire tourner un clip selon la position de la souris :

pupille1.onEnterFrame = function () {
        this._rotation = Math.atan2(_ymouse-this._y, _xmouse-this._x)/(Math.PI/180);
};

Voilà qui va permettre de faire tourner pupille1 dans la direction de la souris.

Mais au lieu de copier-coller ce code pour pupille2, on va faire plus malin. :p

orbites = function () {
        this._rotation = Math.atan2(_ymouse-this._y, _xmouse-this._x)/(Math.PI/180);
};
pupille1.onEnterFrame = orbites;
pupille2.onEnterFrame = orbites;

Et voilà, à ce stade là, vous avez ZoZor qui vous suit des yeux et qui sort son petit bonnet en décembre. :)


Bonnet de noël Contenu de la bulle

Contenu de la bulle

Rotation des yeux Récapitulatif

Contenu de la bulle

Nous allons enregistrer dans un tableau tout ce que Zozor peut dire, je vous donne directement tout le contenu, il y a quelques lignes :) :

var contenu:Array = new Array();
contenu[0] = "Salut les <b>Zéros</b> !";
contenu[1] = "Ce <i>didacticiel</i> vous plaît-il ?";
contenu[2] = "Je me nomme <font color='#FF0000'>Zozor</font> et je sens des <font color='#FF0000'>pieds</font> !";
contenu[3] = "<b>Toufou</b> ? C'est un ami ! En tout cas il en était un avant ce terrible jour, où on était dans sa cave, et...";
contenu[4] = "<b>Hiii Haaan !</b>";
contenu[5] = "J'aime les <b>carottes</b> ! D'ailleurs je suis très copain avec l'avatar de SuprazZz";
contenu[6] = "Il paraît que je dis toujours la même chose... C'est vrai ?";
contenu[7] = "Une bande de gars, nommés <b>Zéros</b>, m'ont élu comme mascotte... C'est toujours mieux qu'être Canard WC";
contenu[8] = "Si j'attrapais <b>l'en*oiré</b> qui m'a fait une <b>tête de vache</b> !";
contenu[9] = "Toi, vu ta tête, je parie que tu es un <b>Zéro</b> !";
contenu[10] = "Tu connais la blague du fou qui repeint son plafond ? Non ? Dommage...";
contenu[11] = "Tu connais la blague du con qui dit non ?";
contenu[12] = "Le SDZ saturé ? Et ca t'étonne encore ? :D";
contenu[13] = "Enfin un peu de compagnie !";
contenu[14] = "Je veux pas dire, mais c'est un peu lassant de toujours parler et qu'on ne nous réponde pas";
contenu[15] = "Surtout n'écoutez pas les rumeurs comme quoi je sortirais avec Toufou !";
contenu[16] = "Sais-tu dancer la Carioca ?";
contenu[17] = "Aïe Caramba !";
contenu[18] = "Après m'avoir vu, Barney a arrêté de boire";
contenu[19] = "Derrière toi ! <b>Tahiti Bob !</b>";
contenu[20] = "Eh Manu ! Tu descends ?";

Comme vous le voyez, Zozor a 20 répliques possibles, vous pouvez en rajouter si vous le souhaitez, mais n'oubliez pas de changer le nombre juste avant.
J'ai aussi mis des balises HTML dans les répliques, et dans les propriétés du clip, j'ai activé le format HTML.

_root.bulle.htmlText = contenu[0];// Affiche la première réplique

Et nous souhaitons afficher de façon aléatoire une réplique, pas que la première. :euh:

Nous cherchons à afficher une entrée entre 0 et le nombre total d'entrées. Il va donc falloir transmettre à cette fonction le nombre total d'entrées du tableau (voir propriété length donnant la longueur d'un tableau).

Ce code affichera donc un nombre entre 0 et 20 compris (car nous avons 21 entrées) :

trace( random(contenu.length) );

Il ne nous reste plus qu'à faire un mélange entre tout ce qu'on vient de faire, ce qui nous donne :

_root.bulle.htmlText = contenu[random(contenu.length)];

Mais nous allons appeler ce code plusieurs fois dans l'animation puisque nous souhaitons pouvoir changer la réplique en cliquant sur l'animation. On va donc mettre ce code dans une fonction, et appeler cette fonction au démarrage de l'animation :

//-- Déclaration de la fonction parlotte
parlotte = function () {
        _root.bulle.htmlText = contenu[random(contenu.length)];
};
//-- Au démarrage de l'animation, on appelle une première fois la fonction parlotte
parlotte();

Rajoutons ce qu'il faut pour que la fonction parlotte soit appelée quand on clique dans l'animation :

_root.onMouseDown = function() {
        parlotte();
};

Et voilà. :D C'était pas bien compliqué en fin de compte !
Et il est possible de rajouter autant de répliques qu'on le souhaite !


Rotation des yeux Récapitulatif

Récapitulatif

Contenu de la bulle Créer et enlever des Clips

Récapitulatif

Pour les fainéants, voici le code final et commenté :

//-
//- POUR NOËL
//-
var date_noel:Date = new Date();
bonnet._visible = (date_noel.getMonth() == 11) ? true : false;
//-
//- ROTATION DES YEUX
//-
//-- Déclaration de la fonction "orbite" permettant d'exercer une rotation sur un clip vers une direction
orbites = function () {
        this._rotation = Math.atan2(_ymouse-this._y, _xmouse-this._x)/(Math.PI/180);
};
//-- Association de la fonction aux événements onEnterFrame des deux clips
pupille1.onEnterFrame = orbites;
pupille2.onEnterFrame = orbites;
//-
//- CONTENU DE LA BULLE
//-
//-- Tableau des contenus possibles
var contenu:Array = new Array();
contenu[0] = "Salut les <b>Zéros</b> !";
contenu[1] = "Ce <i>didacticiel</i> vous plaît-il ?";
contenu[2] = "Je me nomme <font color='#FF0000'>Zozor</font> et je sens des <font color='#FF0000'>pieds</font> !";
contenu[3] = "<b>Toufou</b> ? C'est un ami ! En tout cas il en était un avant ce terrible jour, où on était dans sa cave, et...";
contenu[4] = "<b>Hiii Haaan !</b>";
contenu[5] = "J'aime les <b>carottes</b> ! D'ailleurs je suis très copain avec l'avatar de SuprazZz";
contenu[6] = "Il parait que je dis toujours la même chose... C'est vrai ?";
contenu[7] = "Une bande de gars, nommés <b>Zéros</b>, m'ont élu comme mascotte... C'est toujours mieux qu'être Canard WC";
contenu[8] = "Si j'attrapais <b>l'en*oiré</b> qui m'a fait une <b>tête de vache</b> !";
contenu[9] = "Toi, vu ta tête, je paris que tu es un <b>Zéro</b> !";
contenu[10] = "Tu connais la blague du fou qui repeind son plafond ? Non ? Dommage...";
contenu[11] = "Tu connais la blague du con qui dit non ?";
contenu[12] = "Le SDZ saturé ? Et ça t'étonne encore ? :D";
contenu[13] = "Enfin un peu de compagnie !";
contenu[14] = "Je veux pas dire, mais c'est un peu lassant de toujours parler et qu'on ne nous réponde pas";
contenu[15] = "Surtout n'écoutez pas les rumeurs comme quoi je sortirais avec Toufou !";
contenu[16] = "Sais-tu dancer la Carioca ?";
contenu[17] = "Aïe Caramba !";
contenu[18] = "Après m'avoir vu, Barney a arrêté de boire";
contenu[19] = "Derrière toi ! <b>Tahiti Bob !</b>";
contenu[20] = "Et Manu, tu descends ?";
//-- Déclaration de la fonction parlotte
parlotte = function () {
        _root.bulle.htmlText = contenu[random(contenu.length)];
};
//-- Au démarage de l'animation, on appelle une première fois la fonction parlotte
parlotte();
//-- En cas de clic (n'importe où sur la scène)
_root.onMouseDown = function() {
        parlotte();
};

N'hésitez pas à poser des questions complémentaires dans les commentaires ou sur le forum !
En espérant que vous trouverez des idées de logo pour votre site. ;)

Cette partie vous a autorisé une première approche du langage ActionScript, et vous a permis de réaliser un petit logo animé sympa.
Vous avez appris l'essentiel et sûrement la plus grosse partie de ce qu'il y a à savoir, les prochains chapitres relèveront plus de l'application de ces connaissances. ;)


Contenu de la bulle Créer et enlever des Clips

Créer et enlever des Clips

Récapitulatif Clips dynamiques, statiques et profondeur

Cette partie est d'une importance capitale pour la compréhension de la suite du cours. Nous allons jouer avec des clips ! Nous allons en créer des vides ou à partir de la bibliothèque, en supprimer, et tout cela dynamiquement !

Suivez bien le guide !

Clips dynamiques, statiques et profondeur

Créer et enlever des Clips Créer un clip vide

Clips dynamiques, statiques et profondeur

Avant de passer au côté pratique, nous allons nous plonger un peu dans la théorie.

Il faut savoir qu'il existe deux types de Clips :

Chaque clip a deux caractéristiques propres et uniques : son nom et sa profondeur !

Le nom, vous connaissez déjà, mais la profondeur (depth en anglais), je suis sûr que vous n'en avez jamais entendu parler !

Les profondeurs sont comprises entre -16383 et 1048575, et vous pouvez placer UN seul et unique clip par profondeur : ça laisse une certaine marge de manoeuvre. :D

Il faut savoir que Flash attribue aux clips statiques des profondeurs négatives, en partant de la valeur la plus basse : -16383
Mais il est tout à fait possible de leur indiquer une autre profondeur, ou de créer un clip dynamique avec une profondeur négative.

Pour jouer avec les profondeurs, je vais vous indiquer deux méthodes appartenant à la classe MovieClip :

Essayez de créer un clip statique, et d'afficher sa profondeur dans la fenêtre de sortie : vous constaterez vous-mêmes que sa profondeur sera -16383 si c'est le premier clip statique créé.

Amusez-vous ensuite à changer sa profondeur.

Maintenant, abordons une autre utilisation possible de swapDepths().
Comme le "swap" l'indique, cette méthode permet aussi d'intervertir la profondeur de deux clips monclip1 et monclip2, comme cela :

trace("profondeur de monclip1 :"+monclip1.getDepth());
trace("profondeur de monclip2 :"+monclip2.getDepth());
monclip1.swapDepths(monclip2);
trace("ECHANGE DE PROFONDEUR");
trace("profondeur de monclip1 :"+monclip1.getDepth());
trace("profondeur de monclip2 :"+monclip2.getDepth());

Et voilà ce que vous affichera le fenêtre de sortie :

Citation : Sortie

profondeur de monclip1 :-16383
profondeur de monclip2 :-16381
ECHANGE DE PROFONDEUR
profondeur de monclip1 :-16381
profondeur de monclip2 :-16383

La profondeur fait aussi partie de ce que vous verrez. En effet, si deux clips se chevauchent, c'est celui qui aura la plus haute profondeur qui sera au-dessus des autres !
Intéressant à savoir !


Créer et enlever des Clips Créer un clip vide

Créer un clip vide

Clips dynamiques, statiques et profondeur Dupliquer un clip de la scène

Créer un clip vide

La méthode la plus simple, et en même temps la plus abstraite : createEmptyMovieClip()
Comme son nom l'indique, elle permet de créer un nouveau clip vide.

Décortiquons ce que nous dit l'aide de Flash à son sujet.

public createEmptyMovieClip(name:String, depth:Number) : MovieClip

Le public signifie tout simplement qu'on peut appeler la méthode où que l'on soit par rapport au code. (Je résume. ;) )

Ensuite, on constate que la fonction admet 2 paramètres : name et depth :

Pour name, vous l'aurez compris, il s'agit seulement de donner un nom à notre clip. Il faut donner ce nom sous la forme d'une chaîne de caractères.

Pour depth, on l'a vu, il suffit de donner une profondeur qui n'est pas déjà utilisée. Sinon, le clip qui se trouvait précédemment sur cette profondeur sera détruit (ce qui peut se révéler parfois utile).

Enfin, le : MovieClip à la fin de la ligne signifie que la méthode ne renvoie non pas le MovieClip lui-même, mais une référence vers le Clip créé.

Petit exemple :

reference = _root.createEmptyMovieClip("monclip",1);

Ce code va créer un clip vide sur la profondeur 1 de la scène principale. C'est-à-dire que si vous créez un autre clip sur la scène principale, il pourra prendre toutes les profondeurs possibles, sauf 1, sous peine d'écraser le clip précédent.

Quelle est la différence entre reference et monclip ?

Eh bien en effet, les deux variables indiquent le même clip. Donc, que vous fassiez trace(reference) ou trace(monclip), vous aurez le même résultat !


Clips dynamiques, statiques et profondeur Dupliquer un clip de la scène

Dupliquer un clip de la scène

Créer un clip vide Attacher un clip à la scène

Dupliquer un clip de la scène

Voilà une méthode très facile à comprendre, mais qu'on utilise en fin de compte assez peu :

public duplicateMovieClip(name:String, depth:Number, [initObject:Object]) : MovieClip

Cette méthode permet de dupliquer un clip de la scène principale. Le clip qui va être créé sera dans le même clip parent que le clip que vous copiez, il sera placé au même endroit et aura la même taille : une copie parfaite !
name correspond au nom que l'on donne au nouveau clip, et depth à sa profondeur.

Encore une fois, un seul clip par profondeur !
Tout comme createEmptyMovieClip(), cette méthode renvoie une référence vers le clip. Mais au contraire de createEmptyMovieClip(), le clip qui "porte" la méthode (c'est-à-dire monclip dans cet exemple : monclip.mamethode() ) ne sera pas le clip sur lequel sera créé le duplicata, mais le clip à dupliquer.

Ça paraît peut-être pas très clair :-° mais avec un exemple, vous allez vite comprendre :

Pour tester, dessinez ce qui vous passe par la tête, et transformez votre oeuvre :D en un clip que vous nommerez clipacopier, le tout sur la scène principale.

Tapez ensuite comme code :

reference = clipacopier.duplicateMovieClip('monclip',2);

Comme pour createEmptyMovieClip(), que l'on utilise la variable retournée reference ou le nom du clip monclip pour y accéder, ça revient au même !

Mais il ne fait rien, ton code !

Mais si ! C'est juste que la copie du clip est parfaite, même position et même taille ! Les deux clips sont donc superposés !
Arrangeons tout ça :

reference = clipacopier.duplicateMovieClip('monclip',2);
reference._x = 0;
reference._y = 0;

Maintenant, votre nouveau clip va se placer en haut à gauche de la scène.

Exercice 1
Faites en sorte que le clip nouvellement créé suive la souris.

Correction possible (plein de possibilités) :

reference = clipacopier.duplicateMovieClip('monclip',2);
reference.onEnterFrame = function() {
        this._x = _root._xmouse;
        this._y = _root._ymouse;
}

Exercice 2
Créez 5 copies de votre clip, et disposez-les sur une diagonale, tout ça en utilisant une boucle bien-entendu. ;)

Correction possible (plein de possibilités, encore une fois) :

for (i=0;i<5;i++) {
reference = clipacopier.duplicateMovieClip('monclip'+i,i);
reference._x = i*reference._width;
reference._y = i*reference._height;
}

Vous avez bien remarqué que la profondeur qu'on demande pour le clip est la variable de la boucle. Ce qui permet d'avoir une profondeur différente à chaque fois. Car si vous aviez laissé une constante comme profondeur, alors les nouvelles copies auraient au fur et à mesure remplacé les précédentes !
Vous pouvez essayer avec une constante, et vous verrez que seule la dernière copie est encore là !

A chaque tour de boucle, on donne aussi un nom différent à notre nouvelle copie. Sinon, on se retrouverait avec un seul nom pour 5 clips, et ça poserait de petits problèmes, puisque seul le premier clip conserverait ce nom, tous les autres n'en porteraient pas. :(

Pour le positionnement en diagonale, on multiplie simplement la taille de l'objet par le numéro du tour de boucle en cours.

Maintenant, explicitons pourquoi cette méthode est finalement peu utilisée !
Eh bien jetez un coup d'oeil à votre diagonale : elle n'est pas belle, parce que le clip original est toujours là, et ce n'est pas très esthétique (et peu pratique aussi). Or, c'est un clip statique, car créé dans Flash, et non pas par Actionscript ; et un clip statique ne peut pas être supprimé.
Donc, on préférera utiliser une autre méthode pour pouvoir créer des clips de façon dynamique.


Créer un clip vide Attacher un clip à la scène

Attacher un clip à la scène

Dupliquer un clip de la scène Supprimer un clip

Attacher un clip à la scène

Et cette méthode magique et parfaite, la voilà : il s'agit de :

public attachMovie(id:String, name:String, depth:Number, [initObject:Object]) : MovieClip

Cette fonction va non pas dupliquer un clip de la scène, mais un clip de la bibliothèque !

Voilà comment assigner un identifiant à un clip de la bibliothèque. Pour afficher cet onglet, il faut cliquer sur "Propriétés" du clip, puis afficher les options "avancées". Vous pouvez aussi accéder tout simplement aux options de "liaison".

Image utilisateur

Pour nos tests, on va donner l'identifiant monclip à votre clip, comme d'habitude.

On fournit donc à la méthode l'identifiant id, le nom qu'on veut donner au nouveau clip name, et une profondeur depth.
Le nouveau clip sera créé dans le clip qui porte la fonction.
Et enfin, comme depuis le début, la fonction renvoie une référence vers le clip créé.

Testons :

reference = _root.attachMovie('monclip','nouveauclip',1);

Et là miracle, le clip qui était stocké dans votre bibliothèque apparaît sur votre scène _root.

Exercice 1
Comme tout à l'heure, faited-moi une belle diagonale de 5 fois votre clip.

Correction possible (vous savez déjà qu'il y en a beaucoup :p ) :

for (i=0;i<5;i++) {
reference = _root.attachMovie('monclip','nouveauclip'+i,i);
reference._x = i*reference._width;
reference._y = i*reference._height;
}

En fait, il n'y a rien à changer, si ce n'est la ligne où on a créé le nouveau clip.

Exercice 2
Faites-moi de la belle neige !
Supposez que vous avec un clip représentant un flocon de neige dans votre bibliothèque, et qu'il porte l'identifiant neige.
Supposez aussi que la neige n'apparaît pas en une seule fois (dites au revoir à la boucle for), mais au fur et à mesure du temps qui passe.
Supposez que la neige apparaît tout en haut de l'écran, et à un endroit aléatoire (dites bonjour à la fonction random() :lol: ).
Supposez enfin que la neige descend en ligne droite de 5 pixels par images.
N'oubliez pas de mettre un fond noir, sinon vous ne verrez rien !

Solution possible :

var i:Number=0;
_root.onEnterFrame = function() {
        i++;
        reference = _root.attachMovie('neige','neige'+i,i);
        reference._x = random(500);
        reference._y = 0;
        reference.onEnterFrame = function() {
                this._y+=5;
        }
}

La principale difficulté était de conserver une variable qui s'incrémentait à chaque nouveau clip, pour pouvoir donner au clip une nouvelle profondeur à chaque tour.

Mais le problème, c'est que la neige, une fois disparue de l'écran, existe toujours !

En effet, c'est un problème ! Nous allons corriger cela. :p


Dupliquer un clip de la scène Supprimer un clip

Supprimer un clip

Attacher un clip à la scène Une astuce en profondeur

Supprimer un clip

On va enfin pouvoir se défouler sur ces clips. :D La méthode magique :

public removeMovieClip() : void

Le clip qui porte cette méthode disparaît pour toujours. ;)

Pour tester, on va tout simplement reprendre notre code précédent, et ajouter une condition qui va tester si le clip n'est pas trop bas dans l'écran.
On suppose que votre scène fait 400 px de hauteur, et qu'on doit faire disparaître le clip dès que sa position verticale dépasse ce point.

var i:Number=0;
_root.onEnterFrame = function() {
        i++;
        reference = _root.attachMovie('monclip','nouveauclip'+i,i);
        reference._x = random(500);
        reference._y = 0;
                reference.onEnterFrame = function() {
                        this._y+=5;
                        if (this._y >=400) {
                                this.removeMovieClip();
                        }
                }
}

Il a suffit de rajouter ce petit morceau de code :

if (this._y >=400) {
        this.removeMovieClip();
}

Comme vous le voyez, c'est une méthode très simple à utiliser !


Attacher un clip à la scène Une astuce en profondeur

Une astuce en profondeur

Supprimer un clip La variable dans la variable

Une astuce en profondeur

Sous ce jeu de mot qui vaut pas un clou rouillé, se cache une fonction de Flash bien pratique :

public getNextHighestDepth() : Number

Cette méthode renvoie un nombre qui correspond à la prochaine profondeur non utilisée !
Donc, à priori, plus besoin de s'embêter à utiliser des variables qui s'incrémentent au fur et à mesure, il suffirait d'écrire :

reference = _root.attachMovie('monclip','nouveauclip'+i,_root.getNextHighestDepth());

Mais voilà le petit problème : le nom du clip créé. Il a toujours besoin de i, sinon on donnerait toujours le même nom !

Aller, cherchez 5 secondes pour trouver une solution :D

reference = _root.attachMovie('monclip','nouveauclip'+_root.getNextHighestDepth(),_root.getNextHighestDepth());

Voilà, c'était tout bête !

Autre astuce intéressante : public getInstanceAtDepth(depth:Number) : MovieClip.

Imaginez que vous ayez créé un nouveau clip et que, manque de chance, vous perdiez son nom ET sa référence, ou que vous les effaciez comme ici :

reference = _root.attachMovie('monclip','nouveauclip',1);
reference = null;
monclip = null;

Et maintenant, essayez de supprimer le clip. Vous pouvez essayer avec nouveauclip.removeMovieClip(); ou avec reference.removeMovieClip(); : ça ne marchera pas ! Les variables ne renvoient plus au clip !

Comment on fait alors pour accéder au clip, pour l'effacer par exemple ?

Eh bien on utilise la fonction magique :

_root.getInstanceAtDepth(1).removeMovieClip();

La fonction va renvoyer le clip situé sur _root, et possédant la profondeur 1. Et comme ça, on peut supprimer un clip dont on a oublié le nom (mais pas la profondeur : on a rien sans rien :p ) !


Supprimer un clip La variable dans la variable

La variable dans la variable

Une astuce en profondeur Publication et variables

La variable dans la variable

Reprenons un exemple précédent facile :

for (i=0;i<5;i++) {
reference = _root.attachMovie('monclip','nouveauclip'+i,i);
reference._x = i*reference._width;
reference._y = i*reference._height;
}

Vous êtes d'accord que les clips porteront les noms 'nouveauclip'+i, avec i qui varie de 0 à 4.
Imaginons que nous ne voulions pas utiliser la variable reference que nous retourne la fonction, mais directement le nom du nouveau clip pour accéder à ses coordonnées.
Comment faire ?
Voilà la syntaxe qui permet d'accéder au clip :
_root['nouveauclip'+i]

Appliquons-la ensemble à l'exemple pour bien comprendre :

for (i=0;i<5;i++) {
_root.attachMovie('monclip','nouveauclip'+i,i); // Plus besoin de reference
_root['nouveauclip'+i]._x = i*_root['nouveauclip'+i]._width;
_root['nouveauclip'+i]._y = i*_root['nouveauclip'+i]._height;
}

Ça alourdit drôlement le code ! Alors soyez intelligents, et trouvez un moyen pour n'écrire qu'une seule fois _root['nouveauclip'+i].

for (i=0;i<5;i++) {
_root.attachMovie('monclip','nouveauclip'+i,i);
reference = _root['nouveauclip'+i];
reference._x = i*reference._width;
reference._y = i*reference._height;
}

Eh bien on fait appel à une variable "tampon", qui sera elle aussi une référence au clip, mais plus courte à écrire. ;)

Vous allez me dire que dans cet exemple, ça sert à rien. Et vous avez raison. Mais je vous assure que les cas où on a besoin d'accéder à des variables dans des variables sont légion, et qu'il faut bien connaître la syntaxe :

clipparent['nomduclip']

Il s'agit là du chapitre le plus important ! N'oubliez donc pas son contenu.

Si vous vous demandez toujours le rapport entre l'icône du chapitre et les Clips, pensez aux variables qui font référence aux clips, et au problème qu'on peut avoir si on les perd. ;)


Une astuce en profondeur Publication et variables

Publication et variables

La variable dans la variable Paramètres de publication Html

Dans cette partie, nous nous intéresserons seulement à ce que j'avais précédemment nommé : l'architecture Flashoponctuelle.
C'est à dire que nous allons étudier comment transmettre des variables directement à l'animation contenue dans une page Web, sans que l'animation aie besoin de faire de requête.

Paramètres de publication Html

Publication et variables Le code Html expliqué

Paramètres de publication Html

Image utilisateur

Pour commencer, créez une nouvelle animation vide, et aller voir les options de publication : Fichier->Paramètres de publication.

Vérifiez que les cases Flash et Html sont cochées, puis allez voir l'onglet Html.

Pour plus d'informations sur le Modèle, sélectionnez celui concerné, et cliquez sur Infos.

Vous pouvez changer les dimensions de l'animation dans la page Web : essayez de conserver toujours les mêmes proportions, sinon l'utilisateur verra les "côtés" de l'animation, ce qui n'est pas très beau.

Les cases à cocher de Lecture nous concernent peu, car nous contrôlons la lecture et les autres propriétés directement en Actionscript.

Idem pour la Qualité.

Grâce au Mode fenêtre, vous pouvez rendre l'arrière-plan de votre animation transparent (c'est-à-dire qu'on verra la page Web au travers) ! Mais si l'animation et la page Web qui la porte sont trop complexes, ça va horriblement ralentir l'ordinateur... Option à double tranchant !

Vous comprendrez aisément les options suivantes, sachez toutefois que "Alignement Flash" correspond à l'alignement de l'animation dans l'espace qui lui est réservé, et non pas par rapport à la page.
Or la plupart du temps, l'espace réservé est le même que l'espace pris par l'animation, changer l'alignement ne fera donc rien.


Publication et variables Le code Html expliqué

Le code Html expliqué

Paramètres de publication Html Envoie des variables

Le code Html expliqué

Cliquez ensuite sur le bouton Publier (maj+F12).

Aller jeter un coup d'oeil à la page Html produite par Flash, vous trouverez aisément les lignes qui nous intéressent :

<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0" width="550" height="400" id="Sans nom-1" align="middle">

<param name="allowScriptAccess" value="sameDomain" />
<param name="movie" value="Sans nom-1.swf" />
<param name="quality" value="high" />
<param name="bgcolor" value="#ffffff" />

<embed src="Sans nom-1.swf" quality="high" bgcolor="#ffffff" width="550" height="400" name="Sans nom-1" align="middle" allowScriptAccess="sameDomain" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" />

</object>

J'ai mis un peu en forme le code pour qu'on s'y retrouve.
La balise object permet de signifier au navigateur qu'il doit charger un plug-in possédant les attributs fournis.
Suivent ensuite quelques balises de type param qui permettent de déclarer quelques propriétés qui seront passées au plug-in.
Et enfin vient la balise embed qui n'est pas standard (elle empêchera la validation Xhtml stricte de votre code), qui résume tout ce qui a été dit avant pour les autres navigateurs que IE (Firefox par exemple).

Maintenant que nous avons vu ce que Flash fait, et donc ce qu'il ne faut pas faire, voyons ce qu'on peut faire pour proposer un code valide.
Voici la solution proposée par cette très bonne page Web (anglais) :

<object type="application/x-shockwave-flash" data="monanimation.swf" width="550" height="400">
<param name="movie" value="monanimation.swf" />
<p>Si l'utilisateur ne possède pas le plug-in</p>
</object>

L'auteur de ce code précise cependant que cela conduit à un petit bug avec Internet Explorer : avant d'être lue, l'animation sera chargée complètement, ce qui n'est pas grave pour nous. Mais c'est embêtant pour les grosses animations qui sont lues en streaming, c'est-à-dire pendant le chargement.

Dans tous les cas, il est impératif de garder l'attribut data qui indique aux navigateurs alternatifs (et valides), comme Mozilla Firefox, le chemin vers l'animation.
Mais il faut aussi conserver le param : movie qui lui sera utilisé par Internet Explorer. Vous pouvez d'ailleurs essayer l'un ou l'autre au choix, et ce sera soit IE soit Firefox qui n'affichera pas l'animation !


Paramètres de publication Html Envoie des variables

Envoie des variables

Le code Html expliqué Réception des variables

Envoie des variables

On arrive enfin à ce qui nous intéresse vraiment !
Le moyen le plus simple pour transmettre des variables à une animation Flash est de les lui envoyer codées, sous la forme GET.

Dit comme ça, ça a l'air drôlement compliqué, mais si vous avez quelques connaissances en PHP par exemple, vous comprendrez vite.

Rien de mieux qu'un exemple : dans le code ci-dessous, je transmets à l'animation monanimation.swf la variable siteweb qui vaut www.siteduzero.com.

<object type="application/x-shockwave-flash" data="monanimation.swf?siteweb=www.siteduzero.com" width="550" height="400">
<param name="movie" value="monanimation.swf?siteweb=www.siteduzero.com" />
</object>

Vous avez vu, c'est tout simple, il suffit de rajouter ?nomdemavariable=valeurdemavariable juste après le lien vers l'animation.

Si j'ai plusieurs variables ?

Il faut utiliser le séparateur &
Exemple :
monanimation.swf?premierevariable=premierevaleur&secondevariable=secondevaleur

Et vous pouvez en mettre une infinité comme ça !


Le code Html expliqué Réception des variables

Réception des variables

Envoie des variables Les caractères spéciaux

Réception des variables

On sait comment on peut envoyer les variables, mais concrètement, comment les recevoir et les afficher dans l'animation ?

Il suffit de savoir que les variables sont transmises à la scène principale sur _root.

Pour tester, créez une zone de texte dynamique, et donnez-lui comme nom de variable (pas nom d'occurrence, mais bien nom de variable) : siteweb.

Publiez l'animation, et modifiez votre code Html en conséquence pour avoir, comme tout à l'heure :
votreanimation.swf?siteweb=www.siteduzero.com

Ouvrez votre page Web, et là, miracle, www.siteduzero.com est écrit dans la zone de texte !

Encore un autre petit exemple pour la route.
Dessinez ce que vous souhaitez dans votre animation, et transformez-le en clip que vous appellerez en toute originalité : monclip

Tapez le code suivant sur la scène principale :

this.monclip._rotation = this.degre;
this.monclip._alpha = this.transparence;

Courez dans votre code Html, et changez le chemin de l'animation pour :
votreanimation.swf?degre=90&transparence=50

Ouvrez la page Web, et là, sans étonnement, vous verrez que votre clip est penché de 90° vers la droite, et à moitié transparent !


Envoie des variables Les caractères spéciaux

Les caractères spéciaux

Réception des variables Dessiner avec Actionscript

Les caractères spéciaux

Je vous invite à essayer de transmettre cette variable : Zéros, et de l'afficher dans votre animation !

Si vous êtes sous Internet Explorer : pas de problème, le plug-in Flash (sous forme de contrôle ActiveX) a fait ce qu'il fallait pour que ça passe.
Essayez avec Mozilla Firefox : là c'est beaucoup moins beau, Flash vous affiche Z¡s.

Voilà l'origine du problème :
Tout caractère textuel est codé selon une table des caractères, qu'on appelle aussi charset.
Si vous regardez en haut du code Html des pages Web, vous verrez toujours une ligne avec un attribut de ce type :
charset=iso-8859-1

Ce charset-là est celui le plus répandu pour les sites européens. Il gère la quasi-intégralité des caractères des alphabets européens. Cela dit, ne lui demandez pas de vous afficher du japonais ou du chinois.

Flash, ayant des prétentions mondiales, a choisi un charset "mondial", standard et très à la mode en ce moment, le charsetUTF-8.
Je vous conseille donc de coder en UTF-8 vos pages web !

Pour les lettres de l'alphabet, pas de problème, elles occupent la même position en iso-8859-1 et en UTF-8, ce qui explique pourquoi cela fonctionnait. Mais pour tous les autres caractères accentués, spéciaux, étrangers, il va falloir utiliser UTF-8.

Le charset de la mort

Il va vous falloir utiliser un programme qui permettera de choisir le charset de votre page Web. Dreamweaver, Notepad+, Unired le font. Il vous faut non seulement changer le charset "apparent" en haut de votre page web charset=UTF-8, mais en plus changer le charset "réel" du fichier, soit lors de la sauvegarde avec un logiciel d'édition du texte adapté, soit dans les propriétés de codage de la page avec Dreamweaver.

Et vos peines ne s'arrêtent pas là ! Selon que la page Web soit sur votre ordinateur ou sur votre serveur Web, l'animation affichera peut-être le ¡ qui deviendra vite votre pire ennemi ! Cela vient du fait que le charset est non seulement précisé à l'intérieur du la page web grâce à la ligne charset=UTF-8, mais le serveur Web peut aussi envoyer au navigateur un en-tête HTTP indiquant le charset à utiliser.
Donc la plupart du temps c'est en tâtonnant qu'on trouve la bonne solution, le mieux est d'utiliser le même charset partout.

Dès le départ, indiquez le charset=UTF-8 en haut de vos pages, indiquez à l'éditeur HTML que vous voulez écrire en UTF-8 et vérifiez dans les configurations de votre hébergeur que l'en-tête envoyé précise bien au navigateur qu'il doit utiliser l'UTF-8 (vous pouvez faire un programme PHP qui s'en chargera si votre hébergeur est nul).

L'encodage URL de rêve

Une solution pratique consiste à utiliser les fonctions escape() et unescape() de Flash.
Ces fonctions permettent d'encoder ou de décoder une chaîne de caractères au format URL.

Chaque caractère spécial possède un équivalent en codage URL. Par exemple, le é devient %C3%A9, et l'espace devient %20.
Même pas besoin de s'embêter avec les différents encodages (quoique ... ca serait trop beau :euh: ) !

Essayer de passer cette valeur à Flash : Z%C3%A9ros

Et là, ça marche à tous les coups ! :D Même pas besoin d'utiliser la fonction unescape(), Flash s'en occupe tout seul. ;)

Vous l'aurez compris, l'encodage devient un casse-tête dès le moment où on n'y fait plus attention !
Il est donc conseillé d'encoder les variables en utilisant l'encodage URL, comme ça pas de problème.
Mais il ne faut pas oublier que derrière se cache toujours le gros méchant charset !

Ce tuto vous a permis de comprendre le système de transmission de variable, mais vous a aussi prévenu des dangers de l'encodage des variables !
Le meilleur moyen de ne pas se tromper reste encore d'effectuer les tests non pas en local sur votre ordinateur mais sur un serveur web distant. :)


Réception des variables Dessiner avec Actionscript

Dessiner avec Actionscript

Les caractères spéciaux Couleurs d'un clip

Flash est un superbe outil pour la conception et l'animation d'illustrations pour le Web.
Mais savez-vous qu'Actionscript permet aussi de dessiner de façon dynamique ? :D

Couleurs d'un clip

Dessiner avec Actionscript Dessinons sur des clips

Couleurs d'un clip

On ne peut pas vraiment dire que la classe que nous allons étudier maintenant permet de dessiner, mais dans la mesure où elle permet d'attribuer une couleur à un clip, on va la ranger ici. :D

Avant Flash 8, pour colorer un clip, on utilisait ce code :

var macouleur:Color = new Color(monclip); // On associe macouleur à un clip
macouleur.setRGB(0xFF0000); // On donne une couleur héxadécimal à macouleur

Et ça suffisait pour changer la couleur du clip, et le colorer en rouge, comme dans l'exemple.

Mais si vous allez faire un tour dans l'aide, vous apprendrez que la classe color est obsolète ! :(
J'avoue qu'au départ j'étais un peu déstabilisé. Mais puisque je base ce cours sur Flash 8, je vais vous apprendre à colorer correctement un clip avec ActionScript 2 (et bientôt 3). ;)

Pour colorer un clip, il faut utiliser les classes colortransform et transform. L'une permet de créer la transformation de la couleur, et l'autre de l'appliquer au clip.

Il faut donc penser à rajouter ces deux lignes tout en haut de votre code, pour importer ces deux classes :

import flash.geom.ColorTransform;
import flash.geom.Transform;
Créer un objet ColorTransform

Pour créer un nouvel objet ColorTransform, on va utiliser cette syntaxe, commune à toutes les classes :

var macouleur:ColorTransform = new ColorTransform();

Eh bien dans Flash, on peut aussi employer l'écriture hexadécimale des couleurs (mais elle n'est pas obligatoire). Par contre, pour préciser à Flash que le nombre qui suit est en hexadécimaux, il ne faut pas utiliser le #, mais 0x.
Le bleu s'écrit donc 0x0000FF.

Mini-récapitulatif pour ceux qui découvriraient la notion :

Couleur

Xhtml & CSS

ActionScript

Rouge

#FF0000

0xFF0000

Vert

#00FF00

0x00FF00

Bleu

#0000FF

0x0000FF

Jaune

#FFFF00

0xFFFF00

Bref, la pipette de Flash dans la barre d'outils vous donne accès à toutes les couleurs possibles et imaginables, et vous donne le code hexadécimal correspondant. Il faudra juste penser à remplacer le # par 0x, car la pipette de Flash l'affiche avec un # o_O .

Tout ce qu'il faut savoir, c'est que Flash veut des couleurs notées avec #, et que ActionScript veut des couleurs avec 0x.

Image utilisateur

Maintenant qu'on a notre couleur, on va utiliser la variable rgb (rgb = red-Green-blue = rouge - vert - bleu) de la classe ColorTransform pour l'enregistrer, ce qui nous donne :

import flash.geom.ColorTransform;
import flash.geom.Transform;
 
var macouleur:ColorTransform = new ColorTransform();
macouleur.rgb = 0xFF0000; //Couleur rouge
Application de la transformation couleur

Notre transformation est prête. :D
On a un clip monclip sur la scène, et on souhaite la lui appliquer !

Il faut déjà associer une transformation au clip :

var transformation:Transform = new Transform(monclip);

On a créé avec ce code une transformation appelée, en toute originalité ;) : transformation.
On a aussi précisé que cette transformation s'appliquait à monclip.

Eh bien, il ne reste plus qu'à faire le lien entre la couleur et la transformation, grâce à :

transformation.colorTransform = macouleur;

Ce qui nous donne en récapitulant :

import flash.geom.ColorTransform;
import flash.geom.Transform;
 
var macouleur:ColorTransform = new ColorTransform();
macouleur.rgb = 0xFF0000;
 
var transformation:Transform = new Transform(monclip);
transformation.colorTransform = macouleur;

C'est drôlement plus long que l'ancienne méthode ! Pourquoi ce changement ?

En fait, il y a une logique là-derrière. :p
La classe Transform centralise les transformations qu'on peut effectuer sur un objet. Et la classe colorTransform possède beaucoup plus de possibilités que l'ancienne classe color : vous pouvez ainsi appliquer des coefficients sur les différentes composantes de la couleur, et même sur sa transparence. :D Allez voir l'aide de Flash pour plus d'informations là-dessus.


Dessiner avec Actionscript Dessinons sur des clips

Dessinons sur des clips

Couleurs d'un clip Gribouillons un peu

Dessinons sur des clips

Première chose à comprendre : on dessine toujours sur un clip !
En effet, toutes les méthodes de dessin que nous allons voir appartiennent à la classe MovieClip.

Et puisqu'on est des codeurs propres, on dessinera le moins possible directement sur la scène principale. :)

Nous allons donc préparer notre zone de dessin comme suit :

_root.createEmptyMovieClip('dessin',1);

Et tout ce qu'on dessinera, on le dessinera sur ce clip pour pouvoir :

Bref, énormément d'avantages !


Couleurs d'un clip Gribouillons un peu

Gribouillons un peu

Dessinons sur des clips Un peu de coloriage !

Gribouillons un peu

Sous ce titre explicite, on découvre les bases du dessin avec Flash : les traits !

public lineStyle(thickness:Number, rgb:Number, alpha:Number) : Void

La première chose à faire quand on dessine un trait, c'est de dire à Flash quel type de trait on veut !
thickness correspond à la largeur en pixel du trait, rgb sa couleur (en hexadécimaux, la plupart du temps), alpha sa transparence.
Flash 8 implémente d'autres arguments pour cette fonction, mais qui ne nous servent pas à grand chose pour l'instant : allez faire un petit tour dans l'aide pour en apprendre plus.

Posons la première ligne de notre code :

_root.dessin.lineStyle(4, 0x000000, 100);

Là, on dit à Flash d'utiliser un trait noir de largeur 4 px, et complètement opaque.

public moveTo(x:Number, y:Number) : Void

Cette méthode va vous permettre de placer le point de départ du dessin. Ça n'affiche rien en soi-même.
Si vous commencer directement à dessiner, Flash supposera alors que cette fonction a été appelée avec les arguments (0,0) c'est-à-dire en haut à gauche de votre animation.

Pour l'instant, écrivons :

_root.dessin.lineStyle(4, 0x000000, 100);
_root.dessin.moveTo(10, 10);

Avec ce code, on place le départ du dessin aux coordonnées (10,10) dans le clip dessin (puisque c'est là qu'on va dessiner).

public lineTo(x:Number, y:Number) : Void

Et voilà la reine des fonctions de dessin, celle qui trace effectivement le trait. Elle ne demande que les coordonnées cibles du trait.
Elle va donc tracer un trait entre les dernières coordonnées où on a dessiné (c'est-à-dire pour l'instant les coordonnées qu'on a passées à moveTo() ) et celles qu'on lui fournit.

Ce qui nous donne en achevant le code :

_root.createEmptyMovieClip('dessin',1);
dessin.lineStyle(4, 0x000000, 100);
dessin.moveTo(10,10);
dessin.lineTo(300, 300);

Et voilà un beau trait. :D

Exercice 1

Dessinez un carré.

_root.createEmptyMovieClip('dessin',1);
dessin.lineStyle(4, 0x000000, 100);
dessin.moveTo(10,10); // On se place au coin en haut à gauche
dessin.lineTo(300, 10); // Coin en haut à droite
dessin.lineTo(300, 300); // Coin en bas à droite
dessin.lineTo(10, 300); // Coin en bas à gauche
dessin.lineTo(10, 10);// Et on retourne en haut à gauche
Exercice 2

Permettez à l'utilisateur de dessiner avec la souris.

_root.createEmptyMovieClip('dessin',1);
dessin.lineStyle(4, 0x000000, 100);
dessin.moveTo(0,0);
_root.onEnterFrame = function() {
dessin.lineTo(_xmouse, _ymouse);
}

Petit rajout : ne dessinez que si l'utilisateur a le bouton de la souris enfoncé.

_root.createEmptyMovieClip('dessin', 1);
dessin.lineStyle(4, 0x000000, 100);
_root.onMouseDown = function() { // Quand on appuye sur le bouton de la souris
        dessin.moveTo(_xmouse, _ymouse); // On place le début du dessin aux coordonnées de la souris
        _root.onEnterFrame = function() {
                dessin.lineTo(_xmouse, _ymouse); //Et on dessine à chaque image un trait
        };
};
_root.onMouseUp = function() { //Quand on relâche le bouton
        _root.onEnterFrame = null; //On arrête le onEnterFrame
};

Voilà, vous êtes déjà un pro en dessin ;)


Dessinons sur des clips Un peu de coloriage !

Un peu de coloriage !

Gribouillons un peu Gommez moi tout ça !

Un peu de coloriage !

Continuons nos gribouillis avec un peu de coloriage !

public beginFill(rgb:Number, [alpha:Number]) : Void

La méthode qui permet de colorier, c'est celle-ci. Il en existe 2 autres plus complexes qui sont :

Si vous voulez en savoir plus, allez les voir dans l'aide.

Pour l'instant, reprenons notre cube, et colorions-le en rouge, tout en sachant que pour achever le coloriage, il faut utiliser la méthode MovieClip.endFill() à la fin du dessin :

_root.createEmptyMovieClip('dessin',1);
dessin.lineStyle(4, 0x000000, 100);
dessin.beginFill(0xff0000,100); // On remplit de rouge
dessin.moveTo(10,10); // On se place au coin en haut à gauche
dessin.lineTo(300, 10); // Coin en haut à droite
dessin.lineTo(300, 300); // Coin en bas à droite
dessin.lineTo(10, 300); // Coin en bas à gauche
dessin.lineTo(10, 10);// Et on retourne en haut à gauche  
dessin.endFill(); //On arrête le coloriage

Sympathique, non ?

Et si je ne mets pas dessin.endFill(); ?

Ben ça ne change rien. :D En effet, on ne commence pas de nouvelle figure avec de nouvelles couleurs, donc ce n'est pas bien grave.

Exercice 1

Reprenez le code de votre mini-paint. ;)

_root.createEmptyMovieClip('dessin', 1);
dessin.lineStyle(4, 0x000000, 100);
_root.onMouseDown = function() { // Quand on appuye sur le bouton de la souris
        dessin.moveTo(_xmouse, _ymouse); // On place le début du dessin aux coordonnées de la souris
        _root.onEnterFrame = function() {
                dessin.lineTo(_xmouse, _ymouse); //Et on dessine à chaque image un trait
        };
};
_root.onMouseUp = function() { //Quand on relache le bouton
        _root.onEnterFrame = null; //On arrête le onEnterFrame
};

Et maintenant, faites en sorte que tout ce qu'on colorie soit rempli de rouge !

_root.createEmptyMovieClip('dessin', 1);
dessin.lineStyle(4, 0x000000, 100);
_root.onMouseDown = function() {
        dessin.moveTo(_xmouse, _ymouse);
        dessin.beginFill(0xff0000,100);
        _root.onEnterFrame = function() {
                dessin.lineTo(_xmouse, _ymouse);
        };
};
_root.onMouseUp = function() {
        dessin.endFill();
        _root.onEnterFrame = null;
};

Rien de bien sorcier, suffisait de rajouter le beginFill().

C'est pas très avancé comme Paint, mais c'est déjà suffisant pour dessiner un coeur percé d'une flèche. :honte:


Gribouillons un peu Gommez moi tout ça !

Gommez moi tout ça !

Un peu de coloriage ! Utiliser le clavier

Gommez moi tout ça !

Il y a deux moyens pour effacer tous ces gribouillis !

Vu que c'est sur un clip dynamique, je pense que vous avez déjà deviné la première :

Effaçons le clip

Créez un clip carré sur la scène que vous appellerez effaceur.

Rajoutez ensuite dans votre paint, à la fin du code :

effaceur.onRelease = function() { // Quand on clique sur "effaceur"
        _root.dessin.removeMovieClip(); // On supprime le clip "dessin"
}

Ça marche, ça efface tout, mais impossible de redessiner ensuite, vu que le clip dessin n'existe plus !

Aller, cogitez un peu et trouvez-moi une solution élégante pour recréer le clip dessin à chaque effacement.

//-- Pour dessiner
_root.onMouseDown = function() {        
        dessin.moveTo(_xmouse, _ymouse);
        dessin.beginFill(0xff0000,100);
        _root.onEnterFrame = function() {
                dessin.lineTo(_xmouse, _ymouse);
        };
};
_root.onMouseUp = function() {
        dessin.endFill();
        _root.onEnterFrame = null;
};
//-- Pour effacer
effaceur.onRelease = function() {
        _root.dessin.removeMovieClip();
        _root.creer_espace_de_dessin();
}
//-- Pour commencer
creer_espace_de_dessin = function() {
        _root.createEmptyMovieClip('dessin', 1);
        _root.dessin.lineStyle(4, 0x000000, 100);
}
_root.creer_espace_de_dessin(); //On appelle la fonction qui crée le clip dessin une première fois au lancement de l'animation. Sinon, il faudrait cliquer sur le bouton avant de pouvoir dessiner.

Pas bête, hein ? :D

public clear() : Void

Voici la deuxième solution, beaucoup plus rapide dans notre cas ! Elle efface tout ce qui a été dessiné dans le clip !

Reprenez donc le code précédent, et au lieu d'utiliser removeMovieClip, utilisez moi clear().

//-- Pour dessiner
_root.onMouseDown = function() {        
        dessin.lineStyle(4, 0x000000, 100);
        dessin.moveTo(_xmouse, _ymouse);
        dessin.beginFill(0xff0000,100);
        _root.onEnterFrame = function() {
                dessin.lineTo(_xmouse, _ymouse);
        };
};
_root.onMouseUp = function() {
        dessin.endFill();
        _root.onEnterFrame = null;
};
//-- Pour effacer
effaceur.onRelease = function() {
        _root.dessin.clear();
}
//-- Pour commencer
_root.createEmptyMovieClip('dessin', 1);

Ça va déjà drôlement plus vite !
Vous remarquerez que dessin.lineStyle(4, 0x000000, 100); a été remonté tout en haut, pour être exécuté à chaque clic de souris. Car si on le laissait à sa place originelle, il serait supprimé en même temps que le dessin.
En effet, clear() efface le dessin, et tout ce qu'on a passé comme paramètres de remplissage, ou de couleur de trait ! Il faut donc que ce soit recréé à chaque fois. :)

A priori, les méthodes de dessin en Flash n'ont pas l'air très utiles...
Détrompez-vous ! Vous constaterez vous-mêmes à quel point il est indispensable de bien les connaître dans notre fil rouge. ;)


Un peu de coloriage ! Utiliser le clavier

Utiliser le clavier

Gommez moi tout ça ! Les écouteurs

Voilà une partie très intéressante, puisqu'après l'avoir lue, nous pourrons non seulement passer à la réalisation d'un petit jeu basique, mais vous pourrez commencer à programmer de vrais mini-jeux bien fun. :p

Nous allons étudier l'objet key, et apprendre certaines notions, comme le concept d'écouteurs. Ouvrez bien vos oreilles (sans mauvais jeux de mots :D ).

Les écouteurs

Utiliser le clavier La touche enfoncée

Les écouteurs

Pour commencer, on va s'intéresser à la notion d'écouteurs.

On essaye... et on se plante

Vous vous souvenez probablement des événements ? Les événements permettent d'exécuter du code selon une action, comme le clic de la souris par exemple :

_root.onMouseDown = function() {
trace('bouton gauche de la souris abaissé');
}

Eh bien dans cet exemple, onMouseDown est un événement.

Curieux comme tous les Zéros, vous allez vous jeter sur l'aide de Flash et voir s'il existe un événement onkeydown pour la classe MovieClip.

Et là : miracle ! Il existe bien un événement onKeyDown. :D
Tout con(tent)s, vous vous empressez de rentrer ce genre de code dans votre animation :

_root.onKeyDown = function() {
trace('Une touche du clavier a été titillée');
}

Et là, enfer et damnation, ça ne fonctionne pas. :(
Donc : retour à l'aide de Flash, et là on voit que ça se complique, car, pour que ce code fonctionne, il faut que le clip ait le focus et pleins d'autres propriétés (chiantes).

Bref, la dernière ligne de l'aide résume bien la situation :

Citation : Aide de Flash

Par conséquent, vous devez utiliser Key.onKeyDown dans la plupart des cas.

Voilà la solution, la classe Key :D

Les écouteurs de Key

L'objet Key ne possède pas d'événements comme les MovieClip, mais des écouteurs. La différence primordiale, c'est que là où un clip ne peut avoir qu'un seul et unique événement, alors que l'objet Key peut avoir un nombre infini d'écouteurs, qui seront tous appelés lors d'une action sur le clavier.

Passons à la réalisation du classique "Hello World" :

var ecouteur_clavier = new Object(); // On crée un écouteur, qui est en fait un objet quelconque pour l'instant
ecouteur_clavier.onKeyDown = function() { // On écrit une fonction onKeyDown pour cet objet quelconque
     trace("Hello World");
};
Key.addListener(ecouteur_clavier); // On indique que cet objet n'est pas quelconque, mais un écouteur clavier !

Et maintenant que vous avez compris comment ça marchait, vérifions que ce que j'ai dit précédemment sur les écouteurs est vrai (parce que même le prof peut se planter) :

var ecouteur_clavier:Object = new Object();
var ecouteur_clavier_bis:Object = new Object();
ecouteur_clavier.onKeyDown = function() {
     trace("Hello World");
};
ecouteur_clavier_bis.onKeyDown = function() {
     trace("Hello World (bis)");
};
Key.addListener(ecouteur_clavier);
Key.addListener(ecouteur_clavier_bis);

Et là miracle ! La fenêtre de sortie nous affiche :

Citation : Sortie

Hello World
Hello World (bis)

Les deux écouteurs ont donc été appelés ! :D

Key.onKeyUp

Nous avons déjà vu l'écouteur d'événement Key.onKeyDown, pas besoin donc de le représenter.

Mais il possède aussi son opposé : Key.onKeyUp, qui se déclenche lorsqu'une touche est relâchée.
On l'utilisera comme ceci :

var ecouteur_clavier:Object = new Object();
ecouteur_clavier.onKeyUp = function() {
     trace('Touche relevée');
};
Key.addListener(ecouteur_clavier);

Rien de bien compliqué !

Pour finir sur les écouteurs, il faut que je vous parle de la fonction Key.removeListener(mon_ecouteur);.
Comme son nom l'indique, elle permet de retirer un écouteur. Pas besoin de vous donner d'exemple, de toute façon on l'utilise presque jamais. :D


Utiliser le clavier La touche enfoncée

La touche enfoncée

Les écouteurs Les raccourcis des touches

La touche enfoncée

C'est bien beau tout ça, on peut savoir quand une touche est enfoncée ou relâchée, mais pas encore moyen de savoir laquelle ! :p

Les codes de touche

Flash nous offre non pas une méthode pour cela, mais deux ! :lol:

Il existe getAscii() qui renvoie le code ASCII de la touche, et getCode() qui renvoie le code de la touche selon un tableau des valeurs propre à Flash.
La principale différence entre ces deux méthodes, c'est que getAscii() est sensible à la casse (c'est-à-dire qu'elle fait la distinction entre majuscules et minuscules) ; et surtout que getAscii() ne possède des valeurs que pour les caractères. Pour lui, les touches comme "Ctrl", "Alt", "Maj", ... n'ont aucune valeur. Faites donc bien attention !

Voilà un petit code qui permet d'observer les différences des valeurs dans les deux tableaux des caractères.

var ecouteur_clavier:Object = new Object();
ecouteur_clavier.onKeyDown = function() {
     trace("______________________");
     trace("\t Code : "+Key.getCode());
     trace("\t ASCII: "+Key.getAscii());
     trace("______________________");
};
Key.addListener(ecouteur_clavier);
La baballe qui saute

Maintenant qu'on sait tout ça, on va s'amuser à faire notre premier jeu (attendez de le voir avant de pousser des cris de joie :D ).

Créez un clip balle sur la scène principale, et faites-moi un beau code qui va permettre de la faire "sauter" de 100 pixels vers le haut quand on appuie sur la barre d'espace (à vous de vous débrouiller pour connaître la valeur de la barre d'espace). Ensuite, je veux que la balle redescende à sa position d'origine lentement. :D
Hop ! Au boulot ! :p

Solution :

// Initialisation
var y_de_depart = _root.balle._y; //On récupère la position de départ
var ecouteur_clavier:Object = new Object(); // On crée l'écouteur
 
// Saut de la balle
ecouteur_clavier.onKeyDown = function() {
        if (Key.getAscii() == 32) { // 32 est le code de la barre d'espace
                _root.balle._y -= 100; // 100 pixels vers le haut
        }
};
Key.addListener(ecouteur_clavier);
 
// Retombée de la balle
_root.balle.onEnterFrame = function() {
        if (this._y<_root.y_de_depart) {
                this._y += 2;
        }
}

Je suppose que vous avez déjà remarqué qu'un objet qui tombe accélère sa chute au cours du temps. Eh bien simulez-moi ça ! :p

Voilà la solution, en utilisant une variable vitesse :

// Initialisation
var y_de_depart = _root.balle._y; //On récupère la position de départ
var ecouteur_clavier:Object = new Object(); // On crée l'écouteur
 
// Saut de la balle
ecouteur_clavier.onKeyDown = function() {
        if (Key.getAscii() == 32) { // 32 est le code de la barre d'espace
                _root.vitesse = 2;
                _root.balle._y -= 100; // 100 pixels vers le haut
        }
};
Key.addListener(ecouteur_clavier);
 
// Retombée de la balle
_root.balle.onEnterFrame = function() {
        if (this._y<_root.y_de_depart) {
                this._y += _root.vitesse;
                _root.vitesse += 1;
        }
}
Le problème de certaines touches

Flash impose quelques limitations à connaître. Par exemple, il ne peut capturer des entrées clavier que si l'utilisateur a cliqué dans l'animation, si cette dernière est dans une page web.

Maintenant, faisons une petite expérience.
Reprenez votre code qui permet d'afficher le code de la touche enfoncée.
Faites "Ctrl" + "Entrée" pour lancer votre animation.

Appuyez sur "Echap" sur votre clavier : pas de réaction.
Idem pour "Entrée", et pourtant, ce sont des touches indispensables !

Des touches qui ne fonctionnent pas, c'est à priori un problème insoluble. Voici la solution. En fait, une fois dans une page web, tout fonctionnera parfaitement, mais dans "la zone de test" de l'animation de Flash, les touches "Entrée" et "Echap" sont des touches de raccourci : voici l'astuce pour les désactiver :

Image utilisateur

Les écouteurs Les raccourcis des touches

Les raccourcis des touches

La touche enfoncée Une condition bien pratique !

Les raccourcis des touches

On a vu que chaque touche possédait une correspondance dans le tableau ASCII, ou dans le tableau Code. Mais c'est assez chi*** d'aller chercher à chaque fois à quel code correspond telle ou telle touche. Flash a donc intégré des "raccourcis" pour les touches les plus importantes. Par exemple, dans le code précédent, on avait déterminé que la barre d'espace avait pour valeur en Code : 32.

Eh bien si vous ne le savez pas, utilisez Key.SPACE. C'est un raccourci qui possède la valeur de la barre d'espace dans le tableau Code des caractères. Pour Flash, Key.SPACE = 32.

Voici la liste des correspondances. De nombreuses touches n'ont pas de correspondance avec la table ASCII, tout simplement parce que ce ne sont pas des caractères, mais des touches de contrôle, qui n'ont souvent pas de valeur dans la table ASCII.

Touche

Raccourci

Code

ASCII

Retour arrière

Key.BACKSPACE

8

8

Majuscule

Key.SHIFT

16

0

Verrouillage Majuscule

Key.CAPSLOCK

20

0

Suppr

Key.DELETEKEY

46

127

Echap

Key.ESCAPE

27

27

Insert

Key.INSERT

45

0

Origine

Key.HOME

36

0

Fin

Key.END

35

0

Page précédente

Key.PGUP

33

0

Page suivante

Key.PGDN

34

0

Tabulation

Key.TAB

9

9

Espace

Key.SPACE

32

32

Ctrl

Key.CONTROL

17

0

Entrée

Key.ENTER

13

13

Flèche haut

Key.UP

38

0

Flèche bas

Key.DOWN

40

0

Flèche gauche

Key.LEFT

37

0

Flèche droite

Key.RIGHT

39

0


La touche enfoncée Une condition bien pratique !

Une condition bien pratique !

Les raccourcis des touches Trichons avec les écouteurs

Une condition bien pratique !

Maintenant qu'on connaît les raccourcis, voilà un code qui permettrait de détecter la pression sur la barre d'espace :

var ecouteur_clavier:Object = new Object();
ecouteur_clavier.onKeyDown = function() {
        if (Key.getAscii() == Key.SPACE) {
                trace("Barre d'espace appuyée");
        }
};
Key.addListener(ecouteur_clavier);

Je vous présente maintenant la méthode Key.isDown(votre_touche), qui renvoie true si la touche est pressée, ou false dans le cas contraire.
Voilà l'équivalent du code précédent en utilisant cette fonction :

var ecouteur_clavier:Object = new Object();
ecouteur_clavier.onKeyDown = function() {
        if (Key.isDown(Key.SPACE)) {
                trace("Barre d'espace appuyée");
        }
};
Key.addListener(ecouteur_clavier);

On ne peut pas vraiment dire que le gain de place soit très perceptible, mais je vous conseille vivement de vous souvenir de cette méthode. ;)


Les raccourcis des touches Trichons avec les écouteurs

Trichons avec les écouteurs

Une condition bien pratique ! Les collisions

Trichons avec les écouteurs

Si vous avez bien compris la notion d'écouteurs, alors vous devez avoir intégré que leur seul rôle est d'appeler une fonction s'ils détectent quelque chose, comme la pression d'une touche. Les méthodes Key.getAscii et Key.getCode renvoient le code de la dernière touche pressée. Ce qui veut dire que l'appel à ces fonctions n'a pas besoin d'être parfaitement synchronisé, car même si on appelle la méthode 10 minutes après avoir appuyé sur "Entrée", elle renverra toujours 13.

D'où l'idée qui germe dans vos esprits de Zéros : "pourquoi ne pas se passer d'écouteurs, et effectuer la condition à chaque image (c'est-à-dire presque en continu) ?"

Ce qui nous donnerait par exemple :

_root.onEnterFrame = function() {
        if (Key.getCode() == Key.SPACE) {
                trace("Barre d'espace appuyée");
        }
};

On lance l'animation, et lors de l'appui sur "Espace", l'animation réagit ! Victoire ! On s'est passé des écouteurs ! :)
Mais, argh, horreur ! La fenêtre de sortie affiche en boucle "Barre d'espace appuyée" sans s'arrêter !

Pourquoi ce comportement ?

Eh bien, lors de l'appui sur la barre d'espace, Key.getCode() reçoit la valeur Key.SPACE. Or, on effectue la condition en boucle : l'affichage de la phrase sera donc en boucle. :(

Pour éviter ce comportement plus qu'ennuyant, il faut utiliser la fonction qui était apparemment si inutile, j'ai nommé : Key.isDown(). :D
En effet, la fonction ne renvoie truesi et seulement si la touche est actuellement enfoncée !

Ce qui nous donne :

_root.onEnterFrame = function() {
        if (Key.isDown(Key.SPACE)) {
                trace("Barre d'espace appuyée");
        }
};

Après avoir appris à récupérer les entrées clavier, vous devriez être capables de diriger une voiture. Mais comment lui mettre quelques obstacles ? :p C'est le prochain mini-tuto. :)


Une condition bien pratique ! Les collisions

Les collisions

Trichons avec les écouteurs Approche des collisions

Ce mini-tuto ne traitera que d'une seule méthode de la classe ActionScript, mais quelle méthode ! :D Il s'agit d'une fonction qui permet de tester la collision entre des clips, ou entre des coordonnées et un clip.
Elle possède peu d'options, mais puisque rien ne vaut la pratique pour la comprendre, vous allez avoir des exercices jusqu'à plus soif. :p

Approche des collisions

Les collisions Collision rectangulaire

Approche des collisions

Désolé, mais on ne va pas rentrer directement dans le tas ! On va déjà faire travailler un peu les méninges. :D

On va travailler tout au long de ce chapitre avec une base toute simple : un clip carré de taille 20*20 px, que vous appellerez boite. Ce clip boite se déplace de 2 pixels dans toutes les directions, à l'aide des flèches du clavier. Cadencez l'animation à 24 images par seconde (on sentira moins les "saccades" dans le déplacement de boite). Dimensionnez ensuite l'animation à 400 * 400 px.

La première chose que nous allons faire, c'est délimiter la zone où peut se déplacer librement boite. On va dire tout simplement que la boîte n'a pas le droit de sortir de l'animation.

Qu'est-ce que cela signifie ? C'est la question que vous devez vous poser quand vous êtes face à ce genre de problème.
Cela signifie qu'à tout instant :

Alors, maintenant branchez les neurones, et pondez-moi le code que je dois rajouter dans le blocboite.onEnterFrame !

Bon, je présente ici une solution parmi d'autres, n'hésitez pas à me proposer les vôtres pour évaluation dans les commentaires du tuto :

if (this._y<0) {
        this._y = 0
}
if (this._y>400) {
        this._y = 400;
}
if (this._x<0) {
        this._x = 0;
}
if (this._x>400) {
        this._x = 400;
}

Vous l'avez compris, si le clip dépasse une limite de quelque côté que ce soit, il est repoussé à la position limite !

Voilà pour la première partie de ce tutorial. ;)


Les collisions Collision rectangulaire

Collision rectangulaire

Approche des collisions Collision circulaire

Collision rectangulaire

Maintenant, on a notre animation de base, avec boite qui ne peut plus sortir de l'écran !

On va placer un obstacle, rectangulaire, sur sa route.
Ce qu'on souhaite, c'est que boite ne puisse pas passer par-dessus cet obstacle, qu'on va appeler obstacle_rectangulaire.

Alors, on pourrait de nouveau faire plusieurs conditions, qui vérifieraient que boite ne dépasse pas les limites de obstacle_rectangulaire. Mais vu que le programmeur est toujours un gros paresseux, on va plutôt utiliser la méthode qui va le faire pour nous. :p

Rajoutez ce code, juste avant la fin du bloc boite.onEnterFrame :

if (this.hitTest(_root.obstacle_rectangulaire)) {
        trace('Collision !!!');
}

Ai-je besoin de vous expliquer ? Bon, en clair, la méthode hitTest() va vérifier si le clip this (c'est-à-dire boite, vu qu'on est dans son bloc de code) et _root.obstacle_rectangulaire se chevauchent. Le cas échéant, il va afficher une alerte "Collision !!!" dans la fenêtre de Sortie.
Vous pouvez essayer !

Mais comment faire pour empêcher le clip d'aller sur l'obstacle ? :D

Eh bien il existe de multiples possibilités pour répondre à cette question, et encore une fois j'attends vos solutions. ;)

Voici la mienne, elle déplace le clip, teste la collision, et s'il y a effectivement collision, elle revient en arrière. :D

Voilà le code complet :

var vitesse:Number = 2;
boite.onEnterFrame = function() {       
        /* On enregistre les positions avant de bouger le clip, pour pouvoir le remettre à sa place s'il y a collision */
        posx = this._x;
        posy = this._y;
        /* Pour déplacer le clip */
        if (Key.isDown(Key.UP)) {
                this._y -= vitesse;
        }
        if (Key.isDown(Key.DOWN)) {
                this._y += vitesse;
        }
        if (Key.isDown(Key.LEFT)) {
                this._x -= vitesse;
        }
        if (Key.isDown(Key.RIGHT)) {
                this._x += vitesse;
        }
        /* Vérifions que le clip ne sorte pas de l'animation ! */
        if (this._y<0) {
                this._y = 0
        }
        if (this._y>400) {
                this._y = 400;
        }
        if (this._x<0) {
                this._x = 0;
        }
        if (this._x>400) {
                this._x = 400;
        }
        /* On teste s'il y a collision : si c'est bien le cas, on redonne au clip la position enregistrée au début. C'est instantané, l'utilisateur ne voit pas le déplacement qui a eu lieu, avant l'affichage de l'image */
        if (this.hitTest(_root.obstacle_rectangulaire)) {
                this._x = posx;
                this._y = posy;
        }
}

Ingénieux, non ? ;)


Approche des collisions Collision circulaire

Collision circulaire

Collision rectangulaire Collision ponctuelle

Collision circulaire

Maintenant, créez un clip obstacle_circulaire, qui, comme son nom l'indique, sera un obstacle constitué d'un cercle de diamètre 75 px. N'oubliez pas de bien mettre le centre du clip en phase avec le centre de la forme, sinon le script que nous allons étudier ne fonctionnera pas !

Pour l'instant, on va utiliser le même script pour l'obstacle circulaire que pour l'obstacle rectangulaire : rajoutez donc dans le bloc boite.onEnterFrame :

if (this.hitTest(_root.obstacle_circulaire)) {
        this._x = posx;
        this._y = posy;
}

Et testez votre animation !

Ça marche, mais pas parfaitement, comment ça se fait que boite se bloque des fois sans avoir touché le cercle ?

Et bien, vous venez de rencontrer l'énorme limite de la méthode hitTest !
Cette méthode ne peut pas prendre en compte à la fois la forme circulaire du clip obstacle_circulaire, et la forme de boite !
Elle considère qu'il y a collision à partir du moment où la plus petite zone rectangulaire de chaque clip en chevauche une autre. En fait, il faut vous imaginer qu'autour du cercle, il y a un rectangle invisible, qui est responsable de ce comportement embêtant de la méthode hittest. Ce rectangle s'appelle le cadre de délimitation.

Il va donc falloir feinter. :D
Qu'est-ce qu'on sait sur un cercle ? On sait que tous les points du cercle sont équidistants du centre. La distance entre le centre du disque et son bord vaudra toujours la valeur de son rayon, c'est-à-dire : 75/2 = 37.5 px.

On va donc calculer la distance entre le centre de notre clip boite, qui est tellement petit qu'il peut être assimilé à un cercle de rayon 10px, et le centre de l'autre cercle.

Ressortez vos souvenirs de maths, qu'est-ce qu'il a dit le bon sieur Pythagore ? :D
Il a dit ça :

Image utilisateur

Nous, ce qu'on cherche, c'est D (la Distance), et ce qu'on a, ce sont les coordonnées des centres de chaque cercle.
Donc, la longueur X correspond à la différence entre les deux abscisses des centres, et la longueur Y à la différence entre les deux ordonnées des centres.

On a donc :
X = this._x - _root.obstacle_circulaire._x;
Y = this._y - _root.obstacle_circulaire._y;

On met au carré et on additionne, ce qui nous donne en ActionScript :

Math.pow(this._x - _root.obstacle_circulaire._x,2) + Math.pow(this._y - _root.obstacle_circulaire._y,2)

Et on doit trouver la racine carrée de tout ça pour avoir D :

distance = Math.sqrt(Math.pow(this._x - _root.obstacle_circulaire._x,2) + Math.pow(this._y - _root.obstacle_circulaire._y,2));

Il reste donc à vérifier que la distance est plus grande que le rayon des deux clips additionnés.

Le rayon de obstacle_circulaire est 37.5px
On ne peut pas vraiment dire que boite a un rayon, puisque c'est un carré, mais puisqu'il est relativement petit, ça ne se verra pas trop. On suppose donc son rayon = 10px.

Ce qui nous fait une distance limite de : 37.5+10 = 47.5 px !

On peut donc rajouter à la place du script, qui fonctionnait mal, cela :

distance = Math.sqrt(Math.pow(this._x-_root.obstacle_circulaire._x,2)+Math.pow(this._y-_root.obstacle_circulaire._y,2));
if (distance<47.5) {
        this._x = posx;
        this._y = posy;
}

Ce n'est pas parfait, mais c'est déjà pas mal. :D
Et puis ce qui compte, c'est que vous ayez compris que souvent, les problèmes de collision peuvent se régler sans même utiliser hitTest. :D


Collision rectangulaire Collision ponctuelle

Collision ponctuelle

Collision circulaire Collision bourrine

Collision ponctuelle

Je vous ai dit que hitTest ne pouvait pas calculer de collision entre deux clips aux formes complexes (c'est-à-dire autres que rectangulaires). Mais je n'ai pas dit qu'il n'était pas possible de vérifier la collision entre un point et une forme complexe. :D

Supprimez le script qu'on a rajouté dans la partie précédente pour la collision avec l'obstacle circulaire.

Et copiez-collez le code suivant, qui présente une autre façon d'utiliser hitTest :

if (_root.obstacle_circulaire.hitTest(this._x,this._y,true)) {
        this._x = posx;
        this._y = posy;
}

Ce code vérifie la collision entre les coordonnées de boite (ce qui explique les this._x et this._y), et la forme du clip obstacle_circulaire. L'argument true permet de préciser qu'on souhaite bien que la collision se calcule à partir de la forme complexe du clip, et non pas de son cadre de délimitation rectangulaire.

Comme vous pouvez le vérifier, le code fonctionne assez bien, mais les clips se chevauchent un peu, puisque dans la collision on considère boite comme un point. Ce code n'est donc à utiliser que pour un clip "ponctuel", c'est-à-dire suffisamment petit pour pouvoir être assimilé à un point, pour que l'utilisateur ne se rende pas compte qu'il chevauche un peu la forme complexe.


Collision circulaire Collision bourrine

Collision bourrine

Collision ponctuelle Fil rouge - On The Road Again

Collision bourrine

Sous ce titre à priori fort peut explicite, se cache une astuce qui permet de réaliser des collisions entre un clip dont on connaît la forme complexe à l'avance, et un autre clip à la forme complexe. Oui, oui, vous avez bien entendu, on va réaliser le calcul de collision entre deux formes complexes. :D

En fait, l'astuce est toute simple, on va prendre des points importants de notre clip boite (ça sera les quatres coins, en toute logique), et on va effectuer un test de collision entre obstacle_circulaire et chacun des points ! :p Si je dis que c'est bourrin, c'est parce que, pour 4 points ce n'est pas bien lourd, mais avec des formes vraiment complexes, vous arriverez à des tests de plusieurs dizaines de points, ce qui risque de faire nettement flancher la fluidité de l'animation. ;)

Vous allez donc créer un clip point représenté par un petit cercle rouge de 2 ou 3 pixels. Vous ne placerez pas ce clip sur la scène principale, mais dans le clip boite. Vous copierez-collerez ce clip 3 fois, pour en placer un à chaque coin. Vous nommerez ces clips : point_1, point_2, point_3, et point_4.

On va donc changer le code précédent, qui gérait la collision entre le centre de boite et la forme de obstacle_circulaire.
On va seulement changer ce qu'il faut pour que la collision s'effectue entre point_1 et la forme de obstacle_circulaire.

Ce qui nous donne :

if (_root.obstacle_circulaire.hitTest(this.point_1._x,this.point_1._y,true)) {
        this._x = posx;
        this._y = posy;
}

Testez l'animation.

:o Pourquoi ça ne marche pas ? o_O

Eh bien en fait, la question à se poser est : quelles sont les coordonnées de point_1 ?
Dans la mesure où le référentiel dans lequel on se trouve est boite, on aura donc les coordonnées de point_1 par rapport à boite. Ce qui pose un problème, car dans ce cas, les coordonnées restent toujours les mêmes, soit (-12;-12), car point_1 ne change pas de position par rapport à boite.

Il faut donc convertir ces coordonnées pour qu'elles correspondent aux coordonnés de point_1 dans _root.

Pour cela je vais vous présenter deux solutions.

Un peu de géométrie

Voilà un schéma tout simple, qui va vous aider à comprendre.
Si on est dans le référentiel boite, alors les coordonnées de point_1 sont :
this.point_1._x
this.point_1._y
(avec this qui correspond à boite);

Mais si on veut ces mêmes coordonnées dans le référentiel _root, il faut ajouter les coordonnées de boite :
this.point_1._x + this._x
this.point_1._y + this._y
(avec this qui correspond à boite);

Image utilisateur

Bref, le code donnerait :

vrai_x = this.point_1._x+this._x;
vrai_y = this.point_1._y+this._y;
if (_root.obstacle_circulaire.hitTest(vrai_x,vrai_y,true)) {
        this._x = posx;
        this._y = posy;
}

Et ça fonctionne très bien. ;)

Un peu d'ActionScript

Si vous ne voulez pas vous embêter à réfléchir en dessinant des petits schémas, Flash vous offre une fonction qui va faire le travail pour vous : localToGlobal()
Cette méthode de la classe MovieClip permet de convertir des coordonnées locales d'un clip vers des coordonnées globales avec _root comme référentiel, et ça, quelque soit le clip de départ. L'avantage est donc que cette méthode fonctionne dans tous les cas. :D

Voilà comment l'utiliser :

var un_point:Object = new Object(); // On créé un objet quelconque
un_point.x = this.point_1._x; // On donne à cet objet des propriétés x et y
un_point.y = this.point_1._y;

Il faut tout d'abord créer un objet quelconque comme ci-dessus, et initialiser deux propriétés : x et y (et non pas _x et _y).

Ensuite, la fonction localToGlobal() va travailler un peu :

this.localToGlobal(un_point);

On précise avec this quel était le référentiel local de départ ; ici, il s'agit de boite : or, vu qu'on est dans un bloc de code lui appartenant, on utilise this.
Entre les parenthèses, on indique juste l'objet portant les propriétés x et y, qui doit être converti.

Et c'est tout. :D

Si on adapte ça à notre cas, on arrive à :

var un_point:Object = new Object();
un_point.x = this.point_1._x;
un_point.y = this.point_1._y;
this.localToGlobal(un_point);
if (_root.obstacle_circulaire.hitTest(un_point.x,un_point.y,true)) {
        this._x = posx;
        this._y = posy;
}

Comme vous pouvez le voir, c'est plus long. Mais le problème avec l'autre méthode, c'est que quand on cherche les coordonnées globales d'un clip, lui même dans un clip, qui est lui même dans un clip .. ça devient difficile. :D Alors que là tout se fait automatiquement. :p

Les 3 autres points

Bon, on va donc garder la seconde méthode. Mais maintenant vous savez tout ! Alors, un peu à vous de travailler ! Il faut adapter le code précédent pour que la vérification s'effectue sur les 4 points ! Il faudra bien entendu utiliser une boucle et ce qu'on a vu ICI.

Correction :

for (i=1; i<=4; i++) { // Boucle de 1 à 4 compris
        // Conversion des coordonnées
        var un_point:Object = new Object();
        un_point.x = this['point_'+i]._x;
        un_point.y = this['point_'+i]._y;
        this.localToGlobal(un_point);
        // Test de collision
        if (_root.obstacle_circulaire.hitTest(un_point.x,un_point.y,true)) {
                this._x = posx;
                this._y = posy;
        }
}

Et voilà, maintenant la méthode bourrin n'a plus de secret pour vous. ;)

N'oubliez pas, ce qu'il faut pour utiliser les collisions, c'est surtout de l'ingéniosité. ;)


Collision ponctuelle Fil rouge - On The Road Again

Fil rouge - On The Road Again

Collision bourrine Point de départ

Voilà le TP de fin de chapitre. :D
Vous allez créer votre premier mini-jeu, et pas n'importe lequel : un jeu de voitures pour 2 joueurs (sur un seul clavier ;) ).

Voilà le résultat final de notre futur jeu, que l'on nommera "On The Road Again" :

Point de départ

Fil rouge - On The Road Again Faire mumuse avec la voiture

Point de départ

J'espère que vous avez essayé OTRA (= On The Road Again), ça va vous donner une idée des clips qu'on va avoir besoin de créer.
Ils sont au nombre de 5 :

Une voiture

Oui, j'ai bien dit une voiture, et une seule. Il suffira de créer deux instances sur scène, et de changer leur couleur pour pouvoir différencier les deux voitures : a et b.

Image utilisateur

Voilà comment j'ai dessiné la voiture, c'est pas du grand art, mais on reconnaît 4 roues et un cockpit. :D Arrangez-vous pour centrer la voiture avec le centre du clip : comme ça, on aura des collisions assez précises, puisque la voiture est un clip de petite taille.
Surtout, il faut que vous dirigiez la voiture comme moi, c'est-à-dire de gauche à droite. Sinon vous aurez des problèmes après...

Créez donc deux occurrences de votre voiture sur la scène, changez un peu la couleur des deux voitures, et donnez-leur comme nom voiture_a et voiture_b.

Un compteur

Le compteur de vitesse est la pièce maîtresse de ce jeu, puisqu'il affiche à la fois la vitesse de la voiture, mais aussi le nombre de tours effectués. On va donc distinguer les deux parties.

Le compteur de tours est un bête champ texte dynamique, on lui assigne la variable tour (attention j'ai bien dit la variable, pas le nom d'occurrence).

Pour identifier la voiture à laquelle appartient le compteur, créez un champ de texte dynamique de variable voiture.

Image utilisateur

Le compteur de vitesse est un peu plus complexe. Il faut dessiner un rectangle coloré (ou blanc, si le fond de votre scène est coloré) qui correspond à la taille maximum du compteur (la vitesse maximum). Convertissez ce rectangle en un clip, que vous nommerez vitesse (là, je parle du nom d'occurrence, pas du nom dans la bibliothèque ;) ). Cette fois, positionnez le bord droite du rectangle sur le centre du clip.

Vous allez donc ranger le clip vitesse et les deux champs de texte dynamique de variable tour et voiture dans un nouveau clip, que l'on nommera compteur_a. Créez une autre occurrence de ce clip, que vous nommerez compteur_b (pour l'autre voiture).

Image utilisateur

Voilà à quoi ressemblent vos deux compteurs, côte à côte :

Un feu tricolore

Le feu tricolore est un clip que vous nommerez feu_tricolore sur la scène principale. A l'intérieur, vous dessinez un rectangle arrondi foncé. A côté, créez un clip blanc circulaire que vous dupliquerez 2 fois pour faire les 3 feux ; vous les nommerez de haut en bas : couleur_1, couleur_2 et couleur_3.

Image utilisateur
Une route

Ça peut paraître évident, mais sans route, le jeu va être drôlement moins intéressant ! Bref, le circuit, c'est un simple clip nommé route (vous avez, j'en suis sûr, remarqué l'extrême originalité dont je fais preuve quand je nomme un clip). Dans ce clip, vous dessinez votre route, tout bêtement. Au début, faites un circuit simple, sans "branches", parce que ça posera des problèmes au niveau des waypoints que l'on va voir tout de suite.

Image utilisateur
Des Goals
Image utilisateur

Pour l'instant, vous ne savez pas encore vraiment comment ils vont fonctionner, mais si vous avez un peu joué, vous savez déjà que si vous vous sortez de la route, vous êtes replacé sur le dernier Goal où vous êtes passé. Les Goals permettent aussi de vérifier que vous avez bien fait tout le tour du circuit avant de repasser par la ligne de départ.

Les lignes de départ et d'arrivée sont d'ailleurs des goals comme les autres, on leur donne juste un peu de couleur dans leur occurrence.
Vous pouvez le dessiner comme vous le souhaitez, le goal doit simplement être à peu près rectangulaire, dirigé vers le haut, avec son centre au niveau du centre du clip.
Ensuite, vous allez en placer aux endroits stratégiques de votre route. Vous nommerez le premier (la ligne de départ) goal0. Ensuite, vous avez compris : tous les suivants porteront les noms goal1, goal2 ...

Vous pouvez changer les propriétés des lignes de départ et d'arrivée, pour qu'on puisse les identifier plus facilement. ;)

Image utilisateur
Et pour les feignants ?

J'allais oublier les plus paresseux d'entre vous, ou tout simplement pour comparer avec ce que vous avez. Je vous invite quand même à le prendre pour continuer, comme ca vous êtes sur de tout avoir. ;)


Fil rouge - On The Road Again Faire mumuse avec la voiture

Faire mumuse avec la voiture

Point de départ Les goals

Faire mumuse avec la voiture

On va commencer par s'atteler à la partie la plus fun : le déplacement des voitures. :D

Pour avoir un code propre, on écrira tout le code que je vous donnerai dans ce TP, sur la scène principale !

Structure fonctionnelle

On va créer deux tableaux contenant chacun les 3 touches nécessaire au déplacement des voitures. Le premier tableau contiendra les valeurs des touches pour déplacer la voiture A, et le second, les valeurs pour la voiture B.

var touches_a:Array = new Array(Key.LEFT, Key.RIGHT, Key.UP);
var touches_b:Array = new Array(81, 68, 90);

Ensuite, puisqu'on a deux voitures, on va créer une seule et unique fonction de déplacement, qu'on associera aux deux voitures :

this.controle_voiture = function() {
        //Le code pour le déplacement
}
// On associe la fonction aux événements onEnterFrame des deux voitures
this.voiture_a.onEnterFrame = this.controle_voiture; 
this.voiture_b.onEnterFrame = this.controle_voiture;

Le problème, c'est que je ne veux pas associer les événements à la fonction dès le départ, sinon le jeu commencerait tout de suite !
On va donc créer une fonction qui activera les voitures. Et pour l'instant, on appelera cette fonction une fois pour chaque voiture dès le départ, pour pouvoir tester nos voitures !

this.controle_voiture = function() {
        //Le code pour le déplacement
}
this.activer_voiture = function(nom) {
        this['voiture_'+nom].onEnterFrame = this.controle_voiture; 
        this['voiture_'+nom].nom = nom; // On donne son nom à la voiture ...
}
this.activer_voiture('a');
this.activer_voiture('b');
Déplacements

On va d'abord s'interroger sur le fonctionnement de la voiture. Elle devra avoir deux variables : rotation et vitesse.

Rotation

Pour la rotation c'est facile, on va utiliser la propriété _rotation du clip, ça nous fera gagner du temps :p

On va effectuer une condition assez complexe. On veut vérifier que la touche gauche est pressée. On utilise donc
Key.isDown(latouche).

Mais la valeur de cette touche est contenue dans un tableau sur la scène principale :
Key.isDown(this._parent.letableau[latouche])

Le tableau se nomme touches_a, ou touches_b, selon la voiture, ça tombe bien, puisque que dans la fonction activer_voiture, on a transmis à la voiture son nom dans la variable nom.
Key.isDown(this._parent['touches_'+this.nom][latouche])

La touche correspondante à gauche, c'est la première valeur du tableau, ce qui nous donne :
Key.isDown(this._parent['touches_'+this.nom][0])

Vous refaites ce raisonnement pour l'autre touche, et ça nous donne ce code :

this.controle_voiture = function() {
        if (Key.isDown(this._parent['touches_'+this.nom][0])) {
                this._rotation += -5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][1])) {
                this._rotation += 5;
        }
}

A ce stade, vous pouvez déjà tester votre code en déplaçant les voitures sur la scène avant de compiler. Vous verrez qu'elles tournent selon la touche appuyée.

En avant

On sait tourner, mais il faudrait maintenant avancer !
Si vous connaissez un peu la mécanique newtonienne, et si vous ne la connaissez pas, vous pouvez l'imaginer, quand vous appuyez sur l'accélérateur de la voiture, vous agissez sur son accélération. L'accélération, c'est la dérivée de la vitesse par rapport au temps ; en clair : à chaque fois que vous appuyez sur l'accélérateur, vous incrémentez la vitesse de la voiture. Et la vitesse de la voiture, c'est la dérivée de la position par rapport au temps : en clair, la position est égale à la position d'avant plus la vitesse.

Si vous n'avez pas compris, ce n'est pas bien grave, puisque je ne vais pas utiliser de formule de physique, mais simplement des équations que tout le monde peut deviner par lui-même.
La première chose à faire, c'est de créer une variable vitesse pour chaque voiture. Ça va être facile, puisqu'on a une fonction activer_voiture :

this.activer_voiture = function(nom) {
        this['voiture_'+nom].onEnterFrame = this.controle_voiture;
        this['voiture_'+nom].nom = nom;
        this['voiture_'+nom].vitesse = 0; //La vitesse est nulle au départ
};

Ensuite, il faut faire en sorte d'augmenter la vitesse à chaque fois qu'on appuie sur la touche avant :

this.controle_voiture = function() {
        if (Key.isDown(this._parent['touches_'+this.nom][0])) {
                this._rotation += -5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][1])) {
                this._rotation += 5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][2])) {
                        this.vitesse += 0.5;
        }
};

Il faut maintenant rajouter une condition pour limiter la vitesse ; moi, j'ai décidé de fixer une limite à 10pixels/images.
Il faut aussi prendre en compte les frottements : pour tricher avec la physique, on va dire que quand on n'accélère pas, la voiture perd de la vitesse jusqu'à atteindre la vitesse nulle (sinon elle repart en arrière :( ).

if (Key.isDown(this._parent['touches_'+this.nom][2])) {
        if (this.vitesse<10) {
                this.vitesse += 0.5;
        }
} else {
        if (this.vitesse>0) {
                this.vitesse -= 0.5;
        }
}

Le problème, c'est que la voiture n'avance pas pour autant. :D
Il va falloir faire un lien entre la vitesse de la voiture, et sa vitesse sur l'axe des abscisses et des ordonnées, en fonction de la rotation.

On va donc utiliser les fonctions trigonométriques que sont sinus et cosinus. Pour ceux qui ont lu l'annexe sur la rotation d'un clip en fonction de la souris, vous connaissez déjà la technique !
Sauf que là, on fait exactement l'inverse. :D

Image utilisateur

En fait, on va projeter la vitesse sur les deux axes, pour savoir comment faire avancer la voiture.
On cherche le projeté vitesse_x sur l'axe des abscisses, et le projeté vitesse_y sur l'axe des ordonnées. Normalement, depuis le collège, vous devriez savoir faire ça.

Sur le schéma à droite, j'ai récapitulé les "formules" de base de trigonométrie dans le triangle rectangle.
Le petit point noir représente la voiture, le trait rouge la vitesse, et les traits bleus et verts les projetés de cette vitesse sur les axes. Ce qu'on veut, c'est ajouter à la position de la voiture la valeur de ces projetés.

Flash nous offre les fonctions Math.sin() et Math.cos(), qui fonctionnent en radians. Le problème, c'est que _rotation s'exprime en degrés. Pour convertir un degré en radian, il faut le multiplier par PI (Math.PI), et le diviser par 180.

Je vais arrêter le suspense ici, et vous laisser contempler le code qui va vous permettre d'avancer :

this.controle_voiture = function() {
        if (Key.isDown(this._parent['touches_'+this.nom][0])) {
                this._rotation += -5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][1])) {
                this._rotation += 5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][2])) {
                if (this.vitesse<10) {
                        this.vitesse += 0.5;
                }
                
        } else {
                if (this.vitesse>0) {
                        this.vitesse -= 0.5;
                }
        }
        this._y += Math.sin(this._rotation*(Math.PI/180))*this.vitesse;
        this._x += Math.cos(this._rotation*(Math.PI/180))*this.vitesse;
};

Vous pouvez tester, c'est déjà entièrement fonctionnel. Mais ce que je n'aime pas, c'est la tenue de route de la voiture. J'aimerais qu'elle puisse déraper à fond. Pour donner une conduite un peu plus "fun" à notre voiture, on va faire en sorte qu'elle ne tourne QUE quand on accélère. :p

En clair, on récupère l'angle de la voiture quand elle accélère, et on l'utilise pour calculer les projetés. Quand la voiture n'accélère pas, on conserve l'angle précédent. Ça nous donne donc :

this.controle_voiture = function() {
        if (Key.isDown(this._parent['touches_'+this.nom][0])) {
                this._rotation += -5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][1])) {
                this._rotation += 5;
        }
        if (Key.isDown(this._parent['touches_'+this.nom][2])) {
                if (this.vitesse<10) {
                        this.vitesse += 0.5;
                }
                this.direc = this._rotation;
        } else {
                if (this.vitesse>0) {
                        this.vitesse -= 0.5;
                }
        }
        this._y += Math.sin(this.direc*(Math.PI/180))*this.vitesse;
        this._x += Math.cos(this.direc*(Math.PI/180))*this.vitesse;
};

Libre à vous de conserver le code précédent : mais je trouve celui-là beaucoup plus intéressant à jouer.

Pour ceux qui voudraient comparer leur source avec la mienne à ce stade :


Point de départ Les goals

Les goals

Faire mumuse avec la voiture Collisions inside

Les goals

Maintenant commence la partie sur les collisions. Ce qu'on veut, c'est que la voiture reste sur la route : en clair, elle peut avancer tant qu'il y a collision entre le clip voiture_a (et voiture_b aussi, bien sûr) et le clip route.
Sinon, qu'est-ce qui se passe ? On remet la voiture au Goal précédent.

On va devoir tester les collisions entre goals et voiture. Il faudra effectuer un test entre la voiture et le goal suivant. Ça va être facile puisque les goals portent les noms goal0, goal1, goal2, etc.

Dans activer_voiture, vous allez rajouter cette ligne :

this['voiture_'+nom].dernier_goal = -1;

En clair, on crée une variable dernier_goal pour chaque voiture. Pour l'instant cette variable vaut -1.

On va donc effectuer à chaque image un test de collision entre la voiture et le clip goal, suivi du nombre dernier_goal+1.

Le petit problême qui se pose, c'est que les clips goals ne sont pas dans le même clip que voiture...
Prenons l'exemple de voiture_a :

voiture_a appartient à _root.
Donc, pour accéder à _root depuis voiture_a, on écrit this._parent (on pourrait écrire _root tout simplement, mais je préfère qu'on s'amuse un peu avec les chemins relatifs).

goalX (avec X représentant le numéro du goal) appartient à route qui appartient à _root.

Pour accéder à un goal depuis voiture_a, il faudra donc écrire :

this._parent.route["goal"+X]

Et X représente le numéro du dernier goal franchi, plus 1 !

On a donc this._parent.route["goal"+(this.dernier_goal+1)]

Quand on passe par un goal, on va enregistrer la position de la voiture, ainsi que sa rotation, pour pouvoir la replacer à l'endroit exact où elle est passée, quand elle touchera un mur.

if (this._parent.route["goal"+(this.dernier_goal+1)].hitTest(this._x, this._y, true)) {
        this.dernier_goal++;
        this.dernier_x = this._x;
        this.dernier_y = this._y;
        this.dernier_rotation = this._rotation;
}

Vous pouvez tester en incluant un trace('je passe la porte'+this.dernier_goal); dans le code précédent, tout fonctionne !

Mais un nouveau problême se pose ! :D Au bout d'un moment, on repassera par la porte numéro 0 ! Il va donc falloir ruser. :p Je suppose que vous êtes d'accord pour dire que la solution la plus simple est de remettre dernier_goal à -1 quand on passe la dernière porte. Mais comment connaître le numéro de la dernière porte, puisque, quand on construit le circuit, on en met autant qu'on veut ? :euh:

On pourrait tout simplement créer une variable nombre_goal, où on indiquerait le nombre de portes qu'on a mis. Mais cette solution ne me satisfait pas, je veux que ce soit fait dynamiquement, et que je puisse changer le circuit quand je veux, sans toucher à l'ActionScript.

Bon. Je vous donne une solution, qui vaut ce qu'elle vaut (forcément :D ).
Au tout début début de votre code, on va chercher ce que vaut la variable nombre_goal. Pour cela, on va faire une boucle qui incrémentera la variable nombre_goal ,tant qu'elle trouvera un goal.

var nombre_goal = 0;
while (this.route['goal'+nombre_goal] != undefined) {
        nombre_goal++;
}

Comme vous pouvez le deviner, au bout d'un moment, this.route['goal'+nombre_goal] ne fera plus référence à un clip, et deviendra donc vide, c'est-à-dire undefined.
La variable nombre_goal contiendra donc le nombre de portes. :D

Bien entendu, vous faites ce calcul qu'une seule et unique fois au début de l'animation ; n'allez pas mettre cette boucle dans le onEnterFrame des voitures. :p

Bon ! Maintenant qu'on sait combien on a de goals, on va rajouter une condition dans controle_voiture.

Après le test de collision, rajoutez ce bloc :

if (this.dernier_goal == (this._parent.nombre_goal-1)) {
        this.dernier_goal = -1;
        this.tour++;
}

Pas besoin de vous l'expliquer. Par contre, vous pouvez vous poser des questions quant à la variable tour. Je viens de l'introduire, elle va permettre de comtper le nombre de tours de circuit effectué par la voiture. Mais pour l'instant, elle ne fonctionnera pas, parce qu'on ne l'a pas déclarée à 0 au départ.
Rajoutez donc cette ligne dans activer_voiture :

this['voiture_'+nom].tour = 0;

Faire mumuse avec la voiture Collisions inside

Collisions inside

Les goals Fignolages

Collisions inside

On a déjà écrit 60% du code, et pourtant, il manque quelque chose de primordial : les collisions, pour ne pas pouvoir sortir du circuit !

Vous allez voir, c'est très facile ! Toujours dans la fonction controle_voiture, il va falloir tester si la voiture est bien en collision avec le clip route, et si elle ne l'est pas (c'est-à-dire si elle est sortie de la route), il va falloir la ramener au point qu'on avait sauvegardé dans les variables dernier_x, dernier_y, et dernier_rotation.

Je pense que vous devriez essayer un peu tout seul, parce que c'est vraiment facile. :p Si vous n'avez pas trouvé dans 10 minutes, la solution est ci-dessous :

if (!this._parent.route.hitTest(this._x, this._y, true)) {
        this._x = this.dernier_x;
        this._y = this.dernier_y;
        this._rotation = this.dernier_rotation;
        this.vitesse = 0;
}

Bah voilà, c'est fini. :D
Vous pouvez remarquer qu'on remet la vitesse à 0 pour éviter que la voiture se prenne un mur en boucle. ;)


Les goals Fignolages

Fignolages

Collisions inside Des améliorations

Fignolages

Eh oui, on a le coeur du système, mais il va falloir fignoler !

Prêt ? Partez !

On va déjà activer notre feu tricolore.
Supprimez les deux lignes suivantes de votre code :

this.activer_voiture('a');
this.activer_voiture('b');

Rajoutez ça à la place :

this.feu_tricolore.onRelease = function() {
        this._parent.compteur_temps = 0;
        this.onEnterFrame = this._parent.activation_feu;
};

Quand on cliquera sur le feu tricolore, on va initialiser la variable compteur_temps sur _root à 0, et associer _root.onEnterFrame à une fonction qu'on va écrire maintenant.

Dans cette fonction, on va incrémenter de façon constante la variable compteur_temps, et à chaque fois qu'elle dépassera un certain seuil, on allumera une loupiotte du feu tricolore. :D

this.activation_feu = function() {
        this._parent.compteur_temps++;
        if (this._parent.compteur_temps == 10) {
                // Première lampe
        } else if (this._parent.compteur_temps == 30) {
                // Seconde lampe
        } else if (this._parent.compteur_temps == 50) {
                // Troisième lampe + départ
        } else if (this._parent.compteur_temps>=50) {
                // c'est fini, on fait disparaitre le feu, et on arrête le onEnterFrame
                this._alpha--;
                if (this._alpha<=0) {
                        this.onEnterFrame = null;
                }
        }
};

Maintenant, on va changer la couleur des lampes ; allez vite potasser le cours précédent pour retrouver les fonctions qui permettent de colorer un clip. :)

Je vous rappelle qu'il va falloir importer des librairies tout au début du code :

import flash.geom.ColorTransform;
import flash.geom.Transform;

Il va falloir créer des transformations de couleurs.

/* -> Couleur rouge */
var couleur_rouge:ColorTransform = new ColorTransform();
couleur_rouge.rgb = 0xFF0000;
/* -> Couleur verte */
var couleur_vert:ColorTransform = new ColorTransform();
couleur_vert.rgb = 0x00FF00;

Il faut aussi créer des transformations pour les clips du feu tricolore :

var vers_rouge_1:Transform = new Transform(feu_tricolore.couleur_1);
var vers_rouge_2:Transform = new Transform(feu_tricolore.couleur_2);
var vers_vert:Transform = new Transform(feu_tricolore.couleur_3);

Et ensuite, il ne reste plus qu'à associer les deux, et à lancer la partie. Donc, pour reprendre le code dans sa totalité, on a :

import flash.geom.ColorTransform;
import flash.geom.Transform;

// -TOUT LE RESTE DU CODE DEJA MIS

/* Démarrage du jeu - feu tricolore */
/* -> Couleur rouge */
var couleur_rouge:ColorTransform = new ColorTransform();
couleur_rouge.rgb = 0xFF0000;
/* -> Couleur verte */
var couleur_vert:ColorTransform = new ColorTransform();
couleur_vert.rgb = 0x00FF00;
/* -> Assignation des transformations aux clips */
var vers_rouge_1:Transform = new Transform(feu_tricolore.couleur_1);
var vers_rouge_2:Transform = new Transform(feu_tricolore.couleur_2);
var vers_vert:Transform = new Transform(feu_tricolore.couleur_3);

this.activation_feu = function() {
        this._parent.compteur_temps++;
        if (this._parent.compteur_temps == 10) {
                vers_rouge_1.colorTransform = couleur_rouge;
        } else if (this._parent.compteur_temps == 30) {
                vers_rouge_2.colorTransform = couleur_rouge;
        } else if (this._parent.compteur_temps == 50) {
                vers_vert.colorTransform = couleur_vert;
                this._parent.activer_voiture('a');
                this._parent.activer_voiture('b');
        } else if (this._parent.compteur_temps>=50) {
                this._alpha--;
                if (this._alpha<=0) {
                        this.onEnterFrame = null;
                }
        }
};
/* -> Lancement du jeu si clic de la souris */
this.feu_tricolore.onRelease = function() {
        this._parent.compteur_temps = 0;
        this.onEnterFrame = this._parent.activation_feu;
};
Activation des voitures et du compteur

Comme vous pouvez le constater, au départ les voitures ne sont pas placées sur la ligne de départ. Nous allons y remédier, en créant une fonction qui place tout bien au départ :

this.creer_voiture = function(nom) {
        var voiture = this['voiture_'+nom];
        voiture.nom = nom;
        voiture._x = this.route.goal0._x;
        voiture._y = this.route.goal0._y;
        voiture._rotation = this.route.goal0._rotation;
        voiture.vitesse = 0;
        voiture.dernier_goal = -1;
        voiture.tour = 0;
};
this.creer_voiture('a');
this.creer_voiture('b');

Comme vous pouvez le constater, cette fonction ressemble beaucoup à activer_voiture, mais elle est appelée dès le départ !

Rajoutez dans cette fonction ces quelques lignes :

var compteur = this['compteur_'+nom];
compteur.nom = nom;
compteur.voiture = 'Voiture '+nom;
compteur.tour = '0 / '+this.nombre_tour;
compteur.vitesse._xscale = 0;

Cela permet d'initialiser les compteurs.

On va d'ailleurs s'en occuper, des compteurs !

On va créer une fonction qui va leur permettre d'aller chercher les infos qui les intéressent dans le clip voiture, ce qui va être facile, puisqu'on a introduit dans chaque compteur un nom qui correspond au nom de la voiture (a ou b).

this.controle_compteur = function() {
        this.tour = this._parent['voiture_'+this.nom].tour+' / '+this._parent.nombre_tour;
        this.vitesse._xscale = 10*this._parent['voiture_'+this.nom].vitesse;
};

Et il faut bien sûr associer cette fonction au onEnterFrame de chaque compteur dans la fonction activer_voiture. Rajoutez donc dedans :

this['compteur_'+nom].onEnterFrame = this.controle_compteur;

Voilà, maintenant tout est parfaitement fonctionnel ! On a juste oublié un tout petit détail. :D La fin du jeu !

C'est tout bête, il suffit de créer un champ de texte dynamique sur la scène principale, portant la variable gagnant.

Ensuite allez chercher cette ligne de code :

if (this.dernier_goal == (this._parent.nombre_goal-1)) {
        this.dernier_goal = -1;
        this.tour++;
}

Et faites fonctionner vos méninges pour savoir ce qu'il faut y rajouter :D

Solution :

if (this.dernier_goal == (this._parent.nombre_goal-1)) {
        this.dernier_goal = -1;
        this.tour++;
        if ((this.tour == this._parent.nombre_tour) && (_root.gagnant == null)) {
                _root.gagnant = 'Le gagnant est voiture '+this.nom;
        }
}

Collisions inside Des améliorations

Des améliorations

Fignolages Sécurité et Flash

Des améliorations

On va apporter une petite amélioration, et ensuite vous pourrez proposer les vôtres dans les commentaires. :D

Personnellement, j'adore les effets de transparence, et je trouve que ça ne se voit pas assez quand on passe par une porte.

On va donc créer une fonction qui baisse la transparence au cours du temps, jusqu'à 50% :

this.controle_goal = function() {
        if (this._alpha>50) {
                this._alpha--;
        }
};

Et on va l'associer avec le onEnterFrame de chaque goal dans la boucle qu'on utilisait pour déterminer le nombre de portes, qui devient donc :

while (this.route['goal'+nombre_goal] != undefined) {
        this.route['goal'+nombre_goal].onEnterFrame = this.controle_goal;
        nombre_goal++;
}

Faites attention à placer la fonction controle_goal AVANT la boucle, sinon l'association ne pourra pas se faire puisque la fonction n'existe pas encore pour Flash.

Maintenant, c'est à vous de faire fonctionner vos méninges, et d'apporter vos propres améliorations pour faire un petit jeu convivial. Je peux vous donner quelques pistes :
- permettre de faire plusieurs chemins possibles (problème des goals, il faut actuellement passer par tous ; alors, on ne peut pas en mettre dans les branches ...).
- Rajouter des armes :p (un super-pouvoir pour chaque voiture, activable une seule fois par exemple, qui crée un tremblement de terre, ou stoppe la voiture ennemie ...).

Si ce que vous avez fait ne fonctionne pas ou mal, ou que vous n'avez pas compris certains passages de mon tutorial, voilà la source du jeu fini et (plus ou moins) commenté :

Bon. Après un gros tuto comme ça, je vais aller prendre quelques semaines de sommeil, moi. :p

J'en profite pour préciser que si vous avez des idées pour le fil rouge du 6ème chapitre (c'est pas demain la veille), donnez-les maintenant, que je m'y prépare. ;)

A la fin de ce chapitre, vous avez toutes les connaissances requises pour faire ce que vous voulez avec Flash. Cependant, Flash seul ne suffit plus, il va falloir le coupler avec une technologie côté serveur. :D


Fignolages Sécurité et Flash

Sécurité et Flash

Des améliorations crossdomain.xml

Nous allons étudier, dans la suite de ce chapitre, de nombreuses méthodes qui permettent de charger du contenu, dynamique ou non.
Mais depuis sa version 7, le Flashplayer intègre un nouveau dispositif de sécurité, qui empêche le chargement de données à partir d'un domaine distant.

crossdomain.xml

Sécurité et Flash Structure de crossdomain.xml

crossdomain.xml

Imaginons que vous ayez une animation Flash sur votre site. Si vous lui demandez de charger des données textes ou binaires (images ou animations Flash) dans le même domaine, il n'y a pas de problème. Par même domaine, j'entends que vous utilisez un chemin d'accès relatif pour accéder aux données comme "monfichiertexte.txt", si le fichier est dans le même dossier que l'animation.

Maintenant, si vous utilisez un chemin d'accès complet pour accéder aux données, Flash ne se posera pas la question de savoir si le domaine est le même que celui de l'animation (ou pas) : il refusera l'accès aux données !

Sauf si vous placez à la racine du domaine un fichier bien spécial, un fichier texte au format XML pour être précis, il s'agit du fichier : crossdomain.xml.


Sécurité et Flash Structure de crossdomain.xml

Structure de crossdomain.xml

crossdomain.xml Nouveautés de FlashPlayer 8

Structure de crossdomain.xml

Maintenant, placez-vous du côté du webmaster qui veut, ou ne veut pas, faire charger des données à partir d'une animation hébergée sur un autre site.

Il va devoir placer un fichier crossdomain.xml à la racine de son site Web pour préciser les autorisations. Ce fichier sera chargé automatiquement par une animation Flash qui tenterait d'accéder aux données sur le domaine.

Voici un schéma résumant la situation :

Image utilisateur

Bref, ne sachant pas si vous utiliserez des chemins d'accès absolus ou pas, on va prévenir tout risque, et installer notre petit fichier XML à la racine de notre site.

Voilà comment se présente un crossdomain.xml classique :

<?xml version="1.0"?>
<cross-domain-policy>
        <allow-access-from domain="domaine_a_autoriser" />
</cross-domain-policy>

Il vous suffit de remplacer domaine_a_autoriser par le domaine que vous souhaitez autoriser.

Par exemple, si le Site du Zéro voulait autoriser l'accès à son site aux animations Flash, il faudrait que le Webmaster place à la racine du site (http://www.siteduzero.com/crossdomain.xml) un fichier xml qui autorise l'accès provenant de tous les domaines, on utilise donc l'étoile * comme "joker" :

<?xml version="1.0"?>
<cross-domain-policy>
        <allow-access-from domain="*" />
</cross-domain-policy>

On pourrait aussi accepter que les données ne soient chargées que de sites possédant un nom de domaine français en .fr et allemand en .de :

<?xml version="1.0"?>
<cross-domain-policy>
        <allow-access-from domain="*.fr" />
        <allow-access-from domain="*.de" />
</cross-domain-policy>

Je pense que vous avez bien compris. :D


crossdomain.xml Nouveautés de FlashPlayer 8

Nouveautés de FlashPlayer 8

Structure de crossdomain.xml Contourner la protection

Nouveautés de FlashPlayer 8

Le Flashplayer 8 offre une nouveauté intéressante : il nous permet de spécifier le chemin d'accès à un fichier crossdomain.xml.
C'est une option qui n'est pas très utile, car comme tout le monde ne possède pas le dernier FlashPlayer, il est préférable de conserver le fichier crossdomain.xml à la racine des sites Web.

Voilà comment s'y prendre : le fichier crossdomain.xml doit toujours être placé dans le site, mais il n'est plus indispensable qu'il se trouve à la racine. Il faudra par contre préciser dans l'animation Flash où il se trouve.

System.security.loadPolicyFile("http://www.tondomaine.com/crossdomain.xml");

Cette ligne de code est en fait superflue, puisque FLash irait de toute façon chercher le crossdomain.xml à la racine du site !

Mais vous pourriez tout aussi bien vous adapter à un fichier de police placé de façon non standard :

System.security.loadPolicyFile("http://www.tondomaine.com/undossier/unfichier.xml");

Structure de crossdomain.xml Contourner la protection

Contourner la protection

Nouveautés de FlashPlayer 8 Images et Animations

Contourner la protection

Nous allons maintenant voir une petite astuce toute bête permettant de "contourner" cette protection. J'écris "contourner" entre guillemets, car cette protection n'est pas là pour embêter le créateur d'une animation, ou l'utilisateur lambda. Elle permet seulement aux webmasters qui le souhaitent de protéger leur site Web d'un téléchargement abusif s'effectuant à partir des clients exécutant l'animation.

Alors qu'avec notre astuce, l'animation téléchargera les données en passant par un script sur votre serveur. Ça ne sera donc pas à votre avantage de faire télécharger des données d'un site web de façon abusive, puisque ça encombrera le vôtre !

Vous allez déjà placer un crossdomain.xml à la racine de votre site pour éviter les ennuis.

Ensuite, vous allez créer un fichier chargement.php :

<?PHP
readfile($_GET['lien']);
?>

Ainsi, si vous devez charger un fichier dans votre animation, et que ce fichier est placé sur un autre site Web sans crossdomain.xml, vous pourrez passer par votre fichier chargement.php.

Par exemple, si vous voulez charger dans votre animation la liste des news du SDZ à cette adresse http://www.siteduzero.com/Templates/xml/news_fr.xml, comme www.siteduzero.com ne possède pas de crossdomain.xml, vous aller charger cette page : chargement.php?lien=http://www.siteduzero.com/Templates/xml/news_fr.xml

En fait, il est même préférable "d'encoder" le lien avec la fonction escape() de Flash que nous avons déjà vu dans un chapitre précédent.
Une fois encodée au format URL, votre animation chargerait en fait :
chargement.php?lien=http%3A%2F%2Fwww%2Esiteduzero%2Ecom%2FTemplates%2Fxml%2Fnews%5Ffr%2Exml
Mais il faudrait alors décoder le lien dans le script PHP :

<?PHP
$lien = urldecode($_GET['lien']);
readfile($lien);
?>

Bon. Pour l'instant, vous ne savez pas encore comment charger ce fichier dans Flash, mais vous connaissez au moins la théorie. ;)

Vous l'aurez compris, pour être tranquille, il est indispensable de créer un fichier crossdomain.xml à la racine des sites d'où vous désirez charger du contenu.

L'utilité de System.security.loadPolicyFile() peut vous paraître superflue, mais nous verrons peut-être beaucoup plus loin dans ce tutoriel, que cette méthode a son importance quand on possède un serveur xmlsocket.

Vous devez aussi garder en tête que cette protection permet surtout de protéger le webmaster d'un site qui ne souhaite pas se faire "voler" des centaines de mégaoctets. Néanmoins, il est très facile de contourner cette protection en utilisant un script PHP, mais dans ce cas, les données circuleront par le site web hébergeant l'animation.


Nouveautés de FlashPlayer 8 Images et Animations

Images et Animations

Contourner la protection Dans un clip ou un niveau

Nous allons, tout d'abord, apprendre à charger dans notre animation d'autres animations, et / ou des images aux formats JPG, PNG et GIF (support des PNG et GIF à partir de Flash player 8) de façon dynamique.

Flash intègre, depuis ses dernières versions, une classe sensée faciliter le chargement de fichiers images, ou SWF externes (la classe MovieClipLoader), mais puisqu'on est des pros, on va s'en passer. ;)

Durant tout ce tuto, nous nous efforcerons de charger cette image :

Image utilisateur

Vous pouvez donc dès maintenant rajoutez cette variable en haut de votre code :

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';

L'image est lourde, si elle pèse plus de 800ko, c'est pour pouvoir observer son chargement avec un preloader.

Dans un clip ou un niveau

Images et Animations Un chargeur

Dans un clip ou un niveau

Il existe deux fonctions pour charger une image (ou un SWF) dans votre animation :

loadMovieNum(lien,niveau)

Nous allons vite passer sur la première fonction, car nous ne l'utiliserons pas. Elle permet de charger le contenu dans un niveau de l'animation. Attention : ne confondez pas niveau et profondeur ! Les profondeurs, c'est pour les clips, les niveaux, c'est uniquement des "calques" dans lesquels vous pouvez placer des animations complètes. D'ailleurs, même sans charger une animation externe avec loadMovieNum(), il existe déjà un niveau dans votre animation : le niveau 0. Vous pouvez y accéder grâce à _level0.

_root est en fait une référence au level dans lequel vous tapez votre code. La plupart du temps _root et _level0 sont donc confondus !

Vous pouvez d'ailleurs le vérifier aisément avec la fonction trace() :

trace(_root); // Affiche _level0 dans la fenêtre Sortie

Donc, pour vous faire plaisir, je vous montre comment charger notre astronaute avec cette fonction, mais nous ne l'utiliserons plus après !

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';
loadMovieNum(lien,1);
MovieClip.loadMovie(lien)

Cette méthode me plaît mieux. :D Vous remarquez déjà que contrairement à l'autre fonction, celle-là appartient à une classe, et pas n'importe laquelle : MovieClip !

On va donc charger notre image dans un clip, et pour être plus précis, on va même remplacer ce clip par l'image, il ne faudra donc rien laisser d'important dans ce clip, car tout sera supprimé par l'image !

Un petit code qui nous permet de charger l'image dans un clip vide créé dynamiquement :

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';
this.createEmptyMovieClip('image',1) // Créé un clip vide;
this.image.loadMovie(lien); // Remplace le clip par l'image

Encore une fois, soyez patient ! Il faut le temps de charger l'image !


Images et Animations Un chargeur

Un chargeur

Dans un clip ou un niveau Redimensionner l'image

Un chargeur

Moi je veux bien attendre une minute que l'image se charge, mais comment afficher l'état d'avancement ?

Pour cela, on va créer un chargeur (ou preloader, en anglais dans le texte).
Je vais vous montrer deux méthodes de la classe MovieClip.

getBytesLoaded et getBytesTotal

Ce sont sûrement les méthodes les plus simples à utiliser !

monclip.getBytesTotal() renvoie la taille en octets d'un clip
monclip.getBytesLoaded() renvoie en octets ce qui a été chargé du clip pour l'instant

Donc, si on veut connaître le pourcentage de chargement d'un clip, on fait :

pourcentage = (unclip.getBytesLoaded() / unclip.getBytesTotal() ) * 100;
Chargeur texte

Voilà un code qui permet d'afficher la progression du chargement, la zone de texte se crée en haut à gauche de l'animation dynamiquement :

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';
// On crée deux clips, un pour recevoir l'image, l'autre pour le preloader
this.createEmptyMovieClip('image', 1);
this.createEmptyMovieClip('chargeur', 2);
// On crée un champ de texte dans chargeur et on charge l'astronaute dans image
this.chargeur.createTextField('pourcentage', 1, 0, 0, 100, 20);
this.image.loadMovie(lien);
// On regarde à chaque image où en est le chargement
this.chargeur.onEnterFrame = function() {
        this.pourcentage.text = (this._parent.image.getBytesLoaded()/this._parent.image.getBytesTotal())*100;
};

Ce code fonctionne, mais on ne peut pas dire que ce soit ce qu'il y a de plus beau ; on va donc lui apporter quelques améliorations :

On va donc :

Ce qui nous donne :

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';
// On crée deux clips, un pour recevoir l'image, l'autre pour le preloader
this.createEmptyMovieClip('image', 1);
this.createEmptyMovieClip('chargeur', 2);
// On crée un champ de texte dans chargeur et on charge l'astronaute dans image
this.chargeur.createTextField('pourcentage', 1, 0, 0, 100, 20);
this.image.loadMovie(lien);
// On regarde à chaque image où en est le chargement
this.chargeur.image = this.image;
this.chargeur.onEnterFrame = function() {
        this.pourcentage.text = (Math.round(((image.getBytesLoaded()/image.getBytesTotal())*100)).toString())+' %';
};
Chargeur graphique

Le texte c'est bien, facile à programmer, mais c'est pas très esthétique.
On va donc dessiner une barre de progression. On pourrait la dessiner complètement en ActionScript, grâce aux méthodes de dessin qu'on avait vu, mais rassurez-vous, on va les dessiner nous-mêmes avec l'IDE de Flash.

Créez donc un clip sur la scène principale, et donnez-lui pour nom d'occurrence : chargeur
Dans ce clip, dessinez deux rectangles : ils doivent être de la même taille et se superposer ; celui du dessous devrait un peu déborder sur les côtés. Transformez celui du dessus en un clip auquel vous donnerez comme nom d'occurrence : barre. Placez le centre de barre comme vous le souhaitez par rapport au rectangle, selon l'effet que vous souhaiterez obtenir.

Vous allez voir, on ne va presque rien changer dans le code précédent.
Il ne sert plus à rien de créer le clip chargeur, puisqu'on l'a déjà, donc on supprime la ligne.
Idem pour la zone de texte qui est devenue inutile, puisqu'on affiche la progression sous forme graphique.
On ne va plus affecter le pourcentage à la propriété text d'une zone de texte, mais à la propriété _xscale de barre. On doit donc transmettre un nombre, on enlève donc le % et le tostring(). Éventuellement, on peut aussi enlever le Math.round(), qui ne sert plus à grand chose non plus.

Ça nous donne donc :

lien = 'http://uploads.siteduzero.com/files/105001_106000/105747.jpg';
// On crée un clip pour recevoir l'image
this.createEmptyMovieClip('image', 1);
// On charge l'astronaute dans image
this.image.loadMovie(lien);
// On regarde à chaque image où en est le chargement
this.chargeur.image = this.image;
this.chargeur.onEnterFrame = function() {
        this.barre._xscale = (image.getBytesLoaded()/image.getBytesTotal())*100;
};

Dans un clip ou un niveau Redimensionner l'image

Redimensionner l'image

Un chargeur Particularité du chargement des animations

Redimensionner l'image

Par contre, vous l'aurez remarqué je l'espère, on a un petit problème !
L'image se charge bien, mais elle est tellement grande qu'elle ne rentre pas dans l'animation.

Pas de problème, après avoir créé le clip, rajoutons :

this.image._width = Stage.width;
this.image._height = Stage.height;

Ça ne marche pas ! L'image n'est même plus du toute affichée !

Eh bien oui, on a fait une erreur ! On a donné une taille à un clip qui était encore vide ! Même si vous mettez ce code juste après le loadMovie(), vous aurez le même problème, car l'image n'étant pas chargée complètement, Flash ne peut toujours pas redimensionner le clip vide !

Il faut donc attendre que l'image soit chargée pour la redimensionner !
Dans le bloc de code de chargeur, on va donc rajouter une condition qui redimensionne l'image une fois qu'elle est chargée. On a donc :

this.chargeur.onEnterFrame = function() {
        this.barre._xscale = ((image.getBytesLoaded()/image.getBytesTotal())*100);
        if (image.getBytesLoaded() == image.getBytesTotal()) {
                image._width = Stage.width;
                image._height = Stage.height;
        }
};

Ça ne marche toujours pas !

Eh oui, en effet, essayez de deviner pourquoi. N'oubliez pas d'utiliser la fonction trace() !

Avant que l'image soit chargée, le clip image existe déjà ! Et il est complètement chargé (en plus, il est vide). Notre condition est donc validée au début, avant même le chargement de l'image. Or, on a vu au-dessus qu'il ne fallait surtout pas redimensionner un clip vide avant que l'image ne soit chargée, sinon ça ne fonctionne pas.
Il faut donc rajouter une condition supplémentaire : vérifier que le clip ne soit pas vide. Ainsi, on aura :

this.chargeur.onEnterFrame = function() {
        this.barre._xscale = ((image.getBytesLoaded()/image.getBytesTotal())*100);
        if ((image.getBytesLoaded() == image.getBytesTotal()) && (image.getBytesTotal()>0)) {
                image._width = Stage.width;
                image._height = Stage.height;
        }
};

Tout bête, n'est-ce pas ? :p

Ensuite, c'est à vous de trouver le code pour conserver les proportions de l'image lors du redimensionnement ; sur internet, vous en trouverez pour de nombreux langages, il ne restera plus qu'à l'adapter à votre animation !


Un chargeur Particularité du chargement des animations

Particularité du chargement des animations

Redimensionner l'image Transfert de variables

Particularité du chargement des animations

Eh oui, charger une animation dans un clip d'une autre animation, ça peut vite devenir un casse-tête, style poupées russes ! :p

Car l'animation qu'on charge peut contenir du code ActionScript. Tant que les références à l'intérieur de cette animation se font de façon relative : pas de problème ! Mais imaginez que vous utilisiez _root dans l'animation qui est chargée dans le clip ...
Oui, vous avez compris, le _root ne sera pas le _root de l'animation chargée, mais le _root de l'animation chargeur : un vrai problème !

Alors, soit vous réécrivez toutes vos animations pour vous assurer que vous n'utilisez jamais _root (et si vous avec bien suivi ce cours vous ne devriez n'avoir jamais utilisé _root jusqu'ici), soit vous suivez l'astuce suivante.

ActionScript, depuis la version 7, possède une nouvelle propriété pour les clips : _lockroot.
C'est une variable booléenne (elle prend les valeurs true ou false). Par exemple, si vous chargez une animation qui contient des chemins d'accès absolus (utilisant _root) dans le clip image de tout à l'heure, il faudra préciser avant de charger l'animation :

this.image._lockroot = true;
this.image.loadMovie(lien);

Et grâce à cette propriété, l'animation chargée conservera son _root propre ! :D

Vous savez maintenant charger du contenu graphique (image et SWF) externe ! Vous pouvez donc déjà créer des animations complexes qui peuvent charger dynamiquement des parties trop lourdes. Vous pouvez aussi commencer l'élaboration d'une galerie basique en Flash ! ;)

Mais il existe aussi d'autres types de contenus qu'on peut charger dans une animation : les variables et la musique. :p


Redimensionner l'image Transfert de variables

Transfert de variables

Particularité du chargement des animations La vieille technique

Nous avons appris comment charger des photos ou des animations Flash dynamiquement. C'est bien beau, mais encore faudrait-il savoir quel est le nom de l'image à télécharger !
On va donc s'intéresser à la classe LoadVars, qui permet d'effectuer une requête HTTP sur une page Web, ce qui nous permettra de récupérer des variables contenant ce dont on a besoin. :D

La vieille technique

Transfert de variables Chargement avec LoadVars

La vieille technique

Je vais d'abord vous présenter l'ancienne technique, car elle vous permettra de mieux comprendre les différents mécanismes.

Mettons-nous en situation

On va prendre la situation la plus simple possible. :D
Supposons que vous souhaitez afficher la progression d'un projet avec un petit graphique en Flash.

Image utilisateur

On pourrait passer directement les données à l'animation, comme nous l'avons fait dans Transmission des variables. Mais nous allons utiliser la technique inverse : c'est l'animation qui va aller chercher elle-même les informations qui l'intéressent !

On va déjà créer une petite animation toute bête, avec 4 barres colorées qui vont représenter la progression de votre projet dans 4 domaines différents. On donnera comme nom d'occurrence : barre_1, barre_2, barre_3 et barre_4.

En haut de votre graphique, vous pouvez rajouter un champ de texte dynamique de variable : titre

.

Les variables à charger

Flash va charger 5 variables : la progression pour les 4 barres, et le titre du graphique.

On va donc enregistrer ces variables dans un fichier texte, et on va encoder ces variables au format urlencode, comme nous l'avions déjà fait quand nous passions directement les variables à l'animation.

Créez donc un fichier graphique.txt :

Citation : graphique.txt

titre=Mon+graph&barre_1=50&barre_2=75&barre_3=15&barre_4=89

N'oubliez pas d'enregistrer votre fichier texte au format UTF-8. Dans le Bloc-Notes, par exemple, il faut faire Fichier-> Enregistrez Sous -> Codage -> UTF-8.

Grâce à l'UTF-8, vous n'aurez pas de problème avec les accents et caractères spéciaux, vous pourriez même mettre du chinois mandarin dans le titre de votre graphique. ;)

Du côté d'ActionScript

Maintenant qu'on a toutes les ressources nécessaires, reprenons notre animation, et passons à l'ActionScript.

La fonction loadVariables(url:String, target:Object); permet de charger les variables d'un fichier externe dans un objet.

Nous allons donc devoir créer un clip, qui va être chargé de recevoir les variables que nous allons charger, car les variables portant le même nom que des objets sur la scène, il y aurait un risque à les charger directement dans _root.

Ça commence donc comme ça :

this.createEmptyMovieClip("variables", this.getNextHighestDepth());
loadVariables("graphique.txt", variables);

Ensuite, il ne reste plus qu'à faire correspondre les variables :

_root.titre=variables.titre;
for (var i=1;i<=4;i++) {
_root['barre_'+i]._yscale = variables['barre_'+i];
}

Histoire de ne pas devoir écrire 4 fois barre_1._yscale = variables.barre_1, j'ai fait une petite boucle qui va le faire pour moi. ;)

Maintenant, testons l'animation. :D

o_O Pourquoi ça ne marche pas ?

Parce qu'on a oublié un "détail" gênant. On essaye d'utiliser des variables qui ne sont pas encore nécessairement chargées ! En effet, le temps de charger le fichier graphique.txt, Flash a déjà exécuté le code pour faire correspondre les variables...

Nous allons donc devoir attendre que toutes les variables soient chargées avant de les faire correspondre. Pour cela, nous allons exécuter à chaque image un script qui vérifiera que la dernière variable du fichier texte (barre_4) est bien chargée. Le cas échéant, on fait correspondre les variables et on arrête le code.

Allez, je vous ai tout dit : à vous de bosser, maintenant !

this.createEmptyMovieClip("variables", this.getNextHighestDepth());
loadVariables("graphique.txt", variables);
variables.onEnterFrame = function() { // On se place directement dans "variables"
        if (this.barre_4) { // Si barre_4 est défini 
                _root.titre = this.titre; // On est dans "variables", "this.titre" correspond à ce qui a été chargé du fichier texte
                for (var i = 1; i<=4; i++) {
                        _root['barre_'+i]._yscale = this['barre_'+i];
                }
                delete this.onEnterFrame; // Fait la même chose que "this.onEnterFrame = null;"
        }
};

Et maintenant, tout fonctionne parfaitement ! Vous pouvez même vérifier que les caractères accentués passent bien dans le titre.

Avantages et inconvénients

Cette méthode possède l'avantage d'être rapide à mettre en oeuvre au niveau du code. Par contre, elle n'est pas très propre, car elle fait appel à un onEnterFrame. Et dans une grosse animation, l'accumulation de ce genre de méthodes peut rendre l'application très lourde.

Nous allons donc passer à une méthode plus belle :D (comme quoi la programmation n'est qu'une affaire d'esthétique :lol: ).


Transfert de variables Chargement avec LoadVars

Chargement avec LoadVars

La vieille technique Envoyer des variables

Chargement avec LoadVars

Voilà la classe qui va tous nous sauver : LoadVars

Nous allons reprendre le même exemple que précédemment, et le mettre à la sauce LoadVars ! Vous pouvez déjà supprimer tout le code utilisant LoadVariables().

On n'a plus besoin du clip variables, on va utiliser par contre un objet loadvars pour charger les données. Pour ne pas se dépayser, on l'appellera aussi variables.

var variables:LoadVars = new LoadVars();

Maintenant, on va utiliser l'événement onLoad livré avec la classe LoadVars, qui va grandement nous faciliter la tâche. Cet événement est en effet appelé lorsque le chargement est terminé : plus besoin d'utiliser d'astuce avec onEnterFrame !

variables.onLoad = function() {
        _root.titre = this.titre;
        for (var i = 1; i<=4; i++) {
                _root['barre_'+i]._yscale = this['barre_'+i];
        }
};

Il suffit de reprendre le code précédent, et de remplacer onEnterFrame par onLoad. De plus, onLoad possède un argument bien pratique qui permet de savoir si le chargement a fonctionné ou pas. Notre code donnera donc :

variables.onLoad = function(succes:Boolean) {
        if (succes) {
                _root.titre = this.titre;
                for (var i = 1; i<=4; i++) {
                        _root['barre_'+i]._yscale = this['barre_'+i];
                }
        } else {
                trace("Quelque chose n'a pas fonctionné");
        }
};

Il ne reste plus que le plus important : le code pour charger les données.
Il faut utiliser la méthode load(), qui demande le chemin d'accès au fichier contenant les données comme argument. Le code complet sera donc le suivant :

var variables:LoadVars = new LoadVars();
variables.onLoad = function(succes:Boolean) {
        if (succes) {
                _root.titre = this.titre;
                for (var i = 1; i<=4; i++) {
                        _root['barre_'+i]._yscale = this['barre_'+i];
                }
        } else {
                trace("Quelque chose n'a pas fonctionné");
        }
};
variables.load("graphique.txt");

Et voilà ! Votre animation fonctionne parfaitement et proprement. ;)


La vieille technique Envoyer des variables

Envoyer des variables

Chargement avec LoadVars Exercice : Zozor dynamique

Envoyer des variables

C'est bien beau de pouvoir charger des variables, mais dans de nombreux cas, les variables que l'on chargera dépendront de la requête.

Imaginons que l'état d'avancement de votre projet ne doit être accessible que par mot de passe. On pourrait bien entendu conserver l'animation précédente, et rajouter un champ de texte, avec une bête vérification du mot de passe directement avec ActionScript avant de charger les données externes. Mais ça ne serait pas sécurisé, car il est possible de décompiler une animation Flash pour voir son code ActionScript, et donc le mot de passe, voire directement l'adresse du script auquel on fait appel !

Alors que si c'est le script PHP qui fait la vérification et ne renvoie les données que si le mot de passe est bon, le système devient inviolable (théoriquement :p ).

Nous allons donc transmettre le mot de passe par la méthode GET à notre script lors de la requête.

Du côté de PHP

Intéressons-nous déjà au script PHP qui va vérifier le mot de passe, et renvoyer les données.
Nous allons créer un fichier graph_pass.php en UTF-8.
Ce script recevra le mot de passe dans la variable $_GET['password']. (Nous prendrons comme mot de passe : sdz :D .)

Maintenant, à vous de jouer : faites moi ce petit script PHP ! :D

if ($_GET['password'] == 'sdz') {
echo 'titre=Mon+graphique&barre_1=50&barre_2=75&barre_3=15&barre_4=89';
} else {
echo 'titre=Accès+refusé';
}
Du côté de Flash

Rajoutez sur la scène un champ de saisie, et donnez-lui comme nom d'occurrence (je ne parle pas du nom de variable) : password.

Maintenant, nous avons deux possibilités pour envoyer le mot de passe (contenu dans la propriété text du champ de texte password, c'est-à-dire dans password.text) au script PHP.

- Soit on reprend le code précédent, et on rajoute soi-même la variable pour avoir une ligne de ce genre :

variables.load("graph_pass.php?password="+this.password.text);

- Soit on utilise un second objet loadVars, qui aura pour seule fonction d'envoyer la variable.

Méthode rapide

Je vous ai montré comment faire pour pouvoir envoyer rapidement la variable au script : à vous de modifier le code précédent, pour que les données soient chargées lorsque l'utilisateur appuie sur "Entrée".

Correction possible :

var variables:LoadVars = new LoadVars();
variables.onLoad = function(succes:Boolean) {
        if (succes) {
                _root.titre = this.titre;
                for (var i = 1; i<=4; i++) {
                        _root['barre_'+i]._yscale = this['barre_'+i];
                }
        } else {
                trace("Quelque chose n'a pas fonctionné");
        }
};
this.onEnterFrame = function() {
        if (Key.isDown(Key.ENTER)) {
                variables.load("http://www.jouhaud.eu/sdz/graph_pass.php?password="+this.password.text);
                this.password._visible = false;
        }
};
Méthode lente

Continuons avec le code que nous venons d'écrire.

Dans cette méthode, nous allons créer un second objet LoadVars tout au début du script :

var a_envoyer:LoadVars = new LoadVars();

Lors de l'appui sur "Entrée", nous allons préciser les données à transférer par a_envoyer

a_envoyer.password = this.password.text;

Et ensuite, nous allons modifier la ligne qui envoie le tout pour qu'elle puisse utiliser les deux loadVars en même temps :

a_envoyer.sendAndLoad("http://www.jouhaud.eu/sdz/graph_pass.php",variables,"GET");

Expliquons un peu cette ligne. L'objet qui contient les données à envoyer est l'objet qui porte la méthode sendAndLoad() : il s'agit ici de a_envoyer. Ensuite, en second argument, on doit préciser le nom de l'objet qui recevra les données retournées par le script PHP : variables. Enfin, en troisième argument, on précise la méthode de transmission : ici, c'est "GET".

Le code complet donne donc :

var variables:LoadVars = new LoadVars();
var a_envoyer:LoadVars = new LoadVars();
variables.onLoad = function(succes:Boolean) {
        if (succes) {
                _root.titre = this.titre;
                for (var i = 1; i<=4; i++) {
                        _root['barre_'+i]._yscale = this['barre_'+i];
                }
        } else {
                trace("Quelque chose n'a pas fonctionné");
        }
};
this.onEnterFrame = function() {
        if (Key.isDown(Key.ENTER)) {
                a_envoyer.password = this.password.text;
                a_envoyer.sendAndLoad("http://www.jouhaud.eu/sdz/graph_pass.php",variables,"GET");
                this.password._visible = false;
        }
};

C'est un peu plus long que l'autre méthode. Mais imaginez qu'on ait beaucoup de variables à transmettre ; si en plus, on devait utiliser la méthode POST, alors on serait obligés d'utiliser la seconde méthode avec les deux objets LoadVars.


Chargement avec LoadVars Exercice : Zozor dynamique

Exercice : Zozor dynamique

Envoyer des variables Musique !

Exercice : Zozor dynamique

Vous vous souvenez de notre premier fil rouge avec le Zozor qui parle ? :D
Vous pouvez visionner ici le résultat qu'on avait obtenu.

Nous allons le rendre dynamique, c'est-à-dire que nous stockerons sa réplique dans un fichier texte qui sera chargé et qui pourra être modifié par l'animation. :)

Téléchargez ici la source de notre Zozor comme il était à la fin de notre précédent fil rouge.

Côté serveur - PHP

Il vous faut créer deux fichiers :

Enregistrez zozor.txt en UTF-8 et surtout, surtout, n'oubliez pas de mettre son CHMOD à 777 grâce à votre logiciel de transfert FTP. Sinon, votre script ne pourra pas modifier le fichier.
Pour l'instant, vous pouvez mettre ça comme réplique :

Citation : zozor.txt

Salut je m'appelle Zozor, symbole du SDZ

Maintenant, nous allons coder un petit script PHP qui va aller lire ou écrire dans zozor.txt, selon la requête qu'on lui transmet.
Si l'animation veut lire la réplique, elle enverra la variable suivante au script PHP en POST :
action=lire

Si l'animation veut écrire une nouvelle réplique, elle devra en plus envoyer un mot de passe pour s'authentifier :
action=ecrire
password=sdz
replique=une nouvelle réplique

La première partie de notre script donnera donc :

if ($_POST['action'] == 'lire') {
echo 'replique='.file_get_contents('zozor.txt');
}

Maintenant, nous allons rajouter la partie qui permet de changer la réplique, et qui renvoie ensuite la nouvelle réplique :

if ( ($_POST['action'] == 'ecrire') && ($_POST['password'] == 'sdz') ) {
        $zozor = fopen('zozor.txt','w');
        fwrite($zozor, $_POST['replique']);
        fclose($zozor);
        echo 'replique='.file_get_contents('zozor.txt');
}

Ensuite, on n'a plus qu'à mettre tout ça bout à bout, et à prendre en compte le cas où l'animation envoie un mauvais code d'action, ou un mauvais mot de passe. Au total, ça donne :

if ($_POST['action'] == 'lire') {
        echo 'replique='.file_get_contents('zozor.txt');
} else if ( ($_POST['action'] == 'ecrire') && ($_POST['password'] == 'sdz') ) {
        $zozor = fopen('zozor.txt','w');
        fwrite($zozor, $_POST['replique']);
        fclose($zozor);
        echo 'replique='.file_get_contents('zozor.txt');
} else {
        echo 'replique=ca+bug+...';
}
Côté client - Flash

Reprenez donc notre Zozor là où nous l'avions abandonné. Dans le code déjà écrit, supprimez tout, sauf la partie qui gère les yeux. Supprimez même la partie qui gère le bonnet, il nous servira de bouton pour valider : il doit donc être tout le temps affiché.

Pour la réception simple de la réplique, le code est facile, il n'y a rien de nouveau :

//-
//- CONTENU DE LA BULLE
//-
var a_recevoir:LoadVars = new LoadVars();
var a_envoyer:LoadVars = new LoadVars();
//-- Lecture
a_recevoir.onLoad = function(succes:Boolean) {
        if (succes) {
                _root.bulle.htmlText = this.replique;
        } else {
                trace("Quelque chose n'a pas fonctionné");
        }
};
a_envoyer.action = 'lire';
a_envoyer.sendAndLoad("zozor.php", a_recevoir, "POST");

Maintenant, nous allons concevoir la partie "écriture". Commencez par créer une zone de saisie, et donnez-lui comme nom d'occurrence (je ne parle pas du nom de variable) : password

On va rendre cette zone invisible :

password._visible = false;

Il ne reste plus qu'à écrire ce qui doit se passer quand l'utilisateur clique sur le bonnet :

bonnet.onRelease = function() {
        if (!password._visible) {
                a_envoyer.action = 'ecrire';
                a_envoyer.replique = bulle.text;
                password._visible = true;
                password.text = 'mot de passe ?';
        } else {
                password._visible = false;
                a_envoyer.password = password.text;
                a_envoyer.sendAndLoad("zozor.php", a_recevoir, "POST");
        }
};

Ai-je besoin d'expliquer ?
L'utilisateur peut modifier la bulle, ensuite il clique sur le bouton. Flash stocke alors dans a_envoyer l'action qu'on souhaite effectuer, 'ecrire', et la nouvelle réplique. Il affiche la zone de saisie où on peut rentrer un mot de passe.
Ensuite quand on reclique, le mot de passe est ajouté à a_envoyer, et le tout est transmis au script PHP !
Enfin, quand Flash reçoit les données transmises par le script, la partie qu'on a déjà écrite est exécutée, car on utilise aussi a_recevoir : la bulle est donc mise à jour.

Surtout, n'hésitez pas à vous entraîner à utiliser les LoadVars, ce sont des objets indispensables.

Maintenant, vous avez la capacité de créer un mini-chat, en conjuguant Flash avec un script PHP, et éventuellement une base de données ! :D


Envoyer des variables Musique !

Musique !

Exercice : Zozor dynamique Préparation du terrain

On sait charger des images, des animations et des variables. Maintenant, nous allons apprendre à lire des sons, puis à charger des musiques au format mp3.

Préparation du terrain

Musique ! Lecture

Préparation du terrain

Flash possède la classe sound (son en français), qui permet une gestion simple des effets sonores en ActionScript.

Import statique

Avant de commencer à charger dynamiquement des sons, nous allons les charger dans Flash. Pour cela, cliquez sur Fichier -> Importer -> Importer dans la bibliothèque.
Puis choisissez la musique que vous désirez.

Image utilisateur

Votre son apparaît ensuite dans la bibliothèque : vous pouvez même l'écouter en utilisant les deux petits boutons, stop et lecture, dans la fenêtre de prévisualisation de la bibliothèque. (Le premier qui dit que j'ai des goûts de chio**e, je le sors. :D )

Qualité et compression

Image utilisateurEn sélectionnant votre son dans la bibliothèque, puis en cliquant sur Propriétés, vous pouvez modifier sa compression.

Vous pouvez conserver la compression originale du fichier importé, ou alors en décochant la case Utiliser la qualité mp3 importée, vous pourrez utiliser vos propres paramètres. Flash recompressera le son automatiquement lors de la compilation de l'animation, qui pourra durer alors très longtemps, pour peu que votre fichier son soit lourd.

En général, il est intéressant de convertir le son en Mono, puisque de toute façon sur le Web, on se fiche un peu que le son sortant de chaque baffle soit différent. De même, une vitesse de transmission de 64 kbits/s est dans la plupart des cas largement suffisante.
L'option Qualité vous permet de préciser la "qualité" de l'encodage subi par votre son. Plus la qualité sera haute, plus le temps mis lors de la publication sera long, et plus la qualité propre du son sera bonne. Attention, la qualité de l'encodage n'influe pas sur la taille du fichier audio.

En dessous, Flash vous indique en temps réel une estimation du poids de votre fichier son une fois compressé. Pour être sûr que la musique ne soit pas trop dégradée avec vos paramètres, vous pouvez cliquer sur le bouton Tester, en haut de la fenêtre.

Nom de liaison

Et comme pour tous les objets qui sont dans la bibliothèque, et que nous devons utiliser dans ActionScript, il va falloir lui donner un nom de liaison.

Il suffit de sélectionner le son, et de cliquer sur Liaison...Image utilisateur

Vous atterrissez sur la plus-que-connue fenêtre de liaison ActionScript. Vous devez donc cocher Exporter pour ActionScript, puis donner un nom de liaison pour votre fichier audio dans Identifiant


Musique ! Lecture

Lecture

Préparation du terrain Curseur de lecture

Lecture

B.A. BA

Il nous faut donc déjà créer un nouvel objet Sound qui va "porter" notre fichier son. C'est le rôle du script ci-dessous qui, après avoir initialisé l'instance musique de la classe Sound, va utiliser la méthode attachSound() pour "attacher" une musique de la bibliothèque à notre nouvel objet.

var musique:Sound = new Sound();
musique.attachSound("Hallelujah"); // Faites gaffe aux majuscules dans votre nom de liaison

Ensuite, il ne reste plus qu'à lancer la musique :

var musique:Sound = new Sound();
musique.attachSound("Hallelujah");
musique.start();
start() et stop() => et la pause ?

La méthode start() permet de lancer la lecture de notre son, elle possède deux arguments : le premier correspond à la position en secondes où Flash doit commencer la lecture du son, et le deuxième correspond au nombre de fois que le son doit être lu.

Nous voulons lire une musique de plusieurs minutes, nous n'utiliserons donc pas le second argument, car la lecture en boucle ne nous est pas utile.

Créez donc trois boutons sur votre scène : arret, pause et lecture (je sais que le mot pause se colore en bleu dans le panneau action, signifiant qu'il est utilisé par une autre classe, mais je vous assure qu'il n'y aura pas de conflit. :D )

On écrit le code ci-dessous, qui permet de contrôler la lecture et l'arrêt de notre musique.

var musique:Sound = new Sound();
musique.attachSound("Hallelujah");
arret.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start();
};

Maintenant, un problème se pose : quid du bouton pause ? Il n'existe pas de méthode pause() pour l'objet Sound.
Par contre, il existe une propriété position qui permet de connaître en millisecondes la position actuelle du curseur de lecture ! D'ailleurs, stop() ne remet pas la musique à zéro, il ne fait que la mettre en pause : si la musique recommence du début, c'est qu'on ne transmet pas d'argument à start(), qui va donc commencer la lecture du départ.

Maintenant, c'est à vous de bosser pour me rajouter le code qu'il faut pour faire fonctionner ce bouton pause ! Quand on clique dessus : la chanson s'arrête. Quand on clique sur lecture : la chanson reprend là où elle était. :D

Correction possible :

var musique:Sound = new Sound();
musique.attachSound("Hallelujah");
var vraie_position:Number = 0; // On crée une variable pour conserver la "vraie" position
arret.onRelease = function() {
        vraie_position = 0;     // Quand on stoppe, on la met à zéro
        musique.stop(); // Et on la stoppe tout de suite après
};
pause.onRelease = function() {
        vraie_position = musique.position; // Quand on pause, on la met à la dernière position connue.
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(vraie_position/1000);     // Il faut diviser par mille, car start() demande la position en secondes, pas en millisecondes !
};

Vous l'aurez compris, la seule difficulté était de bien penser à la conversion des millisecondes en secondes, avec une bête division par 1000. ;)


Préparation du terrain Curseur de lecture

Curseur de lecture

Lecture Chargement dynamique

Curseur de lecture

Affichage

Dessinez maintenant un rectangle gris foncé à bords noirs allongé horizontalement sur votre scène.

Image utilisateur

Transformez seulement l'intérieur du rectangle en clip que vous nommerez curseur (il s'agit du nom d'occurrence bien sûr). Surtout mettez bien le centre du clip en haut à gauche de votre rectangle !

C'est ce clip qui va afficher de façon continue la position de lecture actuelle de la musique.

Pour faire cela, je vais vous donner plusieurs indices :
- utiliser un onEnterFrame
- utiliser musique.position
- utiliser musique.duration (temps total de la musique en millisecondes)
- utiliser _xscale

Tous les indices que je vous ai donnés, prennent déjà plus de place que le script que vous allez écrire maintenant, et qui va permettre de faire fonctionner ce curseur. :D

curseur.onEnterFrame = function() {
        this._xscale =(musique.position/musique.duration)*100;
}

C'est une bête règle de trois :D (ou règle de proportionnalité si vous préférez).

Interactivité

Reste le problème de l'interactivité : on voit la position de la musique, mais on ne peut pas naviguer !

Il va donc falloir inverser le processus.

Créez déjà un nouveau clip, exacte copie de curseur : même position, même taille, même centre en haut à gauche du rectangle. Mais il faut que ce clip soit en-dessous de curseur et de couleur gris clair. Nommez-le : selecteur.

On va capter la position de la souris quand elle cliquera sur selecteur, et à partir de là, trouver la position à laquelle on doit mettre la musique. ;)

Image utilisateur

On va travailler dans ce bloc :

selecteur.onRelease = function() {
//-- Code à écrire
}

On peut déjà y mettre que la musique doit être stoppée. Car la propriété position est en lecture seule, c'est-à-dire qu'on ne peut pas la modifier. Il faut donc arrêter et relancer la chanson en indiquant la position de départ.

selecteur.onRelease = function() {
        musique.stop();
}

Maintenant, il faut faire une règle de trois dans le sens inverse.
On a la position de la souris par rapport au centre de selecteur grâce à this._xmouse.
On connaît la taille totale du clip grâce à selecteur._width.
Et on connaît même la durée totale de la musique : musique.duration.

Notre inconnue est donc la position que l'on doit donner à la musique. Une bête règle de trois nous donnera ce code (à condition de ne pas oublier la conversion des millisecondes en secondes) :

musique.start((this._xmouse*musique.duration)/(this._width*1000));

Pour l'instant, voilà notre script dans sa totalité :

var musique:Sound = new Sound();
musique.attachSound("Hallelujah");
var vraie_position:Number = 0;
arret.onRelease = function() {
        vraie_position = 0;
        musique.stop();
};
pause.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(vraie_position/1000);
};
curseur.onEnterFrame = function() {
        this._xscale = (musique.position/musique.duration)*100;
};
selecteur.onRelease = function() {
        musique.stop();
        musique.start((this._xmouse*musique.duration)/(this._width*1000));
};

Lecture Chargement dynamique

Chargement dynamique

Curseur de lecture Vidéos

Chargement dynamique

Conservez toute votre animation, mais supprimez votre musique de la bibliothèque.

Vous allez voir toute la simplicité de Flash sous vos yeux ébahis :D : nous allons modifier une seule et unique ligne de code, et le chargement va devenir dynamique.

Supprimez :

musique.attachSound("Hallelujah");

et remplacez par :

musique.loadSound("Hallelujah.mp3", true);

Et ça fonctionne déjà. :D
Le second argument de loadsound() permet de définir si la lecture peut se faire en streaming ou non. En clair, si vous mettez false, il faudra attendre que la musique soit entièrement chargée avant de pouvoir l'écouter...

Mais quand je charge une grosse musique, et que l'animation est sur internet, le curseur de lecture devient complètement fou ! Qu'est-ce qui se passe ?

Ça aurait été trop facile, aussi :D ! En fait, le problème vient de la propriété duration, qui ne correspond pas à la durée totale de la musique, mais à la durée qui a été chargée dans le lecteur Flash...

En fait, il n'y a aucun moyen de connaître avec exactitude la durée totale de votre fichier audio, tant qu'il ne sera pas chargé complètement. Si vous regardez dans l'aide, vous verrez qu'il est possible de récupérer les tags id3 des musiques que l'on charge. Ces tags incorporent ce qu'on appelle des méta-données sur la musique : son titre, le compositeur ... Il existe même un tag qui indique la durée de la musique. Mais voilà le problème : on trouvera le tag TIME, qui correspond au temps total, sur très très peu de musiques.

Il va donc falloir faire fonctionner les méninges. ;) Si on ne peut connaître exactement la durée de la musique, on peut au moins l'approximer. ^^

Barre de chargement

On va utiliser selecteur comme barre de chargement. Puisque sa taille va changer au cours du temps, nos règles de trois ne seront plus valables. Il va donc falloir enregistrer au début de l'animation la taille maximale de la barre pour l'utiliser dans nos calculs.

On va donc avoir avec cette modification :

var musique:Sound = new Sound();
musique.loadSound("Hallelujah.mp3", true);
var position_pause:Number = 0;
var largeur:Number = selecteur._width; // On stocke la largeur maximale de la barre
arret.onRelease = function() {
        musique.start(0);
        musique.stop();
};
pause.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(musique.position/1000);
};
curseur.onEnterFrame = function() {
        this._alpha = 0;
        this._xscale = (musique.position/musique.duration)*100;
};
 
selecteur.onRelease = function() {
        musique.stop();
        musique.start((this._xmouse*musique.duration)/(largeur*1000)); // Pour pouvoir l'utiliser dans les calculs
};

Vous remarquerez, que j'ai effectué une autre petite modification : j'ai enlevé la variable vraie_position. Quand on utilise attachSound(), elle est indispensable, mais quand on charge le son dynamiquement, écrire start(0) remet réellement la position à zéro, ce qui n'est pas le cas avec la méthode statique (bug ?).

Il ne reste plus qu'à modifier la largeur de selecteur selon le pourcentage correspondant au chargement de notre musique. Pour ça : pas de problème, on retrouve les mêmes méthodes que pour les images et les animations. On peut donc rajouter à la fin de notre code :

selecteur.onEnterFrame = function() {
        this._xscale = (musique.getBytesLoaded()/musique.getBytesTotal())*100;
        if (this._xscale == 100) { // Une fois la musique complètement chargée
                delete this.onEnterFrame; // On supprime le onEnterFrame
        }
};

Si vous désactivez le curseur qui vous cache la barre de chargement, vous pourrez voir selecteur qui grandit au fur et à mesure du chargement de votre musique.

Approximation de la durée totale

On connaît maintenant suffisamment de données pour pouvoir calculer une approximation de la durée totale, en considérant que le poids de la chanson est proportionnelle à sa durée.

On va donc introduire la variable tduration, qui correspondra à la durée approximative totale de la musique.
Pour trouver la valeur de cette variable, c'est toujours et encore une bête règle de trois, il faut diviser la durée chargée par le pourcentage de chargement.

tduration = (musique.getBytesTotal()*musique.duration)/musique.getBytesLoaded();

On placera ce code dans selecteur.onEnterFrame, car ce dernier se détruit de lui-même une fois que la musique est complètement chargée.

Ensuite, il ne reste plus qu'à modifier l'affichage de curseur pour qu'il se base sur tduration, et non plus sur musique.duration, qui est faussé.

Notre code complet :

var musique:Sound = new Sound();
musique.loadSound("Hallelujah.mp3", true);
var largeur:Number = selecteur._width;
arret.onRelease = function() {
        musique.start(0);
        musique.stop();
};
pause.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(musique.position/1000);
};
curseur.onEnterFrame = function() {
        this._xscale = (musique.position/tduration)*100;
};
selecteur.onRelease = function() {
        musique.stop();
        musique.start((this._xmouse*musique.duration)/(largeur*1000));
};
selecteur.onEnterFrame = function() {
        this._xscale = (musique.getBytesLoaded()/musique.getBytesTotal())*100;
        if (this._xscale == 100) {
                delete this.onEnterFrame;
        }
        tduration = (musique.getBytesTotal()*musique.duration)/musique.getBytesLoaded();
};

Vous savez tout sur les sons et le chargement dynamique de musique. :D

Vous êtes maintenant aptes à créer une "radio-blog", comme on en trouve un peu partout sur le web. Ça sera d'ailleurs le sujet de notre prochain fil rouge : la création d'une radio-blog complète. ;)


Curseur de lecture Vidéos

Vidéos

Chargement dynamique Riva FLV Encoder

Voilà la dernière partie de nos tribulations au pays des chargements dynamiques de ressources. :D
Nous apprendrons maintenant à charger des vidéos dans Flash. Attention, les seules vidéos acceptées par Flash sont au format FLV. Nous verrons donc en premier comment convertir une vidéo dans ce format. :)

Riva FLV Encoder

Vidéos Un nouvel objet

Riva FLV Encoder

Un outil est fourni avec Flash pour convertir vos vidéos au format FLV, mais il n'est pas très puissant, et plutôt lent.

Un éditeur allemand a publié un logiciel gratuit plus complet, et beaucoup plus intuitif, qui vous permettra d'encoder vos vidéos : Riva FLV Encoder (cliquez sur l'image "download now").

Une fois le logiciel lancé, vous pourrez changer la langue dans la barre de menu du haut pour le français (sprache->fransözisch ou language->french).

Ci-dessous, l'interface du logiciel avec les différentes étapes. Dans la troisième étape, en vert, je ne donne que des conseils pour pouvoir avoir une vidéo avec un minimum de poids, mais la perte de qualité sera assez conséquente ! C'est donc à vous de faire vos propres réglages, selon l'utilisation que vous ferez de votre vidéo !
Le lecteur que nous allons réaliser en Flash fera 320 * 240 pixels, mais vous pourrez changer cette taille très facilement.
La fréquence correspond au nombre d'images par seconde (15 dans notre exemple), et le bitrate au débit des données en bits par seconde (sachez que plus c'est grand, mieux la qualitée est, mais plus le fichier est lourd).

Le logiciel vous permet aussi de "couper" votre vidéo, si vous connaissez la durée en secondes à partir duquel la coupe doit s'effectuer (Start Offset), et la durée du fichier de Sortie (Duration).
Ensuite, il ne vous reste plus qu'à lancer la conversion, qui peut durer de quelques secondes à quelques minutes.

Vous devriez voir apparaître un fichier .flv, c'est celui qui sera chargé par Flash !

Image utilisateur

Au cas où vous n'auriez pas de vidéo sous la main, j'ai encodé pour vous la vidéo de présentation du SDZ qui était passée à la télévision (québécoise apparemment :D ) : télécharger Ztélé au format FLV.


Vidéos Un nouvel objet

Un nouvel objet

Riva FLV Encoder Trois classes pour le prix d'une

Un nouvel objet

L'import d'une vidéo de façon statique n'ayant aucun intérêt, nous passons directement au chargement dynamique. :D

Image utilisateur

Je vous avais présenté, il y a longtemps de ça maintenant, les différents objets de Flash. On avait vu qu'en gros, il y avait les formes et les symboles (clips, graphiques et boutons).

Mais il existe deux autres objets qu'on peut trouver dans la bibliothèque : les polices et les vidéos.

Nous nous intéresserons bien sûr à cette seconde catégorie. :D

Cliquez donc avec le bouton droit de la souris sur un espace vide de votre bibliothèque, et dans le menu contextuel, choisissez : Nouvelle Vidéo...

Donnez-lui le nom qui vous chante, ça n'a pas d'importance.
Ensuite, glissez cette vidéo sur votre scène pour en créer une occurrence.

Donnez ces différentes propriétés à votre occurrence :

Nous sommes maintenant prêts à accueillir une vidéo dans notre animation. :D


Riva FLV Encoder Trois classes pour le prix d'une

Trois classes pour le prix d'une

Un nouvel objet Contrôle du flux

Trois classes pour le prix d'une

Pour le son, c'était simple : une seule classe.
Pour la vidéo, ça se complique drôlement ! Nous avons droit à trois classes différentes, chacune remplissant son rôle (plus ou moins bien défini).

netconnection

Sûrement une des classes les plus simples de Flash : elle n'a qu'une seule méthode et pas de propriété. :p

En fait, son rôle paraît un peu obscur. En effet, une fois l'objet créé, on appelle sa méthode connect() à laquelle on est censé passer une URL. Mais dans la documentation, on précise, je cite :

Citation : Aide de Flash

targetURI:String - Pour ce paramètre, vous devez transmettre null.

Bref, on ne sait pas à quoi ça sert, mais on obéit ; on mettra donc en haut de notre code :

var connection:NetConnection = new NetConnection();
connection.connect(null);

Ce qu'il faut retenir : NetConnection permet d'ouvrir une connexion (dans le vide puisqu'on transmet null) qu'on pourra associer ensuite à la vidéo.

netstream et Video

Là, on rentre dans le vif du sujet : cette classe s'occupe du transfert et du contrôle de la vidéo. :D

Petite particularité du constructeur de cette classe (c'est-à-dire dans la façon de créer une nouvelle instance) : on doit passer en argument une instance de NetConnection (c'est la dernière fois qu'on le reverra celui-là) :

var connection:NetConnection = new NetConnection();
connection.connect(null);
var flux_video:NetStream = new NetStream(connection); // un NetConnection en argument

Pour la suite, ça fonctionne comme pour la musique. On appelle la méthode attachVideo(), qui est une méthode de la classe Video, et qui va faire le lien entre l'objet vidéo sur la scène et l'objet NetStream fraîchement créé.

var connection:NetConnection = new NetConnection();
connection.connect(null);
var flux_video:NetStream = new NetStream(connection);
video.attachVideo(flux_video);

Enfin, il ne reste plus qu'à donner l'URL de la vidéo FLV en elle-même, grâce à la méthode play() de la classe NetStream.

var connection:NetConnection = new NetConnection();
connection.connect(null);
var flux_video:NetStream = new NetStream(connection);
video.attachVideo(flux_video);
flux_video.play("ztele.flv");

Ce qu'il faut retenir, c'est que NetStream s'occupe du chargement et du contrôle de la vidéo, et que Video ne s'occupe que de l'affichage du film (et NetConnection, on s'en fiche :p ).


Un nouvel objet Contrôle du flux

Contrôle du flux

Trois classes pour le prix d'une Fil Rouge - Radio-Blog

Contrôle du flux

Lecture, pause et arrêt

Créez deux boutons sur votre scène : lecture et arret. Le bouton lecture permettra aussi de faire pause si on clique dessus, alors que la vidéo est déjà en cours de lecture.

Le code pour le bouton lecture va être très simple, car il existe une méthode pause() dans la classe NetStream.
Si on ne passe aucun argument à cette méthode, elle mettra la vidéo en pause si elle est en lecture, et en lecture si elle est en pause : exactement ce qu'on veut. :D

lecture.onRelease = function() {
        flux_video.pause();
};

Un brin plus compliqué, voyons maintenant le code pour le bouton arret. Ce bouton a pour rôle de remettre la vidéo au début. Mais la classe ne possède pas de méthode "stop()".
Il va donc falloir ruser ! ;) Il existe une méthode seek(), qui permet de se positionner à un endroit de la vidéo en transmettant l'instant en secondes comme argument, un peu l'équivalent de la méthode play() de la classe Sound.
On va donc positionner la vidéo à l'instant 0, et la mettre en pause immédiatement après. Le problème, c'est que pause() ne met en pause que si la vidéo était en lecture ; or, nous on veut que la vidéo s'arrête à tous les coups ! Heureusement, on peut passer un argument à pause() : true si on veut arrêter la vidéo et false, si on veut reprendre la lecture. Ce qui nous fait :

arret.onRelease = function() {
        flux_video.seek(0);
        flux_video.pause(true);
};
Curseur de lecture

Comme pour le son, nous allons créer un curseur de lecture tout simple. Dessinez un rectangle plein, foncé, horizontal, et convertissez seulement l'intérieur en clip qu'on nommera : curseur. Faites attention à bien placer le centre du clip en haut à gauche du rectangle !

Vous allez voir qu'on va retrouver le même problème que pour le son : on connaît la position actuelle de la tête de lecture en secondes avec la propriété time de NetStream. Par contre, on ne connaît pas la durée totale. Alors, on pourrait utiliser la même astuce avec approximation de la durée totale, mais il existe une autre technique. Si les tags ID3 sont peu répandus pour les mp3, la plupart des vidéos FLV possèdent des métadonnées plus complètes.

La classe NetStream incorpore un événement onMetaData qui va nous permettre de récupérer facilement la donnée qui nous intéresse. Cette méthode possède un argument, que nous appellerons metadata, et qui contient justement les métadonnées du clip vidéo. Il ne reste plus qu'à savoir que la métadonnée qui contient la durée s'appelle duration, et le tour est joué. On stockera la durée totale de notre vidéo dans la variable tduration :

flux_video.onMetaData = function(metadata) { // On donne un nom à la variable fournie par onMetaData 
tduration = metadata.duration; // Et on récupère la valeur de cette variable
}

Je ne vous représente pas le principe de la proportionnalité :D ; pour faire avancer notre curseur, nous rajouterons donc :

curseur.onEnterFrame = function() {
        this._xscale = (flux_video.time/tduration)*100;
}

Dupliquez maintenant le clip curseur pour faire un clip selecteur de même taille et de même position, mais plus clair de couleur, et positionné en-dessous (au niveau des calques) de curseur.

Nous allons ajouter du code pour pouvoir positionner la vidéo facilement, en cliquant sur selecteur. Encore une fois, le code est très ressemblant à celui du son, il faut juste enlever la division par mille, puisqu'ici tout est donné en secondes, et ne pas oublier que la méthode pour se placer dans une vidéo est seek(). Si on reprend tout le code depuis le début, on aura donc :

var connection:NetConnection = new NetConnection();
connection.connect(null);
var flux_video:NetStream = new NetStream(connection);
video.attachVideo(flux_video);
flux_video.play("ztele.flv");
lecture.onRelease = function() {
        flux_video.pause();
};
arret.onRelease = function() {
        flux_video.seek(0);
        flux_video.pause(true);
};
flux_video.onMetaData = function(metadata) {
        tduration = metadata.duration;
}
curseur.onEnterFrame = function() {
        this._xscale = (flux_video.time/tduration)*100;
}
selecteur.onRelease = function() {
        flux_video.seek((this._xmouse*tduration)/this._width);
}

Des fois, quand je clique pour changer la position, la vidéo se place un peu plus loin, il y a un bug ?

Non, c'est le comportement normal. En effet, seek() ne place pas la tête de lecture exactement à un instant donné en secondes, mais à l'image clé de la vidéo la plus proche. Alors, si les images-clés de votre vidéo sont très espacées, il y aura un petit décalage, imperceptible la plupart du temps.

Chargeur

Il ne nous reste plus qu'à rendre la taille de selecteur proportionnelle à l'état de chargement de la vidéo.

Bizarrement, les méthodes getBytesLoaded() et getBytesTotal() n'existent pas dans la classe NetStream... :o Les développeurs ont préféré utiliser les propriétés bytesLoaded et bytesTotal, on se demande bien pourquoi...
Le code pour la barre de chargement sera donc le suivant :

selecteur.onEnterFrame = function() {
        this._xscale = (flux_video.bytesLoaded/flux_video.bytesTotal)*100;
        if (this._xscale == 100) {
                delete this.onEnterFrame;
        }
};

Mais, comme pour le son, la taille de selecteur étant devenue variable, il va falloir la stocker dans la variable, et utiliser largeur à la place de this._width par la suite.

En bref, voici le code complet et fonctionnel :

var connection:NetConnection = new NetConnection();
connection.connect(null);
var flux_video:NetStream = new NetStream(connection);
video.attachVideo(flux_video);
flux_video.play("ztele.flv");
var largeur:Number = selecteur._width;
// On stocke la largeur maximale
lecture.onRelease = function() {
        flux_video.pause();
};
arret.onRelease = function() {
        flux_video.seek(0);
        flux_video.pause(true);
};
flux_video.onMetaData = function(metadata) {
        tduration = metadata.duration;
};
curseur.onEnterFrame = function() {
        this._xscale = (flux_video.time/tduration)*100;
};
selecteur.onRelease = function() {
        flux_video.seek((this._xmouse*tduration)/largeur);
};
selecteur.onEnterFrame = function() {
        this._xscale = (flux_video.bytesLoaded/flux_video.bytesTotal)*100;
        if (this._xscale == 100) {
                delete this.onEnterFrame;
        }
};

Vous connaissez maintenant tout ce qu'il faut savoir sur le chargement de données externes par requête HTTP : le chargement de variables, d'images, d'animations, de musiques et de vidéos n'a plus de secret pour vous !


Trois classes pour le prix d'une Fil Rouge - Radio-Blog

Fil Rouge - Radio-Blog

Contrôle du flux Du côté de PHP

Et voilà notre traditionnel petit fil rouge de fin de chapitre. On a appris pas mal de choses dans cette partie, nous utiliserons principalement vos connaissances sur le transfert de variables, et sur le chargement dynamique de musique.

Il y a déjà tous les composants, mais vous ne trouverez aucun code ActionScript. Je tiens à remercier yash pour le design. ;)

Du côté de PHP

Fil Rouge - Radio-Blog Chargement de la Playlist

Du côté de PHP

Bon. Cette partie va être facile pour moi, je vais vous donner le code minimum du côté PHP, car ce n'est pas mon boulot de vous apprendre ce langage. Cela étant dit, je vous encourage fortement à compléter ce script pour le rendre plus dynamique, et vous permettre de mettre à jour facilement votre radio-blog.

Nous allons transmettre toujours de la même façon les données à Flash, en utilisant une succession de variables. Le script PHP devra donc retourner une chaîne de caractères de ce genre :

Citation : Chaîne à transmettre

radio=Radio du SDZ&total=1&lien_0=Hallelujah.mp3&infos_0=hallelujah+-+jeff+buckley

Bon, vous avez 500 techniques différentes pour coder cette partie : moi, je ne me suis pas embêté, toute la playlist est enregistrée en "dur" dans le script PHP. Il faut donc le modifier à chaque fois qu'on change la playlist, même si c'est moyennement pratique. Le nom de mon script PHP est lecteur.php, et encodé en UTF-8, bien entendu. ;)

<?PHP

$racine = 'http://www.votresite.com/'; // Répertoire contenant les musiques
$radio = 'Radio du SDZ'; // Nom de la radio

$lien[0] = 'Hallelujah.mp3'; // Lien vers la première musique
$infos[0] = 'Hallelujah - Jeff Buckley'; // Infos de la première musique
$lien[1] = 'calypso.mp3';
$infos[1] = 'Harry Belafonte - Calypso';

$retour = 'radio='.$radio; // On crée une chaîne pour stocker les données à envoyer
$retour .= '&total='.count($lien); // On compte le nombre d'entrées pour la variable "total"

for ($i=0;$i<count($lien);$i++) {
        $retour .= '&lien_'.$i.'='.$racine.urlencode($lien[$i]).'&infos_'.$i.'='.urlencode($infos[$i]);
// On oublie surtout pas "d'urlencoder" les données pour que la transmission ne bogue pas au premier titre contenant un & ou un =
}

echo $retour; // On affiche la chaîne contenant les données

?>

Il ne vous reste plus qu'à coupler ce script à une base de données, ou à un bête fichier texte, et une interface vous permettant de gérer simplement la playlist.
Je vous conseille de compléter, pour la suite du fil-rouge, la playlist avec au moins un quinzaine de musiques pour pouvoir coder les boutons de défilement de la liste dans le lecteur.


Fil Rouge - Radio-Blog Chargement de la Playlist

Chargement de la Playlist

Du côté de PHP Gestion de la musique

Chargement de la Playlist

Allons dans l'ordre, et avant de commencer à jouer une musique, chargeons déjà les données qui leurs correspondent.
On va donc créer un nouvel objet LoadVarsload_playlist qui se chargera de cette tâche :

var load_playlist:LoadVars = new LoadVars();
load_playlist.load('lecteur.php');
load_playlist.onLoad = function(succes) {
        if (succes) {
                // A coder :D 
        } else {
                _root.infos = 'ERREUR dans le chargement'; // En cas d'erreur
        }
};

La question maintenant, c'est : comment donc récupérer les chansons et les stocker ?
Ma solution, et elle vaut ce qu'elle vaut ;) , c'est de créer une occurrence du clip ligne présent dans la bibliothèque par chanson. L'occurrence aurait donc non seulement un rôle d'interface, mais chaque clip contiendrait les informations sur sa chanson. L'avantage de cette méthode, c'est qu'elle est rapide, et très "Flash" dans l'idée. On aurait aussi très bien pu séparer l'interface des données (et ça aurait d'ailleurs été plus propre pour un programmeur venant d'un autre langage), nous aurions stocké les données dans un tableau, et associé chaque ligne de la liste avec une ligne du tableau par un numéro d'identifiant.

Pour l'instant, suivons mon idée ! Nous allons donc créer une occurrence de ligne pour chaque lien transmis par le script PHP. Nous allons donc utiliser une boucle, qui ira de zéro à...

la valeur de total transmise par le script PHP.

load_playlist.onLoad = function(succes) {
        if (succes) {
                for (var i = 0; i<this.total; i++) { // Boucle de 0 au nombre total de chansons
                        var temp = _root.attachMovie('ligne', 'ligne_'+i, i); // Création d'une occurence de ligne
                }
                radio.htmlText = this.radio; // On donne le titre à la radio
                total = this.total; // On stocke le nombre total de titres dans une variable de _root
        } else {
                _root.infos = 'ERREUR dans le chargement';
        }
};

On est dans un bloc de code de load_playlist, pour accéder à un de ses objets (c'est-à-dire à une des variables transmises), on passe par this.lavariable.

Nous devons transmettre maintenant plusieurs informations à ce clip fraîchement créé, et on a donc une référence simple donné par temp.

Vous pouvez maintenant tester votre animation :D ! Ça devrait fonctionner. :lol: (J'utilise le conditionnel, car il y a toujours des Zéros qui arrivent à se compliquer la vie ;) .) Pour ces derniers, voilà le code complet pour l'instant, j'y ai rajouté tout de même une ligne, qui transmet à notre future fonction chargeur() les données pour la première chanson de la liste, histoire de commencer la lecture aussi tôt que possible. ;)

//--
// CHARGEMENT DES DONNEES
//--
var load_playlist:LoadVars = new LoadVars();
load_playlist.load('lecteur.php');
load_playlist.onLoad = function(succes) {
        if (succes) {
                for (var i = 0; i<this.total; i++) {
                        var temp = _root.attachMovie('ligne', 'ligne_'+i, i);
                        temp._y = 95+i*20;
                        temp._x = 17;
                        temp.id = i;
                        temp.infos.text = this['infos_'+i];
                        temp.lien = this['lien_'+i];
                        temp.lecture._visible = false;
                        temp.onRelease = function() {
                                chargeur(this.id);
                        };
                        if (temp._y>271) {
                                temp._visible = false;
                                temp._alpha = 0;
                        }
                }
                radio.htmlText = this.radio;
                total = this.total;
                chargeur(0); // La ligne que j'ai rajoutée :D 
        } else {
                _root.infos = 'ERREUR dans le chargement';
        }
};

Du côté de PHP Gestion de la musique

Gestion de la musique

Chargement de la Playlist Le volume - startDrag() notre ami

Gestion de la musique

Interface de base

Nous avons déjà vu la majeure partie dans le tutoriel précédent, Musique !, auquel je vous invite à vous reporter si vous souhaitez comprendre quelque chose à la suite. :p

On va en effet passer sur les explications déjà données quant au chargement de la musique et à l'approximation effectuée sur sa durée totale.

Voilà notre code de départ, celui qu'on peut reprendre de plus haut :

var tduration:Number = 0; // Variable stockant la durée approximée totale de la musique
var largeur:Number = selecteur._width; // Largeur de la barre de navigation
var musique:Sound = new Sound(); // Notre objet son
arret.onRelease = function() {
        musique.start(0); // On remet la musique à zéro
        musique.stop(); // Pour l'arrêter tout de suite après
};
pause.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(musique.position/1000); // "position" donnée en millisecondes
};
curseur.onEnterFrame = function() {
        this._xscale = (musique.position/tduration)*100;
};
selecteur.onRelease = function() {
        musique.stop();
        musique.start((this._xmouse*musique.duration)/(largeur*1000));
};
selecteur.onEnterFrame = function() {
        this._xscale = (musique.getBytesLoaded()/musique.getBytesTotal())*100;
        tduration = (musique.getBytesTotal()*musique.duration)/musique.getBytesLoaded();
};

Comme vous le constatez, on n'a aucune ligne qui s'occupe du chargement de la chanson : c'est normal. :D On a dit en effet que nous allions construire une fonction chargeur() qui s'en occuperait. Cette fonction prend pour argument la variable id que chaque ligne lui transmet :

chargeur = function (id) {
musique.start(0); // On remet la musique à zéro
// Le code
};

On a le numéro de la ligne, et on connaît la structure du nom des clips ligne que nous avons créés : ligne_X.
On utilisera donc la même syntaxe que d'habitude pour aller chercher nos petites infos :

chargeur = function (id) {
        musique.start(0);
        musique.loadSound(this['ligne_'+id].lien, true);
        info.text = this['ligne_'+id].infos.text;
};

On pouvait aussi bien écrire _root['ligne_'+id] à chaque fois, ça n'aurait rien changé.

Maintenant, le petit fignolage de dernière minute : on va faire disparaître la petite flèche lecture de la ligne qui n'est plus lue, et la rajouter à celle qui est lue.

Comment je connais l'id de la ligne qui n'est plus lue ?

Bah, il suffit de faire intervenir une nouvelle variable : var id_encours = 0;

Ensuite, dans notre fonction, on va rendre invisible la flèche du clip correspondant à id_encours, afficher celle de id, et mettre à jour la valeur de id_encours avec la nouvelle musique. (Et bien sûr dans cet ordre-là, sinon, il y aurait un petit problème .;) )

chargeur = function (id) {
        this['ligne_'+id_encours].lecture._visible = false; // On la fait disparaître
        this['ligne_'+id].lecture._visible = true; // On la fait apparaître
        id_encours = id; // Et on met à jour l'id du nouveau titre
        musique.start(0);
        musique.loadSound(this['ligne_'+id].lien, true);
        info.text = this['ligne_'+id].infos.text;
};

Petit récapitulatif de cette première partie :

var tduration:Number = 0;
var id_encours = 0;
var largeur:Number = selecteur._width;
var musique:Sound = new Sound();
chargeur = function (id) {
        this['ligne_'+id_encours].lecture._visible = false;
        this['ligne_'+id].lecture._visible = true;
        id_encours = id;
        musique.start(0);
        musique.loadSound(this['ligne_'+id].lien, true);
        info.text = this['ligne_'+id].infos.text;
};
arret.onRelease = function() {
        musique.start(0);
        musique.stop();
};
pause.onRelease = function() {
        musique.stop();
};
lecture.onRelease = function() {
        musique.start(musique.position/1000);
};
curseur.onEnterFrame = function() {
        this._xscale = (musique.position/tduration)*100;
};
selecteur.onRelease = function() {
        musique.stop();
        musique.start((this._xmouse*musique.duration)/(largeur*1000));
};
selecteur.onEnterFrame = function() {
        this._xscale = (musique.getBytesLoaded()/musique.getBytesTotal())*100;
        tduration = (musique.getBytesTotal()*musique.duration)/musique.getBytesLoaded();
};

Vous pouvez exécuter votre animation, et miracle, la plupart des fonctions sont déjà opérationnelles :D !

Précédent, suivant et passage automatique

Il manque les nouvelles fonctions inhérentes à l'utilisation d'une playlist : les boutons "précédent", "suivant" et le passage automatique à la chanson suivante, à la fin de celle en cours.

Pour les boutons "précédent" et "suivant", ça pourrait paraître facile ; il y a cependant un petit piège : arrivé à la dernière chanson, il faut revenir au début ! De même, si on est à la première chanson, et que l'utilisateur fait "précédent", il faudra aller à la dernière !
Bon, je vous laisse créer le code (les boutons ont pour nom d'occurrence precedent et suivant).

Correction possible :

precedent.onRelease = function() {
        if (id_encours>0) {
                chargeur(id_encours-1);
        } else {
                chargeur(total-1);
        }
};
suivant.onRelease = function() {
        if (id_encours<total-1) {
                chargeur(id_encours+1);
        } else {
                chargeur(0);
        }
};

Maintenant, je vais vous présenter un événement pratique dans notre cas de la classe Sound : onSoundComplete.
Cet événement se déclenche, comme son nom l'indique, quand une musique arrive à sa fin.
On aura donc :

musique.onSoundComplete = function() {
        if (id_encours<total-1) {
                chargeur(id_encours+1);
        } else {
                chargeur(0);
        }
};

Maintenant, on peut constater que le code est le même que pour le bouton suivant, on peut donc lier les deux pour gagner un peu de place :

suivant.onRelease = musique.onSoundComplete =function() {
        if (id_encours<total-1) {
                chargeur(id_encours+1);
        } else {
                chargeur(0);
        }
};

Allez, courage, on a déjà fait plus de la moitié. :p


Chargement de la Playlist Le volume - startDrag() notre ami

Le volume - startDrag() notre ami

Gestion de la musique L'ascenceur

Le volume - startDrag() notre ami

La gestion du volume n'est en elle-même pas bien complexe. Si vous vous souvenez de la méthode setVolume(), il n'y devrait pas y avoir de problème.

Sur la scène, vous pouvez voir une petite barre de volume nommée volume (les noms simples sont toujours les meilleurs :) ). Si vous rentrez dans ce clip, vous trouverez le petit curseur qui s'appelle, allez, essayez de deviner... OUI ! curseur.

Bref, comme d'habitude, on va devoir lui appliquer une petite règle de trois qui va nous permettre de transformer sa position en volume. Tout à gauche, (_x = 0) le volume est nul, tout à droite (_x = 60), le volume est à fond.

Voyons si vous avez bien compris comment fonctionnait startDrag(), et donnez-moi le code qui ira dans volume.curseur.onPress.

Solution :

volume.curseur.onPress = function() {
        this.startDrag(false, 0, 0, 60, 0);
};

On n'a en effet pas besoin que le curseur soit verrouillé au centre du clip, le curseur ne doit ni aller vers le haut, ni vers le bas. Il est limité à 0 à gauche, et à 60 à droite !

Le problème, c'est qu'une fois la souris relâchée, le curseur continue de la suivre. Il faut donc utiliser la méthode stopDrag() qui ne demande par d'argument, et qui arrêtera la poursuite. Appelez cette fonction quand la souris est relâchée, que ce soit à l'intérieur, ou à l'extérieur du clip !

volume.curseur.onRelease = volume.curseur.onReleaseOutside=function () {
        this.stopDrag();
};

Il manque encore le plus utile, c'est-à-dire le onEnterFrame, qui va ajuster le volume en fonction de la position. Je vais supposer que vous connaissez la proportionnalité (soit par la logique, soit par l'école, soit par les exemples que j'ai donnés jusqu'à maintenant), c'est donc à vous de jouer. :)

volume.curseur.onEnterFrame = function() {
        musique.setVolume((this._x*100)/60);
};

Voilà donc le petit récapitulatif de la partie sur la gestion du volume :

//--
// GESTION DU VOLUME
//--
volume.curseur.onEnterFrame = function() {
        musique.setVolume((this._x*100)/60);
};
volume.curseur.onPress = function() {
        this.startDrag(false, 0, 0, 60, 0);
};
volume.curseur.onRelease = volume.curseur.onReleaseOutside=function () {
        this.stopDrag();
};

Encore un peu de courage, tout fonctionne maintenant, il ne reste plus que les détails. ;)


Gestion de la musique L'ascenceur

L'ascenceur

Le volume - startDrag() notre ami Gestion du XML

L'ascenceur

Certes, ce ne sont que des détails, mais il vont nous prendre pas mal de temps. ^^ !

Commençons par créer deux fonctions qui, attachées à un onEnterFrame, feraient apparaître et disparaître progressivement le clip :

apparition = function () {
        this._alpha += 5; // On le fait apparaître de 5 à chaque image
        this._visible = true; // On le rend visible au cas où il aurait été rendu invisible
        if (this._alpha>=100) { // Une fois complétment affiché
                delete this.onEnterFrame; // On supprime l'événement
        }
};
disparition = function () {
        this._alpha -= 5;
        if (this._alpha<=0) {
                this._visible = false;
                delete this.onEnterFrame;
        }
};

Le code des deux fonctions n'est pas très compliqué.
Le reste va être plus dur. Si vous ouvrez le clip ascenseur, vous trouverez en haut un clip haut et en bas un clip... bas ! On va ajouter des actions à ces deux boutons pour faire respectivement descendre et monter la liste.

Je vais vous montrer pour haut, et vous extrapolerez pour bas.

On commence par les événement "presque" vides :

ascenceur.haut.onPress = function() {
        this.onEnterFrame = function() {
                // Notre code
        };
};
ascenceur.haut.onRelease = ascenceur.haut.onReleaseOutside=function () {
        delete this.onEnterFrame;
};

On va donc créer une événement onEnterFrame quand on appuiera sur le bouton. Il faut rajouter le code qui fera monter les lignes, si la ligne numéro 0 n'est pas en dessous de 95 pixels.

ascenceur.haut.onPress = function() {
        this.onEnterFrame = function() {
                if (ligne_0._y<95) {
                        // Le code
                }
        };
};

Nous allons donc devoir créer une boucle, qui va effectuer sur chaque ligne_X, avec X variant de 0 à (total-1) une augmentation de la coordonnée _y :

ascenceur.haut.onPress = function() {
        this.onEnterFrame = function() {
                if (ligne_0._y<95) {
                        for (var i = 0; i<total; i++) {
                                _root['ligne_'+i]._y += 5;
                        }
                }
        };
};

Il ne reste plus qu'à rajouter deux conditions qui vont utiliser les deux fonctions écrites en début de partie pour faire apparaître les lignes selon qu'elle sortent ou qu'elle rentrent dans le cadre :

ascenceur.haut.onPress = function() {
        this.onEnterFrame = function() {
                if (ligne_0._y<95) {
                        for (var i = 0; i<total; i++) {
                                _root['ligne_'+i]._y += 5;
                                if (_root['ligne_'+i]._y>=95) {
                                        _root['ligne_'+i].onEnterFrame = apparition;
                                }
                                if (_root['ligne_'+i]._y>=271) {
                                        _root['ligne_'+i].onEnterFrame = disparition;
                                }
                        }
                }
        };
};

Je vous laisse donc faire la même chose pour le bouton bas : n'hésitez pas à tâtonner, à regardez à la règle les positions limites des clips...

Le code complet pour la gestion de l'ascenseur est ci-dessous :

//--
// GESTION DE L'ASCENCEUR
//--
apparition = function () {
        this._alpha += 5;
        this._visible = true;
        if (this._alpha>=100) {
                delete this.onEnterFrame;
        }
};
disparition = function () {
        this._alpha -= 5;
        if (this._alpha<=0) {
                this._visible = false;
                delete this.onEnterFrame;
        }
};
ascenceur.haut.onPress = function() {
        this.onEnterFrame = function() {
                if (ligne_0._y<95) {
                        for (var i = 0; i<total; i++) {
                                _root['ligne_'+i]._y += 5;
                                if (_root['ligne_'+i]._y>=95) {
                                        _root['ligne_'+i].onEnterFrame = apparition;
                                }
                                if (_root['ligne_'+i]._y>=271) {
                                        _root['ligne_'+i].onEnterFrame = disparition;
                                }
                        }
                }
        };
};
ascenceur.haut.onRelease = ascenceur.haut.onReleaseOutside=function () {
        delete this.onEnterFrame;
};
ascenceur.bas.onPress = function() {
        this.onEnterFrame = function() {
                if (_root['ligne_'+(total-1)]._y>271) {
                        for (var i = 0; i<total; i++) {
                                _root['ligne_'+i]._y -= 5;
                                if (_root['ligne_'+i]._y<=271) {
                                        _root['ligne_'+i].onEnterFrame = apparition;
                                }
                                if (_root['ligne_'+i]._y<=95) {
                                        _root['ligne_'+i].onEnterFrame = disparition;
                                }
                        }
                }
        };
};
ascenceur.bas.onRelease = ascenceur.bas.onReleaseOutside=function () {
        delete this.onEnterFrame;
};

Que rajouter sur ce TP ? Si ce n'est qu'il vous ouvre déjà pas mal de perspectives pour l'utilisation de Flash sur votre site-web.

Soyez donc bien sûrs que vous avez tout compris, car dans le chapitre prochain je considérerais ce que nous avons vu comme un acquis, et passerai plus rapidement sur les fonctions triviales.

Maintenant vous savez tout ! Les chapitres suivants seront plus pointus et dévoileront des fonctions propres aux dernières versions de Flash.


Le volume - startDrag() notre ami Gestion du XML

Gestion du XML

L'ascenceur Rappel sur le XML

Si vous avez un peu bourlingué sur le web, ou même juste dans l'aide de Flash, vous avez dû tomber au moins une fois sur cet étrange acronyme : XML

Que se cache-t-il dans ces trois lettres, et en quoi peuvent-elles nous aider quand on programme une application en Flash ?
Voilà la question à laquelle nous allons tenter de répondre !

Rappel sur le XML

Gestion du XML Chargement

Rappel sur le XML

XML est l'acronyme de Extensible Markup Language. En français, ça veut dire : langage de balises extensible. Vous allez me dire que ça ne nous avance pas beaucoup, et vous n'avez pas tout à fait tort ^^ !
En gros, avec le XML, on pourra enregistrer des informations qui seront rangées grâce à des balises.

Pour pouvoir nous amuser, nous allons prendre un petit exemple trivial de fichier XML :

<?xml version='1.0' encoding="UTF-8" ?>
<bibliotheque>
  <livre isbn="2-02-022212-4">
        <titre>Don Quichotte de la Manche</titre>
        <auteur>Miguel De Cervantes</auteur>
        <tome>1</tome>
  </livre>
  <livre isbn="2-02-022213-2">
        <titre>Don Quichotte de la Manche</titre>
        <auteur>Miguel De Cervantes</auteur>
        <tome>2</tome>
  </livre>
  <livre isbn="2-07-037924-8">
        <titre>Du côté de chez Swann</titre>
        <auteur>Marcel Proust</auteur>
  </livre>
  <livre isbn="2-7116-0519-1">
        <titre>De la recherche de la vérité</titre>
        <auteur>Malebranche</auteur>
        <tome>2</tome>
  </livre>
  <livre isbn="2-07-032325-0">
        <titre>La psychanalyse du feu</titre>
        <auteur>Gaston Bachelard</auteur>
  </livre>
</bibliotheque>

Pour l'instant, je vous demanderais d'enregistrer ce fichier XML dans le même dossier que votre animation, vous lui donnerez comme nom : bibliotheque.xml.


Gestion du XML Chargement

Chargement

Rappel sur le XML Une grande famille !

Chargement

On va encore utiliser une classe spéciale. :p Il s'agit, vous l'aurez deviné, de la classe XML.

Comme d'habitude, on va commencer par l'instanciation :

var bibliotheque:XML = new XML();
Ignorer les blancs

Intéressons-nous à la propriété ignoreWhite de la classe XML. Non, elle n'a rien de raciste :p , elle est au contraire très utile !
Si on la laisse à false (valeur par défaut), rien ne changera dans le fichier XML ; si on la met à true, elle supprimera tous les espaces, tabulations et autres retours à la ligne qui ne font pas partie d'un noeud texte !

En gros elle transformera :

<mon_xml>
  <noeud_texte> salut les amis ! </noeud_texte>
  <noeud_vide> </noeud_vide>
</mon_xml>

En

<mon_xml><noeud_texte> salut les amis ! </noeud_texte><noeud_vide /></mon_xml>

Elle n'a pas altéré le noeud contenant le texte, mais elle a simplifié le noeud qui ne contenait qu'un espace, supposant alors qu'il était vide.

Dans notre exemple de bibliotheque, on n'a aucun noeud contenant uniquement des espaces, on utilisera donc ignoreWhite uniquement pour que vous vous rappeliez de cette propriété. :)

var bibliotheque:XML = new XML();
bibliotheque.ignoreWhite = true;
load() et onLoad()

En fait, on retrouve les mêmes méthodes qu'on utilisait avec la classe LoadVars et XML. Donc, si vous vous souvenez bien des chapitres précédents, le code ci-dessous ne devrait pas vous poser de problème :

var bibliotheque:XML = new XML();
bibliotheque.ignoreWhite = true;
bibliotheque.onLoad = function(succes) {
        if (succes) {
                trace(this);
        } else {
                trace("Une erreur s'est produite");
        }
};
bibliotheque.load("bibliotheque.xml");

Le ignoreWhite étant sur la valeur true, la fenêtre de sortie devrait vous afficher ça :

<?xml version='1.0' encoding="UTF-8" ?><bibliotheque><livre isbn="2-02-022212-4"><titre>Don Quichotte de la Manche</titre><auteur>Miguel De Cervantes</auteur><tome>1</tome></livre><livre isbn="2-02-022213-2"><titre>Don Quichotte de la Manche</titre><auteur>Miguel De Cervantes</auteur><tome>2</tome></livre><livre isbn="2-07-037924-8"><titre>Du côté de chez Swann</titre><auteur>Marcel Proust</auteur></livre><livre isbn="2-7116-0519-1"><titre>De la recherche de la vérité</titre><auteur>Malebranche</auteur><tome>2</tome></livre><livre isbn="2-07-032325-0"><titre>La psychanalyse du feu</titre><auteur>Gaston Bachelard</auteur></livre></bibliotheque>

Le fichier XML a donc bien été chargé dans l'objet bibliotheque, et nous allons voir comment l'exploiter !


Rappel sur le XML Une grande famille !

Une grande famille !

Chargement Types et attributs

Une grande famille !

Un document XML peut se représenter sous la forme d'un arbre, c'est pour cela qu'on parle de noeuds entre les branches, il y a des noeuds enfants et noeuds parents.
A l'intérieur de notre objet XML nommé bibliotheque, on va trouver des noeuds qui sont en fait chacun une instance de la classe XMLNode, dont on va voir quelques propriétés et méthodes.

Le premier enfant

La propriété la plus basique est firstChild. Elle fait référence au premier enfant du noeud courant. Pour l'instant, dans l'objet bibliotheque, on ne s'est encore placé dans aucun noeud, même pas le noeud racine matérialisé par les balises <bibliotheque>[...]</bibliotheque>.

Pour voir ce qui se passe, changez donc le trace(this); par trace(this.firstChild);
Cela renvoie le tout premier noeud rencontré, qui se trouve être le noeud racine, c'est-à-dire tout ce qui se trouve entre <bibliotheque>[...]</bibliotheque>, les balises inclues.

Donc, en suivant cette logique, quelle serait la valeur de this.firstChild.firstChild ?

Le premier noeud de bibliotheque correspond au premier livre, cette variable vaudrait donc (en la remettant en forme pour plus de lisibilité) :

<livre isbn="2-02-022212-4">
        <titre>Don Quichotte de la Manche</titre>
        <auteur>Miguel De Cervantes</auteur>
        <tome>1</tome>
  </livre>
Les frères, les soeurs et le cadet !

Voyons rapidement les autres propriétés du même acabit.

Le cadet

lastChild renvoit, à l'inverse de firstChild, le dernier noeud de la branche courante.
Par exemple, this.firstChild.lastChild correspond au dernier livre de la liste.

Les frères et soeurs

Les anglais ont la chance d'avoir un mot qui veut dire "frères et soeurs" : il s'agit de "sibling". On trouve ainsi une propriété nextSibling, qui retourne le noeud suivant sur la même branche que le noeud courant, c'est-à-dire un noeud frère.

this.firstChild.firstChild correspondait au premier livre.
this.firstChild.firstChild.nextSibling correspond donc à son frère suivant, c'est-à-dire le second livre de la liste.

Et on peut continuer ainsi autant que vous le voulez. Par exemple, cette affreuse ligne renvoie au dernier livre de la liste :
this.firstChild.firstChild.nextSibling.nextSibling.nextSibling.nextSibling

Il existe aussi la propriété previousSibling, qui correspond au frère précédent.

Le parent

Là, je vous ai montré les propriétés qui permettent de "descendre" dans la généalogie. Sachez qu'il existe aussi la propriété parentNode, qui permet de remonter au noeud parent.

Par exemple, this.firstChild.parentNode, revient au même que this.


Chargement Types et attributs

Types et attributs

Une grande famille ! XML tabulaire

Types et attributs

Les types

Chaque noeud possède un type précis auquel on peut accéder par la propriété nodeType.

Intéressons-nous au type du noeud racine :

trace(this.firstChild.nodeType);

Cela nous renvoie 1, c'est-à-dire qu'il s'agit d'un noeud élément qui contient donc d'autres noeuds.

C'est aussi le type du premier noeud "livre", ainsi que celui de son premier noeud, "titre".

Cela peut paraître étonnant, car <titre>[...]</titre> contient du texte et aucun autre élément. En fait, ActionScript considère que ce qu'il y a àl'intérieur de balises est toujours un noeud : il faut donc aller encore au noeud enfant pour trouver vraiment le texte !

trace(this.firstChild.firstChild.firstChild); // Correspond au noeud "titre"
trace(this.firstChild.firstChild.firstChild.nodeType); // Renvoie 1
trace(this.firstChild.firstChild.firstChild.firstChild); // Correspond au texte à l'intérieur de "titre"
trace(this.firstChild.firstChild.firstChild.firstChild.nodeType); // Renvoie 3, car le noeud est textuel

Ce qui nous permet de constater qu'un noeud texte a le type 3.

Les attributs

Les attributs en XML sont les valeurs qu'on explicite à l'intérieur même d'une balise. Dans notre exemple, il s'agit du numéro ISBN, qui est présent dans chaque balise "titre".

Pour récupérer ce numéro, il faut utiliser la propriété attributes, qui ne retourne non pas un tableau des attributs du noeud, mais un objet avec les attributs comme propriété.

Pour accéder à l'ISBN du premier livre, il faudra donc taper :

trace(this.firstChild.firstChild.attributes.isbn);

Une grande famille ! XML tabulaire

XML tabulaire

Types et attributs Rotation d'un clip vers la souris

XML tabulaire

Un tableau !

Rassurez-vous, pour naviguer dans notre document XML, il existe une propriété beaucoup plus simple ! Elle renvoie un tableau de tous les noeuds composant la branche courante.

Dans notre exemple, le code ci-dessous renvoie tous les noeuds "livre", chacun dans une cellule du tableau :
this.firstChild.childNodes

On peut donc accéder au premier livre de cette façon : this.firstChild.childNodes[0].
Avouez que c'est tout de même plus simple ?

Maintenant, petit exercice tout simple, faites-moi apparaître dans la fenêtre de sortie tous les titres des livres !

var bibliotheque:XML = new XML();
bibliotheque.ignoreWhite = true;
bibliotheque.onLoad = function(succes) {
        if (succes) {
                var livres:Array = this.firstChild.childNodes;
                for (var i=0;i<livres.length;i++) {
                        trace(livres[i].firstChild.firstChild);
                }
        } else {
                trace("Une erreur s'est produite");
        }
};
bibliotheque.load("bibliotheque.xml");

Comme vous le voyez, pour simplifier la boucle, j'ai créé une référence au tableau des livres que j'ai justement appelé livres.
Vous vous demandez peut-être pourquoi j'ai écrit deux fois firstChild pour afficher le titre.
En fait, comme nous l'avons vu tout à l'heure, quand on parle de noeud, on comprend les balises qui le matérialisent avec. Or, nous, on ne veut pas les balises <titre>[...]</titre> dans notre fenêtre de sortie. On rajoute donc un firstChild qui fait référence au noeud dit "texte", c'est-à-dire au contenu du noeud.

Exerice de style

Un tuto de ce genre a toujours besoin d'un petit exercice de style pour pouvoir bien appliquer les connaissances !
On va essayer de combler un manque dans les outils que nous donne Flash pour manipuler le XML. Quand on utilise childNodes, on a un tableau des noeuds enfants. Par exemple, si je suis dans le noeud "livre" et que je veux accéder au "titre", il faudra que j'écrive childNode[0], car je sais que "titre" est le premier noeud. Le problème, c'est que "titre" ne sera peut-être pas toujours le premier noeud, d'ailleurs, dans un document XML, l'ordre est susceptible de changer...

Vous allez donc créer une méthode pour la classe XMLNode, qui va renvoyer un tableau de tous les noeuds ayant un certain nom de balise. On lui donnera le même nom que son homologue dans le langage Javascript : getElementByTagName

Deux nouvelles connaissances pour réaliser cette méthode :

La propriété nodeName

Vous aurez besoin de la propriété nodeName, qui renvoie le nom de la balise du noeud courant.
Ainsi, dans notre exemple, this.firstChild.nodeName correspond à la chaîne de caractères "bibliotheque", qui est bien le nom de notre noeud racine.

Les prototypes

J'ai bien précisé que vous alliez créer une méthode, et non pas une fonction (une méthode est une fonction qui appartient à une classe). On devra donc l'utiliser de cette façon :

trace(un_noeud.getElementByTagName('nom_balise'));

Ce qui devra renvoyer un tableau des balises s'appelant "nom_balise" dans les enfants directs de un_noeud.

Il faut donc utiliser la notion de prototype, qui permet de rajouter des méthodes à une classe.

Je vous donne donc notre méthode, vide du code, il ne vous reste plus qu'à la compléter !

XMLNode.prototype.getElementByTagName = function(Tag:String):Array  {
// Le code
}

Sachez qu'à l'intérieur de cette méthode, this correspond au noeud qui portera la méthode, et que Tag sera le nom de la balise à chercher, passée en argument.
Je rappelle que la méthode doit renvoyer un tableau (d'où le :Array à la fin de la ligne) !

Correction possible :

XMLNode.prototype.getElementByTagName = function(Tag:String):Array  {
        var bons_noeuds = new Array();
        var tous_noeuds = this.childNodes;
        for (var i:Number = 0; i<tous_noeuds.length; i++) {
                noeud_courant = tous_noeuds[i];
                if (noeud_courant.nodeName == Tag) {
                        bons_noeuds.push(noeud_courant);
                }
        }
        return (bons_noeuds.length<=0)? null : bons_noeuds;
};
//--
var bibliotheque:XML = new XML();
bibliotheque.ignoreWhite = true;
bibliotheque.onLoad = function(succes) {
        if (succes) {
                trace(this.firstChild.nodeName);
                var livres:Array = this.firstChild.childNodes;
                for (var i = 0; i<livres.length; i++) {
                        trace(livres[i].getElementByTagName('titre'));
                }
        } else {
                trace("Une erreur s'est produite");
        }
};
bibliotheque.load("bibliotheque.xml");

Avant de continuer, un bon conseil : travaillez à fond ce que vous venez de voir ! C'est très très important, y compris les explications qui n'ont pas de rapport direct avec le XML, comme les prototypes par exemple !


Types et attributs Rotation d'un clip vers la souris

Rotation d'un clip vers la souris

XML tabulaire Création du clip

La rotation d'un clip vers la position de la souris est un effet souvent utilisé. Il permet de faire bouger les yeux des personnages, ou de créer des effets de traînée derrière la souris.

Dans notre exemple, nous allons utiliser une flèche toute bête qui indique la position de la souris.

Création du clip

Rotation d'un clip vers la souris Explication géométrique

Création du clip

Il vous faut d'abord dessiner une flèche.
Dessinez-là indiquant le côté droit de votre écran, c'est important pour la suite !
Important aussi : positionnez le point d'ancrage au milieu de la flèche, pour qu'elle puisse tourner autour de cet axe.

Image utilisateur

Transformez-la en clip que vous nommerez dans l'onglet propriété : flèche (tout bêtement)

Image utilisateur

Rotation d'un clip vers la souris Explication géométrique

Explication géométrique

Création du clip Le code

Explication géométrique

Nous allons voir un peu plus en détail comment faire en sorte que la flèche se tourne vers la souris.

Pour cela, nous allons faire appel à vos connaissances en trigonométrie (sinus, cosinus, tangente...). Si vous n'en avez jamais entendu parler, patientez un peu, votre prof de maths vous montrera tout ça bien assez tôt. :D

Plantons déjà le décor avec les données qu'on a :

Image utilisateur

Maintenant, voyons si vous ne reconnaissez pas quelque chose de connu...
Vous avez trouvé ?
La solution consiste à tracer un simple triangle rectangle :

Image utilisateur

Et là, vous devez reconnaître une formule trigonométrique, en français :

tangente (angle) = (côté opposé) / (côté adjacent)

Ce qui revient à écrire la formule sur le schéma.
Avec
Dy = _ymouse - this._y
Dx = _xmouse - this._x

Une fois qu'on arrive à faire le lien avec son cours de maths, ça paraît beaucoup plus simple. ;)


Création du clip Le code

Le code

Explication géométrique

Le code

Bref : nous avons l'explication mathématique, nous avons le clip fleche, maintenant passons au code. :D

Nous connaissons déjà Dx et Dy, l'inconnue de l'équation est donc _rotation.

Le problème vient de la fonction tangente... Il faut utiliser la fonction réciproque qui correspond à Math.atan2 en Flash.

L'équation devient donc _rotation = Math.atan2(Dy/Dx);

Un dernier problème sur notre chemin, atan2 renvoie l'angle en radians et _rotation demande un angle en degrés.

On a donc enfin l'expression qu'on va écrire dans Flash (avec this correspondant au clip que l'on fait tourner):

this._rotation = Math.atan2(_ymouse-this._y, _xmouse-this._x)/(Math.PI/180);

Et il nous faut utiliser l'événement onMouseMove ou onEnterFrame :

fleche.onEnterFrame = function() {
        this._rotation = Math.atan2(_ymouse-this._y, _xmouse-this._x)/(Math.PI/180);
}

Et sous vos yeux ébahis, le résultat :


Explication géométrique