Voir le Shockwave à cette étape
Voir le Flash à cette étape
Voir le DHTML à cette étape
(cliquer)

Télécharger le .dir à cette étape
Télécharger le .fla à cette étape
Télécharger le .htm à cette étape

(bouton droit —> enregistrer la cible sous...)


Premier exercice : les balles —1ère étape :
Si la boule a déjà disparu ci-contre, cliquez avec le bouton droit (ctrl+clic sur Mac) sur l'animation pour la redémarrer (valable aussi dans les fenêtres Lingo et ActionScript), ou recharger la page (touche F5) pour redémarrer l'animation de la fenêtre Javascript (valable dans la fenêtre Javascript).

On ne s'est occupé, pour l'instant que de mettre la boule en marche, et horizontalement.

Comment l'exprimer ?
"la position horizontale de la boule devient la position horizontale de la boule auparavant + un petit chouïa (ici 1 pixel)"

ou encore :
"la position horizontale de la boule = la position horizontale de la boule + 1"

Dans un langage informatique, on écrira plus volontiers :
"boule.positionHorizontale = boule.positionHorizontale + 1"

Nous allons voir que la manière d'accéder à la propriété "positionHorizontale" de l'objet boule diffère dans les langages, mais que le principe général qui consiste à changer une propriété pour obtenir un résultat visible reste le même.

Quelques remarques dès cette première étape :

- Lorsqu'on écrit "unTruc = unTruc + unMachin", cela ne représente pas une égalité.
La signification de cette notation est la suivante. unTruc reste unTruc. Il représente une certaine valeur. A droite du signe = , on lui ajoute la valeur de unMachin, et le résultat de cette opération est ENSUITE, réaffectée à unTruc, qui à ce moment-là seulement change de valeur.
En d'autres termes, "unTruc = unTruc + unMachin" effectue en fait deux opérations distinctes : la première qui ajoute "unTruc" (qui est connu, au moins de la machine) à "unMachin" (connu lui aussi) et la seconde qui AFFECTE le résultat de l'opération à unTruc, dont la valeur a ainsi changé (attention : la valeur précédente de unTruc disparaît complètement pour être remplacée par la nouvelle valeur.
Dans cette écriture, le signe = s'appelle "opérateur d'affectation".

- Dans notre exemple, unTruc en question est la position horizontale de la boule. On ajoute 1 à cette position horizontale, et on dit que la nouvelle position horizontale est le résultat de l'addition. Si la position horizontale était de 60, elle sera, après l'instruction, de 61. On verra donc la boule se déplacer de 1 pixel vers la droite (l'axe des x est orienté positivement vers la droite. Pour l'axe des y, c'est moins une règle absolue, mais il est souvent orienté positivement vers le bas).

- Enfin, on parlera de la boule comme d'un objet (ou souvent d'un élément dans ce cours), et de sa position horizontale comme d'une de ses propriétés.
En réalité, ce n'est pas exactement la boule qui est un objet mais le conteneur qui la contient. En effet, la boule est physiquement représentée à l'écran par un petit bitmap, et cette image est contenue dans un conteneur qui lui, possède des propriétés modifiables de position — et d'autres.
Ces conteneurs sont invisibles (mais on peut les rendre visibles lorsque cela est nécessaire graphiquement — nous verrons comment), c'est donc bien le bitmap qui est contenu dans le conteneur que l'on voit bouger, alors que c'est son conteneur qui bouge réellement.
Ce conteneur peut contenir diverses choses : des images, du texte, de la vidéo, ou du vide...

Nous avons donc poussé notre conteneur de 1 pixel vers la droite, mais après ?
La seule instruction "boule.positionHorizontale = boule.positionHorizontale + 1" telle quelle n'est rien s'il n'est pas dit explicitement de l'exécuter. En d'autres termes, il nous faudra un déclencheur pour que positionHorizontale soit effectivement incrémentée.

Un tel déclencheur s'appelle un événement.
Ce qu'il faut voir c'est que nous devons explicitement associer l'action à faire ("incrémenter la positionHorizontale" — c'est une action : son expression contient un verbe en langage naturel), à un événement, ce qui se fait par l'intermédiaire d'un "gestionnaire d'événement".

Et nous allons pouvoir faire porter à notre balle le bloc cohérent suivant (exprimé dans ce qu'on appelle du pseudo-code) :

quand un certain événement survient
balle.positionHorizontale = balle.positionHorizontale + 1
fin des actions liées à un certain événement

NB : nous ferons un usage intensif du pseudo-code dans tout ce cours. Le pseudo-code est une manière de décrire un traitement (un algorithme) dans un langage proche du langage naturel bien que télégraphique, mais en respectant l'enchaînement des opérations et leur logique. Il n'y a pas de syntaxe établie pour le pseudo-code : vous êtes libres d'employer les mots que vous souhaitez employer. La seule obligation est de respecter la structure d'un code, avec ses marqueurs, ses conditions, ses boucles... Un pseudo-code bien écrit doit permettre d'implémenter la syntaxe particulière d'un langage sans peine, par simple transposition.
Nous allons voir ci-dessous une autre manière de représenter les traitements : les organigrammes.

Il s'agit bien d'un bloc cohérent : une action ne s'exécute pas seule, comme ça, au hasard. elle est déclenchée.
Si nous prenions une analogie dans la vie courante : "la porte claque : la dame sursaute...". C'est bien le bruit du claquement de la porte qui fait sursauter la dame.
Si nous regardions une dame qui sursaute comme ça de temps en temps sans raison apparente, nous penserions que cette dame a un vrai problème nerveux...
En d'autres termes, nous penserions que la dame est imprévisible.
C'est tout l'intérêt des événements en programmation : ils permettent de rendre les fonctionnements prévisibles, ou en tout cas de maîtriser le moment auquel les choses se font.
La différence sémantique est importante : les événements arrivent, ils surviennent (they happen in english). Les choses, les actions, les instructions font quelquechose, exécutent une tâche (they do something).

Ce qui conduit à s'interroger sur l'événement en question. Quand survient-il ? Combien de fois a-t-il lieu ? Quelle est sa nature ?
Quand survient-il ? quelle est sa nature ?
Ces deux questions sont liées. Si on parle d'un clic de souris par exemple, l'événement survient à n'importe quel moment lorsque l'utilisateur a effectivement cliqué sur la souris. Nous pouvons donc dire qu'il s'agit d'un événement provoqué par l'utilisateur.
Du fait qu'il puisse intervenir n'importe quand nous amènera à parler d'événement asynchrone.
En interne, du fait que l'événement asynchrone nécessite d'être traité séance tenante et toute affaire cessante, on parlera d'interruption (cette notion est importante dans la programmation des microcontroleurs par exemple).
Les langages fournissent des gestionnaires d'événements pour ce type, tels que mouseDown, mouseUp, keyDown... dont nous ferons grand usage.
Tout se passe comme si la machine était en permanence "à l'écoute" d'un objet comme la souris ou le clavier pour pouvoir s'interrompre quand celle-ci s'est manifesté. Notons au passage que la souris et le clavier sont par essence des interfaces utilisateurs, que le signal qu'il transmettent provient de l'extérieur, et qu'il peut de ce fait survenir n'importe quand.
Des événements assimilés à des interruptions sont toujours fournis par les langages (encore que Flash permette de fabriquer des "écouteurs" d'événements personnalisés).
D'autres événements, eux, ont lieu "tout seul", par le simple fait du déroulement d'une animation. Nous parlerons alors d'évenements système, par opposition aux événements provoqués par l'utilisateur évoqués plus haut. Le fait qu'ils aient lieu tout seul ne signifie pas pour autant qu'ils ont lieu n'importe quand. Il sobeissent alors à certains enchaînements.

Combien de fois a-t-il lieu ?
Toujours parlant d'un clic de souris, on voit que cet événement se produira une seule fois, quand l'utilisateur clique sur sa souris, et puis plus rien d'autre ne se passe. Il faudra attendre que l'utilisateur clique à nouveau pour obtenir un nouvel événement. On parlera alors d'événement unique et instantané.
Dans le cas de notre positionHorizontale de la balle, on voit qu'un tel événement ne convient pas, puisque nous voulons un déplacement continu (plusieurs déplacements unitaires faits à la suite les uns des autres mènent à un déplacement continu).
Il nous faudra donc utiliser un autre type d'événement qui puisse se reproduire seul dans le temps. Nous parlerons d'événement répétitif. En associant une action à un événement répétitif, on accomplira cette action de façon continue dans le temps. Ce qui nous convient bien pour notre positionHorizontale et nous allons voir de quoi nous disposons.
Une dernière remarque : la technique qui consiste en l'utilisation d'un événement répétitif dans le temps pour surveiller une grandeur dont la modification ne provoque pas, par elle-même, d'interruption au sein du système (une valeur quelconque de variable, un temps limite écoulé, un signal sur un fil électrique quelconque ou sur un port de la machine...), est appelée technique de scrutation (par opposition à la technique des interruptions). C'est à dire que l'on va explicitement évaluer la grandeur qui nous interesse pour savoir s'il y a lieu de faire quelquechose. C'est ce que nous ferons dès que nous surveillerons la position de notre balle pour la faire rebondir.

Il est très important d'assimiler parfaitement la topologie des événements pour les utiliser au service de nos réalisations, avec l'ergonomie et la compréhension intuitive des dispositifs voulues.
Le choix d'un événement est une pièce essentielle de l'analyse. Voir classification des événéments.

Pour en revenir à notre balle, nous allons donc pouvoir utiliser un événement système répétitif : système parce que notre balle doit avancer seule sans l'intervention d'un utilisateur, répétitif de manière à obtenir un mouvement continu dans le temps comme expliqué plus haut.

Dans toute la suite du cours, je ferai la confusion entre l'événement proprement dit, et son gestionnaire. Le second est simplement l'expression du premier.

  Lingo    ActionScript  

Du fait que Director et Flash sont historiquement des logiciels d'animation, ils possèdent une notion bien à eux qui est la "tête de lecture". C'est cette tête que nous voyons se déplacer dans les "scénarios" de ces deux logiciels (attention, malgré les apparences, ces deux scénarios ne sont pas du tout de même nature — nous verrons cela plus loin dans le cours).
Même si, ici, nous ne faisons pas d'animation, et que nous travaillons toujours sur une seule frame, nous disposons toutefois de l'événement système répétitif fourni par cette particularité.

Il s'agit de on exitFrame en Lingo Il s'agit de onEnterFrame en ActionScript.

Du fait que ces deux événements sont système, il n'y a pas lieu de lancer les actions une première fois comme en Javascript. Du fait que l'animation existe et fonctionne, les événements de tête de lecture ont lieu et font avancer la balle de manière répétitive de 1 pixel.
Le pseudo-code écrit plus haut se suffit à lui même :
quand un certain événement répétitif survient
balle.positionHorizontale = balle.positionHorizontale + 1
fin des actions liées à un certain événement répétitif

Néanmoins, nous allons voir que ces événements ne se situent pas "au même endroit" dans l'architecture de l'animation en Lingo et en ActionScript.

 

  Javascript  

En Javascript, il n'y a pas de notion de tête de lecture, et nous allons devoir recourir à autre chose pour obtenir la répétitivité.

Nous y disposons d'un objet de temporisation auquel on indique d'exécuter des instructions regroupées dans une fonction, au bout d'un certain laps de temps.
Ainsi, si nous plaçons cette instruction de temporisation à la fin du bloc qui fait avancer la balle de 1 pixel, chaque avancée provoquera elle-même la répétition de cette instruction au bout d'un laps de temps donné, obtenant ainsi la répétitivité.

Voici le pseudo-code Javascript :

quand on exécute une "fonction qui fait avancer la balle de 1 pixel"
balle.positionHorizontale = balle.positionHorizontale + 1
au bout d'un certain temps, répéter la "fonction qui fait avancer la balle de 1 pixel"
fin fonction

Une telle fonction qui se répète d'elle-même est dite "récurrente".

Et comme cette fonction ne se lancera pas toute seule la première fois, il nous faudra utiliser un autre événement pour la déclencher une première fois. Cet autre événement doit être système (il doit survenir seul) et il est unique et instantané (il déclenche une première fois la fonction qui ensuite s'entretient seule à l'aide de son instruction de répétition).
C'est un événement unique a lieu au début de la vie de la page(*), quand celle-ci se charge dans le navigateur. Il s'appelle onLoad et doit être associé à la balise <body> de la page, comme il semble logique (c'est bien le corps de la page qui se charge).
La fonction qui fait avancer la balle, elle, se trouve dans l'en-tête de la page (les balises <head></head>). Ainsi son code sera disponible quand elle sera appelée (la page se charge dans le navigateur de haut en bas).
Mais encore une fois, elle ne s'exécutera pas seule si elle n'est pas appelée.
Sa simple existence constitue seulement un savoir-faire potentiel ("je sais faire avancer une balle")(*), qui n'est rien s'il n'est pas mis en oeuvre.

(*) Nous reviendrons sur ce qui se passe au début de la vie des choses, et nous reviendrons aussi sur ces "savoir-faire potentiels" à propos des méthodes.

Nous pouvons également décrire le traitement que nous venons d'élaborer dans une représentation schématique qu'on appelle un organigramme.
Voici l'organigramme des traitement Lingo/ActionScript d'une part, et Javascript d'autre part (les différences tiennent aux différences d'événement exposées ci-dessus :

 Lingo  et  ActionScript 

L'action d'avancer la balle se boucle toute seule par la grâce de l'événement de tête de lecture répétitif

 Javascript 

Il faut déclencher une première fois la fonction appellée bougerBalle() par l'événement de naissance de la page onLoad. Puis l'objet de temporisation va assurer le bouclage en rappelant la fonction bougerBalle().


Il est fondamental de bien comprendre cette notion d'événement déclencheur.

Avant de passer au code proprement dit, il faut encore parler des conteneurs évoqués plus hauts, lesquels contiennent notre bitmap représentant la balle.
Là encore, nous allons voir des différences importantes, mais qui, encore une fois, ne changent pas le fond du problème.

  Lingo 

Les sources des éléments de médias sont stockées dans le fichier de l'animation (il est aussi possible de les stocker à l'extérieur : nous verrons cela dans des techniques plus avancées).
L'interface du logiciel Director est ainsi faite que ces sources sont présentées dans un "réservoir", que Director appelle une distribution.
Les éléments de médias qui s'y trouvent sont appelés, eux des acteurs.
Lorsqu'on met un acteur sur la scène, il prend place dans un sprite. C'est ce sprite qui est son conteneur.
Le sprite peut être qualifié de conteneur universel, plastique et polymorphe, en ce sens que :
- C'est lui qui possède la majeure partie des propriétés qu'il faudra modifier pour manipuler un élément de l'animation,
- Ces propriétés sont constituées d'une collection "permanente" (applicable au sprite quel que soit le type de média qu'il contient — c'est le cas par exemple de la position), et d'une collection qui va varier en fonction du type de média que le sprite contient.
Nous verrons cela en détail à mesure que nous aurons le cas à traiter dans ce cours.

Le sprite est le seul objet disponible sur la scène, il est manipulable à loisir, en position et en déformation et autres.

Le sprite contient un élément de média unitaire (un bitmap, un texte, une forme vectorielle...) mais on ne peut pas mettre un sprite dans un autre sprite.

Les sprites sont appelés, référencés, par leur numéro d'ordre (à partir de MX2004, il est possible de nommer les sprites.). Pour les manipuler, nous n'avons donc qu'à connaître les numéros des sprites que nous créons.

ATTENTION :
Les scénarios ne sont que des outils d'interface.
Dans Director, le scénario n'est qu'une représentation alternative de la scène. Les objets que sont les sprites sont identifiés par leur numéro, et chacun de ces sprites apparaît sous forme d'une piste du scénario.
Les pistes NE SONT PAS des calques.
Chacune des pistes EST un objet sprite, dont l'aspect visuel réel est représenté sur la scène. Il n'y a JAMAIS plusieurs sprites sur la même piste.
C'est n'est pas le cas dans Flash (voir ci-contre)
.


  ActionScript  

Les sources des éléments de médias sont stockées dans le fichier de l'animation (il est aussi possible de les stocker à l'extérieur : nous verrons cela dans des techniques plus avancées).
L'interface du logiciel Flash est ainsi faite que ces sources sont présentées dans un réservoir que Flash appelle une bibliothèque.
Les éléments qui s'y trouvent sont appelés, eux, des symboles, et ces symboles peuvent être de différents type. Pour l'instant, nous n'utiliserons que le type MovieClip.
Lorsqu'on met un symbole de MovieClip sur la scène, il prend place dans une occurence de clip.
Les occurences de clip peuvent également être créées par code.

Les occurences de clip sont un des objets disponibles sur la scène de Flash, manipulables en position et en déformation et d'autres choses.

Une caractéristique importante de Flash est qu'un symbole de MovieClip peut à son tour contenir d'autres occurences de clip.
Les clips sont ainsi emboitables à l'infini.
Ce qui pose le problème de les appeler, de les référencer.

Les occurences de clip sont appelées par des noms qu'on leur donne quand on les créé. Ce nom est le nom qu'ils portent à l'intérieur du clip qui les contient et lorsqu'on appelle un clip, le chemin complet de ses clips contenants à la manière des poupées russes doit être indiqué.
Dans un premier temps, nous n'imbriquerons pas les clips et nous nous contenterons de faire référence à celui qui les contient tous : la scène, c'est à dire l'animation elle-même, que Flash appelle _root.

ATTENTION :
Les scénarios ne sont que des outils d'interface.
Contrairement à Director, le scénario de Flash n'est pas une représentation de la scène et plusieurs occurences peuvent très bien coexister sur le même calque.
Le calque n'est pas un objet manipulable dans flash et ce n'est surtout pas une représentation d'occurence. Les calques permettent de séparer les éléments lors de la conception, permettent aussi à Flash de calculer ses interpolations si on utilise cette méthode.
Je ne connais pas de moyen de manipuler les calques par code, et du reste, ceux-ci n'existent plus dans le fichiers swf publié : vous pouvez faire auttant de calques que vous le souhaitez, la taille du .swf n'augmente pas.
Enfin, vous constaterez que lorsqu'on créé une occurence par code (avec attachMovie() ou createEmptyMovieClip() ) on ne fait nullement référence à un quelconque calque.

  Javascript  

Les sources des éléments de médias se trouvent sur le disque dur, dans un des répertoires qui constituent le site sur lequel on travaille.
Les sources sont intégrées aux pages HTML à l'aide de balises HTML qui indiqent au navigateur de récupérer tel élément de média à tel emplacement pour l'intéger dans la page. Une même source peut figurer en plusieurs exemplaires dans une même page.
Il existe la balise <img> pour insérer une image, les balises <object> et <embed> pour insérer des médias complexes encapsulés tels que les animation Flash ou Shockwave...
Ces balises, chacune pour ce qui la concerne, peut être affectée par certaines propriétés (applelées attributs en HTML). Ces propriétés sont propres à chaque balise.
Ici, nous souhaitons afficher une balle bleue. Nous indiquerons donc à la balise <img> que la propriété qui définit sa source est le nom du fichier balleBleue.jpg.

Mais nous désirons aussi que cette balle se déplace en lui donnant une position au pixel près.
Et là, les choses se compliquent parce que la balise <img> ne possède pas de propriété qui lui donne une position précise.
Le seul élément HTML que l'on peut positionner au pixel près est le calque, défini par une balise <div>.

Le calque html présente deux différences par rapport aux sprites et aux occurences :
- il est un conteneur universel dans lequel il faut placer explicitement ce qu'on souhaite y voir.
La balise <div> doit donc aussi contenir l'image du bouton sous la forme d'une balise <img> qu'il FAUT écrire.

- Si on peut déformer un calque en lui modifiant sa hauteur et sa largeur, cette déformation ne déforme pas automatiquement ce qu'il contient. Si l'on souhaitait déformer l'image contenue dans le calque par manipulation de sa largeur et de sa hauteur, c'est l'<img> qu'il faudrait déformer et nonp as son conteneur. Tandis que les variations de position, elles, sont appliquées au calque conteneur.
Nous devrons donc souvent agir sur DEUX ou plusieurs éléments, contre un seul dans Director et Flash.

Enfin, pour appeler, référencer, un élément html quelconque présent sur une page, il doit être nommé par un attribut "name" ou "id". Nous utilisons ici l'attribut id pour appeler les éléments avec la syntaxe document.getElementById() — il existe aussi getElementByName().

Pour finir, si Flash et Director gèrent automatiquement le plan sur lequel se trouve chaque objet sur la scène, ce n'est pas le cas dans une page html, et nous devons donc préciser un z-index pour chaque calque.

Dernière précision à propos du html et du javascript : son rendu est dépendant des navigateurs qui n'interprètent pas toujours les propriétés d'éléments de la même manière. Ici, je teste sur IE et sur Firefox (normalement, ce qui fonctionne sur Firefox fonctionne aussi sur Safari sur Mac).

ATTENTION :
Un calque html est bien un objet à part entière du document html, et n'a rien à voir avec les calques de Flash. Sans parler de ceux de Photoshop, d'Illustrator ou autre.
Il existe souvent une confusion du fait que des environnements différents utilisent le même terme pour désigner des choses fondamentalement différentes. Nous n'y pouvons rien, il faut vivre avec et s'interroger, à chaque fois qu'on rencontre un terme connu dans un terrain inconnu à quoi correspond la notion désignée par le terme pourtant connu.

Mainentant que nous avons passé en revue toutes ces différences, nous allons pouvoir écrire notre code :

  Lingo  

En lingo, une animation qui n'est pas explicitement bouclée s'arrête à la dernière image rencontrée par la tête de lecture. Comme ici, nous n'avons qu'une seule image, nous devons écrire explicitement de retourner à l'image 1 dès qu'on en sort. Accessoirement, c'est cela qui rend l'événement exitFrame répétitif.
Les trois lignes de code suivantes sont écrites dans la première image du scénario, une fois pour toutes. Nous ne reviendrons jamais dans ce script.
Nous écrirons systématiquement le même dans chaque nouvelle animation que nous ferons en Lingo. Dès qu'on ouvre une nouvelle animation, c'est la première chose à écrire.


on exitFrame me
go to the frame
end

Puis, associé au sprite (bouton droit sur le sprite —> script), nous écrivons ces trois lignes, strictement conformes au pseudo-code écrit plus haut.
on exitFrame me
sprite(1).locH = sprite(1).locH + 1
end


Quelques remarques :
- Le script que nous associons à l'image du scénario et au sprite apparaissent comme deux nouveaux acteurs dans la distribution. Ce n'est qu'une disposition de l'interface : les différents scripts sont accessibles via la distribution. Il n'en demeure pas moins que le premier est associé à l'image 1 du scénario, et que le deuxième est associé au sprite.
- La syntaxe Lingo "sprite(1).locH = sprite(1).locH + 1" n'est qu'un problème trivial de notation : les concepteurs du langage ayant choisi de nommer la position horizontale d'un sprite "locH". Mais ils auraient pu aussi bien l'appeler "mauricette".
- C'est bien le "sprite" dont nous manipulons la propriété pour obtenir l'effet désiré. L'objet n'est surtout pas l'acteur, bien que celui-ci soit aussi traité comme un objet en interne avec ses propriétés à lui.
Mais l'acteur sera TOUJOURS lui-même une propriété de sprite, et JAMAIS l'inverse.
Cette notion devrait s'éclaricir à mesure qu'on avancera dans la compréhension des animations.

- Ci-dessus, l'événement est bien un exitFrame. Il est pris en charge par on, mot-clé qui indique le début du gestionnaire prenant en charge l'événement. Remarquons donc tout de suite la structure du bloc : il y a un marqueur de début, on, et un marqueur de fin, end. Entre les deux, on trouve les instructions à exécuter. C'est une bonne habitude à prendre que d'écrire tout de suite end trois lignes plus bas dès qu'on a écrit on.
D'autres remarques importantes sur les structures dans un script sont données dans les étapes suivantes.
- Enfin, Lingo n'est pas sensible à la casse et on exitFrame est considéré comme identique à On Exitframe. Cependant ActionScript et Javascript le sont ainsi que de nombreux autres langages. C'est une bonne habitude que de respecter la manière d'écrire les choses, en utilisant toujours les mêmes règles. (voir règles pour le nommage des variables... sur ce site).


  ActionScript  

La particularité de Flash est que chaque MovieClip possède lui-même son propre scénario. Les scénarios de MovieClip bouclent automatiquement dès qu'ils ont atteint leur dernière image. L'animation principale, _root, elle, s'arrête lorsqu'elle atteint sa dernière image, mais la tête de lecture y reste alors stationnaire sans arrêter toute l'animation (au contraire de Director). On peut donc écrire un stop() dans la première image de la scène mais ce n'est pas obligatoire.
Les scripts des MovieClip, eux, n'apparaissent pas dans la bibliothèque. Ils sont écrits sur la première image (ou d'autres images si on utilise le scénario en animation, mais ici, nous serons toujours sur une seule image) du scénario DU MovieClip. On y accède en double cliquant sur l'occurence ou en double-cliquant sur le symbole dans la bibliothèque.
Voici donc ce que nous écrivons sur la première image du scénario de notre MovieClip :

this.onEnterFrame=function(){
this._x += 1;
}


Il n'y a pas grand chose à en dire sinon que :
- alors qu'en lingo, le gestionnaire d'évenement est lui-même une fonction, il faut en ActionScript définir une fonction (ce qui est fait ici par le mot-clé function() ) et dire que cette fonction est celle qui doit être exécutée chaque fois que l'événement onEnterFrame survient.
Le code ci-dessus pourrait être écrit de la façon suivante :
function avancer(){
this._x += 1;
}
Puis, en dessous :
this.onEnterFrame=avancer;

Cela reviendrait au même : on définit un objet fonction qui contient des instructions et on la nomme avancer(), puis on dit que l'événement onEnterFrame est associé à cette fonction. La première forme est simplement plus concise : on affecte la fonction à onEnterFrame au moment de sa création, cela économise une ligne de code.
- le mot-clé this indique au MovieClip qu'il est question de lui-même. Le code pourrait s'énoncer ainsi en français : quand mon événement onEnterFrame à moi survient, ma propriété _x à moi augmente de 1.
On a dit plus haut que les occurences devaient être nommées pour pouvoir être appelées. C'est vrai et on verra dans le .fla téléchargeable que je l'ai nommée "b". On pourrait donc écrire le code de la manière suivante :
_root.b.onEnterFrame=function(){
_root.b._x += 1;
}

et cela pourrait être écrit tant sur la première image de la scène que sur la première image du MovieClip (puisque le nom est un nom absolu : l'occurence "b" qui appartient à la scène _root est toujours qualifié).
Mais ce ne serait pas une bonne idée : si nous changeons l'emplacement de notre MovieClip dans la hiérarchie de manière que par exemple notre clip "b" se trouve dans le clip "ba" qui lui-même se trouverait dans le clip "bal" qui lui-même serait sur la scène, il faudrait changer le nom pour écrire "_root.bal.ba.b._x, et ceci partout ou ce chemin est employé. et si nous avons plusieurs clip, il faudra changer pour tout le monde.
En utilisant this, le MovieClip sait qu'il s'agit de lui-même, quel que soit l'emplacement de la hiérarchie de l'animation dans lequel il se trouve.
- Là où les développeurs de Lingo ont appelé la propriété de position horizontale d'un sprite locH, ceux d'ActionScript ont appelé la propriété de position horizontale d'une occurence _x (le "underscore" _ fait partie du nom de la propriété).
- l'ActionScript (comme le Javascript du reste) dispose d'un opératuer concis pour l'incrémentation d'une valeur : machin += 1 est équivalent à machin = machin + 1. C'est un raccourci précieux qui fait gagner beaucoup de temps lorsque les valeurs à incrémenter ont une expression assez longue. Lingo n'en dispose pas. Dans Director MX2004, on dispose de cet opérateur si on utilise la syntaxe dite Javascript.
- enfin, remarquer que les marqueurs de début et de fin de bloc sont également présents : ils sont notés par les accolades ouvrantes et fermantes { et }. Quant aux parenthèses à la fin du mot function(), elles sont obligatoires pour indiquer que ce qui suit est un objet fonction et pas un nom de variable.
Le Code
this.onEnterFrame=function(){
this._x += 1;
}

peut donc s'énoncer ainsi en français (c'est le MovieClip qui parle) :
"quand mon événement onEnterFrame à moi survient, il faut exécuter la fonction qui contient l'instruction suivante 'augmenter de 1 ma propriété position horizontale à moi' ".
- Pour finir, noter le point-virgule qui termine la ligne d'instruction à l'intérieur de la fonction : c'est uniquement la syntaxe pour indiquer la fin d'une ligne d'instruction. Il n'est pas obligatoire mais il est fortement recommandé de le mettre pour des questions de normalisation. Ce point-virgule existe aussi en Javascript, et dans la syntaxe Javascript de Director.

 

  Javascript  

Comme annoncé plus haut, en Javascript, la fonction s'écrit telle quelle dans la section <head> de la page HTML (il n'y a pas de de notion de tête de lecture donc pas de "enterFrame" en Javascript).
Elle se déclare avec le mot-clé function suivi d'un nom qu'on donne à la fonction (ici bougerBalle() ). Le nom est suivi de parenthèses pour indiquer qu'il s'agit d'un objet fonction.
Puis, plus bas, cette fonction est appelée (exécutée) une première fois par la survenance de l'événement onLoad de la page. ensuite la fonction se rappelle elle-même.

<head>
...

<script language="JavaScript">
function bougerBalle(){
var posH = parseInt(document.getElementById("b").style.left );
posH += 1;
document.getElementById("b").style.left = posH+"px";
setTimeout("bougerBalle()", 40);
}
</script>
</head>

<body onLoad="bougerBalle()">

Quelques remarques sur ce code, déjà plus touffu qu'en ActionScript et en Lingo :
- on ne peut pas directement écrire l'incrémentation sur la propriété de position horizontale comme on le fait en ActionScript et en Lingo. La raison est la suivante.
La position est donnée, dans le HTML, par le paramètre left de l'attribut style de la balise <div> :
<div id="b" style="position:absolute; left:147px; top:101px; width:8px; height:8px; z-index:1"> ... </div>
on récupère ce paramètre comme suit : document.getElementById("b").style.left qui peut se dire en français "le paramètre left de l'attribut style de l'élément portant l'id 'b' dans le document".
On voit que cette position est exprimée sous la forme NNNpx, où NNN est un nombre et "px" un suffixe qui indique que l'unité est le pixel (cette notation est imposée par les recommandations du W3C, qui édicte les normes en matière de HTML). Dans l'exemple left:147px.
Donc, lorsqu'on lit cette propriété à l'aide de la syntaxe document.getElementById("b").style.left, on récupère une chaîne de caractères composée d'une valeur numérique et d'un suffixe (ici "147px").
C'est une chaîne de caractère : on a donc une erreur si on essaye de faire une opération arithmétique dessus comme de lui ajouter 1.
Il faut donc d'abord extraire la valeur numérique (ici 147) à l'aide de la fonction intégrée de Javascript parseInt().
Cette valeur numérique, stockée dans une variable locale posH est ensuite incrémentée de 1, avant d'être réaffectée au paramètre left de la propriété style de la balise <div>. Le même opérateur condensé += qu'en ActionScript existe.
Comme on le voit c'est un peu lourd d'autant que, avant de réinjecter cette valeur dans le paramètre, il faut lui rajouter le suffixe "px" par concaténation(* / **).
On pourrait penser à écrire de manière plus ramassée en regroupant les instructions : document.getElementById("b").style.left = ((parseInt(document.getElementById("b").style.left ))++)+"px"; mais ceci NE FONCTIONNE PAS. Il FAUT décomposer en extrayant d'abord la valeur numérique, puis en incrémentant cette valeur, puis en la réaffectant au paramètre (l'opérateur ++ incrémente une valeur de 1 : nous verrons cela plus tard).
- A la dernière ligne de la fonction, on trouve l'objet de temporisation setTimeout("bougerBalle()", 40), qui relance bougerBalle() au bout de 40 millisecondes.

(*) concaténation : mise bout à bout de deux chaînes de caractères. L'opérateur pour cela est + comme pour l'addition de deux nombres. C'est le contexte qui indique comment se fait l'opération. Entre deux valeurs numériques, on fait une addition, entre deux chaînes, on fait une concaténation, entre une chaîne et un nombre, l'opérateur convertit d'abord le nombre en chaîne, puis fait une concaténation.

(**) Il semblerait qu'on ne soit pas toujours obligé de rajouter le suffixe "px" à la valeur avant de la réinjecter dans le paramètre. Si, sous Internet Explorer, cela marche toujours si on ne le rajoute pas (le suffixe doit etre rajouté en interne dans le navigateur), il semble que sous Firefox, il faille le mettre parfois (parfois, cela marche sans qu'on mette le préfixe, et parfois pas, sans que j'aie trouvé d'explication rationnelle à cela). Dans le doute, je préfère le mettre toujours, pour me tenir à l'abri des surprises.

 

Nous en avons fini avec la première étape de notre balle.

 

Retour au sommaire