On va commencer par s'atteler à la partie la plus fun : le déplacement des voitures.
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.
Code : Actionscript | 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 :
Code : Actionscript | 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 !
Code : Actionscript | 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
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 :
Code : Actionscript | 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 :
Code : Actionscript | 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 :
Code : Actionscript | 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

).
Code : Actionscript | 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.
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.
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 :
Code : Actionscript 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | 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.
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 :
Code : Actionscript 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | 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 :