|
Voir
le Shockwave à cette étape Télécharger
le .dir à cette étape |
On ne s'est occupé, pour l'instant que de mettre la boule en marche, et horizontalement. Comment l'exprimer ? ou encore : Dans un langage informatique, on écrira plus
volontiers : 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). |
|
| 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. 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. Voici le pseudo-code Javascript : quand on exécute une "fonction
qui fait avancer la balle de 1 pixel" 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). |
(*) 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). 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 :
|
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). 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 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é. ATTENTION : |
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. Mais nous désirons aussi que cette balle se
déplace en lui donnant une position au pixel près. Le calque html présente
deux différences par rapport aux sprites et aux occurences : 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(). 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 : |
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.
|
| 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. 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.
|
| 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). Quelques remarques sur ce code, déjà plus
touffu qu'en ActionScript et en Lingo : (*) 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 |