Tuto Racing
Tuto Racing
version : as3
resume : Cr�ation d'un jeu de type COURSE
auteur : Monsieur Spi
datecreation : 01/08/2013
revisions :
lienforum :
licence : by-nc-sa
tags : jeux, tableaux, comportement
----
Bonjour,
{{.:course:course_mb.swf?800x800}}
On ne parle pas ici d'un jeu en particulier, mais d'une cat�gorie de jeux. Tout le
monde sait en quoi consiste un jeu de course, les joueurs s'affrontent sur un
circuit avec un v�hicule et le premier arriv� � gagn�.
En mati�re de jeux vid�o de course il existe diff�rents rendus : la vue top down,
c'est � dire vu du dessus tel un oiseau, la vue lat�rale, tr�s peu utilis�e, la vue
isom�trique, tr�s employ�e dans les vieux jeux vid�o, les vue � la troisi�me
personne ou subjective, utilis�e dans les jeux plus r�cents utilisant la 3D.
Si vous avez d�j� tent� de r�aliser un jeu de course vous vous �tes s�rement
confront� au probl�me de la gestion des collisions et de la reconnaissance du
terrain par les v�hicules, quelle que soit le rendu choisi. Comment obtenir une
d�tection tr�s fine de la forme de la piste, comment faire r�agir un v�hicule en
fonction du terrain sur lequel il roule, comment indiquer � l'ordinateur qu'il doit
suivre un chemin dans le cas des adversaires contr�l�s par l'ordinateur, comment
g�rer une conduite plus ou moins r�aliste, ... ?
Ce sont autant de questions que nous allons aborder avec cet exercice.
Avant de commencer nous allons devoir mettre quelques petites choses au point, si
vous avez d�j� cr�� quelques jeux (ou fait les exercices pr�c�dent de cette s�rie),
vous avez sans doute pris l'habitude de vous servir de grilles, de tuiles, de
tableaux � deux dimensions, et de formules de collisions entre une hitbox et tout
un tas de choses (point, grille, cercle, droite, segment, ...).
Si le principe g�n�ral reste le m�me, les outils dont nous allons nous servir sont
bien diff�rent de ce � quoi on est habitu�. Ici les ma�tres mots seront "Bitmap",
"BitmapData" et "Point".
CAPTURE
Comme vous pouvez le constater, le circuit (ici un circuit de Mario Kart que je
vais utiliser pour l'exercice), est plut�t grand. La premi�re option � laquelle on
pense c'est d'utiliser une grille comme pour du Tile Based, et tracer chaque tuile
une par une, sauf que pour obtenir une pr�cision suffisante il faudrait des tuiles
mesurant presque un pixel de c�t�, or pour un terrain de 800*800 pixels cela nous
fait 640 000 tuiles � se dessiner � la main puis � placer dans un tableau, �a fait
beaucoup et ce n'est pas efficace. Une autre option est de s'orienter vers la
technique du flipper, c'est � dire utiliser des formules de math pour d�terminer
chaque courbe, chaque ligne droite, chaque segment, chaque mur, etc..., c'est
compliqu� et l� encore assez peu efficace car si cela nous permet de tracer un
circuit cela ne nous permet pas de d�tecter le terrain et ses variations. Pour
afficher le terrain nous allons donc nous servir tout simplement d'un Bitmap, de
l'image du terrain elle m�me tout simplement, et nous allons g�rer les collisions
d'une autre mani�re, c'est encore la m�thode la plus simple. Notez qu'un Bitmap est
par d�finition un tableau (donc une grille) rempli de pixels de couleur, ce qui
nous ram�ne au Tile Based. En ce qui concerne la pr�paration de l'affichage du
terrain c'est donc tranquille, on se sert juste de l'image du terrain � afficher,
plut�t chouette non ?
CAPTURE
Cette image fait exactement la taille du circuit, elle reprend les zones
importantes comme le bitume, l'herbe et les murs mais cette fois avec une palette
de couleurs limit�e. Ici nous avons besoin de diff�rentier 3 choses, nous allons
donc utiliser trois couleurs et uniquement trois couleurs, m�fiez vous des formats
d'images compress�s et utilisez un PNG limit� � 3 couleurs pour �tre sur de ne pas
avoir de couleurs interm�diaires li�es � la compression d'un JPEG par exemple. Pour
savoir ce que le v�hicule rencontre sur son chemin il nous suffit de v�rifier la
couleur de la ColorMap d'un point situ� sur le v�hicule ou autour. Imaginons un
point au centre du v�hicule, si le point correspond � du noir sur la ColorMap alors
on est sur du bitume, du bleu il s'agit d'un mur, du rose c'est de l'herbe, etc...
Bien sur vous pouvez ajouter autant d'obstacles et de types de terrain que vous le
souhaitez, il suffit d'attribuer une couleur � chaque chose : t�che d'huile,
paille, eau, turbo, bonus, ...
Nous avons r�gl� pas mal de probl�mes, d'une part l'affichage du circuit, facile il
s'agit juste d'une image, d'autre part la reconnaissance des surfaces, l� aussi
tr�s simple � l'aide d'une ColorMap de la taille du circuit, reste � pr�sent �
g�rer les d�placements des v�hicules contr�l�s par l'ordinateur. Partis comme on
l'est vous devez vous douter qu'il y aura encore une astuce avec un Bitmap, mais je
ne souhaite pas vous en parler tout de suite, nous verrons cela en temps voulu,
pour le moment nous avons assez d'infos pr�paratoires pour commencer � programmer
notre jeu, limit� au seul v�hicule du joueur.
R�sumons la pr�paration :
Cr�ez ensuite un MovieClip nomm� "Joueur" dans lequel vous allez placer la voiture,
faites en sorte que le rep�re de position du clip soit au centre de la voiture, ce
sera plus pratique pour les calculs, et exportez le pour AS.
C'est tout pour la pr�paration, il y aura d'autres choses � cr�er par la suite mais
on verra �a en temps et heure. Pour le moment notre objectif va �tre d'afficher le
terrain, d'y poser la voiture, de permettre au joueur de la diriger et de g�rer les
interactions avec les diff�rentes surfaces, on s'occupera des adversaires dans un
second temps.
Notre programme va pour le moment comporter une partie principale au sein de votre
FLA, et les classes "Marqueur" pour afficher les points de rep�re, "Joueur" pour
toute la gestion du joueur et "Collisions" pour toute la gestion des collisions,
voici ce que cela donne.
<code actionscript>
var mapCollisions:BitmapData;
var terrain:Bitmap;
var joueur:Joueur;
init();
function init():void{
addChild(terrain);
addChild(joueur);
}
</code>
On cr�e tout simplement tout le mat�riel dont on a besoin, � savoir la map pour les
collisions, le terrain pour l'affichage et le joueur. Vous noterez qu'il n'y a pas
besoin d'ajouter la map des collisions � la liste d'affichage, on a juste besoin
qu'elle existe.
<code actionscript>
package {
import [Link];
import [Link];
import [Link];
import [Link];
import [Link];
x = X;
y = Y;
addChild(pt1);
addChild(pt2);
addChild(pt3);
addChild(pt4);
addChild(pt5);
addChild(pt6);
mapCollisions = mapColl;
col = new Collisions();
addEventListener(Event.ADDED_TO_STAGE, init);
}
[Link](this,mapCollisions);
if (!rebond) {
dx = droite-gauche;
dy = haut-bas;
angle = Math.atan2(dy, dx);
}
vit += acc*dy;
dir += dx*0.2;
dir *= fri;
vit *= fri;
if (0.1 > [Link](vit) > 0) vit = 0;
rotation += dir*vit;
angle = (rotation - 90) * [Link] / 180;
idealX = [Link](angle)*vit;
idealY = [Link](angle)*vit;
moveX += (idealX-moveX)*glisse;
moveY += (idealY-moveY)*glisse;
if (rebond) {
x -= moveX;
y -= moveY;
} else {
x += moveX;
y += moveY;
}
dir -= (dir * 0.1);
}
}
}
</code>
Je consid�re que vous avez lu les pr�-requis, on va donc estimer que vous savez
cr�er et utiliser une classe et avancer un peu plus vite.
On a beaucoup de variables, je ne vais pas les expliquer une par une mais on va les
passer en revue par blocs utiles.
<code actionscript>
private var W:Number;
private var H:Number;
Tout ceci nous sert pour diriger le v�hicule, angle, acc�l�ration, direction,
vitesse max, friction, etc....
<code actionscript>
public var p1:Point = new Point(W, -H);
public var p2:Point = new Point(-W, -H);
public var p3:Point = new Point(W, H);
public var p4:Point = new Point(-W, H);
public var p5:Point = new Point(0, H);
public var p6:Point = new Point(0, -H);
</code>
Ces variables publiques sont des points de contr�le que l'on va placer sur le
v�hicule, comme en formule 1, il s'agit de petits capteurs plac�s � des endroits
importants qui vont nous servir pour obtenir les informations sur le terrain. J'ai
fait le choix de cr�er 6 points de contr�le, vous pouvez en mettre plus ou moins
selon la pr�cision que vous souhaitez obtenir. J'ai choisi d'en placer un sur
chaque angle de la voiture, plus un au centre du pare choc avant et un au centre du
pare choc arri�re, ce devrait �tre suffisant pour nos besoins.
<code actionscript>
private var pt1:Marqueur = new Marqueur(p1.x, p1.y);
private var pt2:Marqueur = new Marqueur(p2.x, p2.y);
private var pt3:Marqueur = new Marqueur(p3.x, p3.y);
private var pt4:Marqueur = new Marqueur(p4.x, p4.y);
private var pt5:Marqueur = new Marqueur(p5.x, p5.y);
private var pt6:Marqueur = new Marqueur(p6.x, p6.y);
</code>
Ces marqueurs ne sont l� que pour vous indiquer visuellement les points de contr�le
qu'on � pos�, ils ne servent strictement � rien dans le jeu lui m�me et vous pouvez
vous en passer. Ils d�pendent qu'une classe "Marqueur" qu'on �tudiera plus tard
mais qui ne contient que le positionnement du marqueur et son lien avec le
MovieClip "Marqueur".
<code actionscript>
private var col:Collisions;
private var mapCollisions:BitmapData;
</code>
Ici nous avons la gestion des collisions qui correspond � l'objet priv� "col" et la
ColorMap des collisions qui correspond � l'objet "mapCollisions".
<code actionscript>
private var gauche:int;
private var droite:int;
private var haut:int;
private var bas:int;
</code>
Et on termine cette longue liste de variables avec celles qui servent au joueur �
contr�ler son v�hicule.
<code actionscript>
public function Joueur (X:int, Y:int, mapColl:BitmapData) {
x = X;
y = Y;
addChild(pt1);
addChild(pt2);
addChild(pt3);
addChild(pt4);
addChild(pt5);
addChild(pt6);
mapCollisions = mapColl;
col = new Collisions();
addEventListener(Event.ADDED_TO_STAGE, init);
}
</code>
Le constructeur du joueur, on lui passe trois param�tres qui sont sa position sur
X, sa position sur Y et la ColorMap des collisions. On place le joueur, on ajoute
les Marqueurs (inutiles sauf pour d�boguer), on initialise la map des collisions et
le calcul des collisions (que nous �tudierons un peu plus tard), et pour finir on
attend que le joueur soit ajout� � la liste d'affichage avant de faire quoi que ce
soit d'autre.
<code actionscript>
private function init(e:Event):void {
sante = 100;
glisse = .12;
moveX = 0;
moveY = 0;
angle = 0;
dir = 0;
acc = .30;
vitMax = 5;
dirMax = 1.5;
W = width/2;
H = height / 2;
dx = 0;
dy = 0;
vit = 0;
rebond = false;
fri = .95;
freine = false;
addEventListener(Event.ENTER_FRAME, update);
[Link](KeyboardEvent.KEY_DOWN, appuyer);
[Link](KeyboardEvent.KEY_UP, relacher);
removeEventListener(Event.ADDED_TO_STAGE, init);
}
</code>
<code actionscript>
// appuyer sur une touche
public function appuyer (e:KeyboardEvent):void{
if ([Link] == 37) gauche = 1;
if ([Link] == 39) droite = 1;
if ([Link] == 38) haut = 1;
if ([Link] == 40) bas = 1;
}
Bon, l� rien de bien neuf, on voit ce genre de chose depuis le d�but des exercices,
on passe donc tout de suite � ce qui nous int�resse vraiment, la gestion du joueur.
<code actionscript>
private function update(e:Event):void {
[Link](this,mapCollisions);
if (!rebond) {
dx = droite-gauche;
dy = haut-bas;
angle = Math.atan2(dy, dx);
}
vit += acc*dy;
dir += dx*0.2;
dir *= fri;
vit *= fri;
if (0.1 > [Link](vit) > 0) vit = 0;
rotation += dir*vit;
angle = (rotation - 90) * [Link] / 180;
idealX = [Link](angle)*vit;
idealY = [Link](angle)*vit;
moveX += (idealX-moveX)*glisse;
moveY += (idealY-moveY)*glisse;
if (rebond) {
x -= moveX;
y -= moveY;
} else {
x += moveX;
y += moveY;
}
<code actionscript>
[Link](this,mapCollisions);
</code>
On commence par regarder les collisions (on �tudie la classe Collisions juste apr�s
rassurez-vous).
<code actionscript>
if (!rebond) {
dx = droite-gauche;
dy = haut-bas;
angle = Math.atan2(dy, dx);
}
</code>
<code actionscript>
if (freine) vit *= 0.9;
</code>
Si le joueur freine ou est frein� par quelque chose, sa vitesse se r�duit
progressivement, �a il peut le faire m�me quand il rebondit sur un mur, c'est un
r�flexe de pilote ;-)
<code actionscript>
vit += acc*dy;
dir += dx*0.2;
dir *= fri;
</code>
<code actionscript>
if ([Link](vit) > vitMax) vit = vitMax*dy;
if ([Link](dir) > dirMax) dir = dirMax*dx;
if ([Link](dir) < 0.05) dir = 0
</code>
<code actionscript>
vit *= fri;
if (0.1 > [Link](vit) > 0) vit = 0;
</code>
<code actionscript>
rotation += dir*vit;
angle = (rotation - 90) * [Link] / 180;
idealX = [Link](angle)*vit;
idealY = [Link](angle)*vit;
moveX += (idealX-moveX)*glisse;
moveY += (idealY-moveY)*glisse;
</code>
<code actionscript>
if (rebond) {
x -= moveX;
y -= moveY;
} else {
x += moveX;
y += moveY;
}
</code>
Il ne nous reste plus qu'� d�placer la voiture, mais tout d�pend si elle rebondit
suite � une collision ou pas, si elle rebondit elle repart en sens inverse du
mouvement actuel.
<code actionscript>
dir -= (dir * 0.1);
</code>
Et enfin, dans tous les cas la direction subit un effet de friction, tant que le
joueur tourne cela n'influence que tr�s peu le comportement du v�hicule, mais d�s
qu'il arr�te de tourner la direction revient peu � peu au centre, ce qui est le
comportement normal de tout v�hicule ayant une certaine vitesse, si vous l�chez le
volant les roues reviennent dans le sens de la marche.
C'est termin� pour le joueur, rien de tr�s complexe normalement, il nous reste
quand m�me � voir comment son g�r�es les collisions.
<code actionscript>
package {
import [Link];
import [Link];
with (ob) {
[Link] = false;
if(c1==terre || c2==terre ||c3==terre || c4==terre)
[Link] = true;
if(rebond){
if ([Link](vit) > 0.1) {
vit *= fri;
} else {
rebond = false;
vit = 0;
}
} else {
if (vit>0) {
if(c6 == mur){
vit = -vit/2;
dy = 0;
rebond = true;
sante -= 25;
return;
}
if(c1 == mur) rotation -= vit*vit;
if(c2 == mur) rotation += vit*vit;
}
if (vit<0) {
if(c5 == mur){
vit = -vit/2;
dy = 0;
rebond = true;
sante -= 25;
return;
}
if(c3 == mur) rotation += vit*vit;
if(c4 == mur) rotation -= vit*vit;
}
}
}
}
}
}
</code>
Comme vous pouvez le voir dans les imports on n'utilisera dans cette classe que
deux choses essentielles, un BitmapData et des Points.
<code actionscript>
public function hitTest(ob:Object, map:BitmapData):void { ... }
</code>
Cette fonction sert pour le test de collision entre un objet et la ColorMap des
collisions, on lui passe donc ces deux param�tres.
<code actionscript>
var terre:int = 16711935;
var mur:int = 6750207;
</code>
Je d�fini deux variables, l'une repr�sente la couleur que doit avoir la terre sur
la ColorMap, l'autre la couleur que doivent avoir les murs.
<code actionscript>
// converti les coordonn�es des points
var p1:Point = [Link](ob.p1);
var p2:Point = [Link](ob.p2);
var p3:Point = [Link](ob.p3);
var p4:Point = [Link](ob.p4);
var p5:Point = [Link](ob.p5);
var p6:Point = [Link](ob.p6);
</code>
Notre voiture poss�de 6 points de contr�le, chacun plac� dans la voiture et ayant
donc des coordonn�es locales � cette voiture, j'ai besoin de r�cup�rer ces points
mais de les convertir en coordonn�es globales pour savoir o� chacun se situe sur la
ColorMap et non juste au sein de la voiture.
<code actionscript>
// trouve les couleurs sous les points
var c1:int = [Link](p1.x, p1.y);
var c2:int = [Link](p2.x, p2.y);
var c3:int = [Link](p3.x, p3.y);
var c4:int = [Link](p4.x, p4.y);
var c5:int = [Link](p5.x, p5.y);
var c6:int = [Link](p6.x, p6.y);
</code>
<code actionscript>
with (ob) { ... }
</code>
<code actionscript>
[Link] = false;
if(c1==terre || c2==terre || c3==terre || c4==terre) [Link] = true;
</code>
<code actionscript>
if(rebond){
if ([Link](vit) > 0.1) {
vit *= fri;
} else {
rebond = false;
vit = 0;
}
}
</code>
Si la voiture est en train de rebondir suite � une pr�c�dente collision (c'est
important), si sa vitesse est sup�rieur � une vitesse minimale la voiture est
ralentie, sinon on consid�re que l'action du rebond est termin�e et que la voiture
est arr�t�e.
<code actionscript>
} else {
</code>
<code actionscript>
if (vit>0) {
if(c6 == mur){
vit = -vit/2;
dy = 0;
rebond = true;
sante -= 25;
return;
}
if(c1 == mur) rotation -= vit*vit;
if(c2 == mur) rotation += vit*vit;
}
</code>
<code actionscript>
if (vit<0) {
if(c5 == mur){
vit = -vit/2;
dy = 0;
rebond = true;
sante -= 25;
return;
}
if(c3 == mur) rotation += vit*vit;
if(c4 == mur) rotation -= vit*vit;
}
</code>
Si la voiture est en train de reculer, on r�it�re la m�me op�ration mais cette fois
avec les points de contr�le situ�s � l'arri�re du v�hicule. Cette op�ration dans un
sens puis dans l'autre selon si la voiture avance ou recule va nous permettre de
mieux g�rer des collisions multiples, par exemple lorsque la voiture se trouve
coinc�e entre deux murs proches, on ne regarde la collision que dans le sens o� la
voiture se d�place et on �vite ainsi les situations o� la voiture se retrouve
bloqu�e � rebondir � l'infini entre les deux murs.
C'est termin� pour les collisions, bien sur vous pouvez affiner et ajouter des
facteurs qui influencent le comportement lors d'une collision, par exemple les
t�ches d'huiles, les turbos, les autres v�hicules, etc....
<code actionscript>
package {
import [Link];
Bon l� pas grand chose � dire, les marqueurs ne sont que des rep�res visuels aidant
au d�bogage, cette classe ne sert qu'� placer chaque marqueur au moment de sa
cr�ation, vous pouvez tr�s bien vous en passer.
Si vous avez compris tout ce que nous venons de faire dans la premi�re partie vous
devriez vous en sortir haut la main dans celle-ci. Cette fois on s'attaque aux
adversaires, la r�action des v�hicules et les collisions ne devraient pas trop
poser de probl�me car sensiblement identiques � celles du joueur � quelques d�tails
pr�s. Ce qui va nous int�resser en revanche c'est l'IA, l'intelligence de chaque
adversaire pour suivre le parcours du circuit sans avoir une trajectoire trop
parfaite, ni compl�tement al�atoire.
Avant toute chose il nous faut une nouvelle voiture � afficher pour repr�senter les
adversaires, cr�ez donc un nouveau MovieClip nomm� "Ordinateur" et exportez-le pour
AS. Dedans mettre la m�me voiture que pour le joueur (avec les m�mes contraintes et
la m�me taille) d'une couleur diff�rente.
Il nous faudra bien sur une classe "Ordinateur" pour piloter les voitures mais on
verra �a plus tard.
Si vous avez d�j� jou� � un jeu de voiture vous savez que le secret d'une course
r�ussie r�side dans la trajectoire que vous choisissez d'emprunter, un m�me virage
pouvant se passer � fond si vous l'engagez correctement, ou pas si vous y entrez
n'importe comment. Certains jeux dit "r�alistes" vous affichent sur la piste une
tra�n� lumineuse qui vous indique la meilleure trajectoire possible pour r�aliser
un record. Tous vos adversaires vont essayer de suivre au plus pr�s cette marque
afin d'optimiser leur conduite, et c'est pr�cis�ment ce dont nous allons nous
servir pour donner un chemin � suivre � l'ordinateur. Mais si l'on se contentait de
tracer un chemin et posions les voitures dessus, elle se d�placeraient comme sur un
rail et il n'y aurait plus de d�fit, on va donc n'utiliser que des points de
rep�res � atteindre en fonction de chaque virage, un point plac� � un endroit
strat�gique devient une cible � atteindre par la voiture qui va le viser. Mais cela
entra�ne un autre probl�me, comment d�terminer quel point la voiture doit viser en
fonction de sa position sur le circuit ?
La solution passe une nouvelle fois par un Bitmap qui va nous permettre de
d�terminer des zones, tant que la voiture se trouve dans une zone elle dispose d'un
point unique � atteindre pour cette zone. On va donc cr�er une nouvelle ColorMap,
mais cette fois elle ne servira que pour d�couper le circuit en zones plus petites.
Pour bien vous montrer le d�coupage voici une capture o� je superpose le terrain et
la ColorMap :
CAPTURE
CAPTURE
Chaque couleur repr�sente une zone, on d�terminera les points � atteindre plus
tard. Lorsqu'un adversaire contr�l� par l'ordinateur se d�place, il regarde sur
quelle zone il se trouve sur la ColorMap et r�agit en cons�quence, exactement de la
m�me mani�re que nous l'avons fait pour d�terminer les surfaces du terrain lors des
collisions. Attention, une fois de plus la ColorMap doit �tre un PNG avec une gamme
de couleurs limit�e pour s'assurer qu'il n'y ait pas de couleurs parasites li�es �
la compression, de plus vous ne devez laisser aucun trou entre les zones sinon les
voitures pourraient se retrouver bloqu�es sans savoir quoi faire.
Cr�ez donc cette nouvelle ColorMap, un simple Bitmap sous Photoshop par exemple,
donnez lui le nom de "ColormapTrajets" et exportez le pour AS.
<code actionscript>
var zones:Array = [14211288, 11645361, 10395294, 8750469, 7500402, 6381921,
4934475, 3552822, 2039583,12698111, 9671679, 7105791, 5197823, 2829311, 251, 223,
179, 151, 119, 91, 66, 16777215];
var i:int;
var X:int;
var Y:int;
var mapCollisions:BitmapData;
var mapTrajets:BitmapData;
var terrain:Bitmap;
var joueur:Joueur;
var ordi:Ordinateur;
var p:Point;
init();
function init():void{
addChild(terrain);
addChild(joueur);
On cr�e ensuite la map des trajets qu'on vient de dessiner, ainsi qu'une variable
"ordi" qui servira � placer les adversaires, et un point "p" qui servira uniquement
� placer des marqueurs sur chaque point r�f�renc� dans le tableau des cibles, cela
va vous permettre de voir o� se trouvent les points que vous avez pos�.
Enfin, pour chaque cible on pose un marqueur sur le circuit afin de mieux les voir
tant qu'on travaille.
import [Link];
import [Link];
import [Link];
import [Link];
// d�tecte le sol
p = [Link](this.p7);// converti les coordonn�es des
points
zone = [Link](p.x, p.y);// trouve les couleurs sous
les points
cible = cibles[[Link](zone)];// trouve le point �
cibler
// d�placements
if (!rebond) {
dx = cible.x-x;
dy = cible.y-y;
angleCible = angle360(Math.atan2(dy, dx) /
[Link]*180);
angleActuel = angle360(angle / [Link]*180);
diff = angleActuel - angleCible;
if (diff <= 0) diff += 360 else diff -= 360;
diff = angle360(diff);
if (diff < 180) dir -= 0.2;
if (diff > 180) dir += 0.2;
if (dir > 1.5) dir = 1.5;
if (dir < -1.5) dir = -1.5;
if (vit < vitMax) vit += 0.5;
if (freine) vit *= 0.9;
vit *= fri;
idealX = [Link](angle)*vit;
idealY = [Link](angle)*vit;
moveX += (idealX-moveX)*glisse;
moveY += (idealY-moveY)*glisse;
x += moveX;
y += moveY;
} else {
moveX *= 0.7;
moveY *= 0.7;
x -= moveX;
y -= moveY;
}
// tourner
angle += dir*vit*.030;
if(diff>3 && diff<357) rotation = angle * 180/[Link]+90;
dir -= (dir * 0.1);
On refait donc ce qu'on � d�j� fait avec le joueur, c'est � dire cr�er les
diff�rentes variables (friction, vitesse, etc....), et en ajouter de nouvelles que
l'on d�taillera en cours de route, puis placer non plus 6 mais 7 points de
contr�le. En effet pour les ordinateurs j'ai ajout� un point central � la voiture,
vous verrez pourquoi un peu plus tard.
<code actionscript>
public function Ordinateur (X:int, Y:int, mapTrajectoires:BitmapData, zones:Array,
cib:Array, mapColl:BitmapData) {
mapTrajets = mapTrajectoires;
mapCollisions = mapColl;
col = new Collisions();
portions = zones;
cibles = cib;
_X = X;
_Y = Y;
init(X, Y);
}
</code>
Lorsqu'un adversaire est cr��, on lui passe les diff�rents maps dont il a besoin
pour les collisions et le trajet ainsi que les points cibles, et on enregistre sa
position sur la grille de d�part. Notez ici que pour bien faire il faudrait ajouter
un �couteur pour savoir quand la voiture est ajout�e � la liste d'affichage, mais
on va s'en passer pour l'exercice.
<code actionscript>
function init(X:int, Y:int):void {
x = X;
y = Y;
dx = 0;
dy = 0;
vit = 0;
dir = 0;
fri = .95;
acc = .30;
angle = 0;
moveX = 0;
moveY = 0;
sante = 100;
vitMax = 5;
dirMax = 1.5;
glisse = .12;
rotation = 0;
rebond = false;
freine = false;
angle = -[Link] / 2;
addEventListener(Event.ENTER_FRAME, update);
}
</code>
<code actionscript>
private function update(e:Event):void { ... }
</code>
<code actionscript>
// d�tecte le sol
p = [Link](this.p7);// converti les coordonn�es des points
zone = [Link](p.x, p.y);// trouve les couleurs sous les points
cible = cibles[[Link](zone)];// trouve le point � cibler
</code>
<code actionscript>
// g�re les collisions
[Link](this, mapCollisions);
</code>
<code actionscript>
// limitation de vitesse selon les zones
if (zone == 6381921) vitMax = 3;
else if (zone == 179) vitMax = 2;
else if (zone == 151) vitMax = 3;
else vitMax = 5;
</code>
L'autre int�r�t des zones c'est de pouvoir influer sur la vitesse de la voiture,
l'ordinateur n'ayant pas appris les notions de vitesse relative, de courbe, de
forces, et globalement de physique, il ne sait pas quand il doit ralentir et fonce
tout le temps � fond. Gr�ce aux zones nous pouvons lui signifier que dans une
certaine zone sa vitesse doit �tre limit�e, ce qui lui permet de mieux aborder le
virage suivant. L� aussi ce sera � vous de t�tonner pour trouver les bonnes
vitesses pour chaque zone en fonction du comportement de la voiture. M�fiez-vous
�galement des couleurs, vous n'aurez sans doute pas le m�me nombre de couleurs pour
tous vos circuits et une m�me couleur n'aura pas forc�ment la m�me action sur le
comportement de la voiture d'un circuit � l'autre. L� j'ai cod� �a comme un sauvage
en dur directement dans la classe "Ordinateur" pour vous montrer le principe en
trois lignes, mais bien sur c'est � vous de cr�er un tableau par circuit comprenant
toutes les zones de freinage, voire de cr�er une nouvelle ColorMap par circuit pour
y coller des zones de freinages qui peuvent �tre diff�rentes des zones utilis�es
pour le trajet, les deux n'�tant pas forc�ment li�es, bref sur le m�me principe
vous pouvez faire un peu ce que vous voulez pour obtenir une plus grande pr�cision.
Revenons � nous moutons et voyons de plus pr�s comment la voiture doit se d�placer.
<code actionscript>
// d�placements
if (!rebond) {
dx = cible.x-x;
dy = cible.y-y;
angleCible = angle360(Math.atan2(dy, dx) / [Link]*180);
angleActuel = angle360(angle / [Link]*180);
diff = angleActuel - angleCible;
if (diff <= 0) diff += 360 else diff -= 360;
diff = angle360(diff);
if (diff < 180) dir -= 0.2;
if (diff > 180) dir += 0.2;
if (dir > 1.5) dir = 1.5;
if (dir < -1.5) dir = -1.5;
if (vit < vitMax) vit += 0.5;
if (freine) vit *= 0.9;
vit *= fri;
idealX = [Link](angle)*vit;
idealY = [Link](angle)*vit;
moveX += (idealX-moveX)*glisse;
moveY += (idealY-moveY)*glisse;
x += moveX;
y += moveY;
} else {
moveX *= 0.7;
moveY *= 0.7;
x -= moveX;
y -= moveY;
}
</code>
Un premier probl�me li� � l'Actionscript survient, tous les angles sont compris
entre 0 et 180 ou 0 et -180, AS ne travaillant pas avec des angles sur 360 degr�s.
Or pour savoir o� se trouve une cible par rapport � l'orientation actuelle de la
voiture il nous faut raisonner sur des angles � 360 degr�s. Pour ce faire on va
utiliser une petite fonction que je vous d�taille tout de suite et qui a pour but
de convertir un angle sur 360 degr�s.
<code actionscript>
// convertir un angle sur 360 degres
private function angle360(t:Number):Number {
t %= 360;
if(t < 0) t+= 360;
return t
}
</code>
C'est tout b�te mais �a va nous rendre un immense service, revenons aux
d�placements de notre voiture.
On va ensuite faire tourner la voiture selon l'angle qu'on � trouv�, s'il est
inf�rieur � 180 on tourne vers la gauche et s'il est sup�rieur on tourne � droite,
180 �tant donc l'angle pr�cis � atteindre sur notre cercle, si la voiture est
orient�e dessus on ne tourne pas bien sur. Plut�t que de dire "tourner" je devrait
dire "corriger la trajectoire" car c'est en fait ce qu'il se passe ici, on corrige
la trajectoire pour essayer d'atteindre l'angle optimal.
<code actionscript>
// tourner
angle += dir*vit*.030;
if(diff>3 && diff<357) rotation = angle * 180/[Link]+90;
dir -= (dir * 0.1);
</code>
Cette petite partie est importante, l'angle actuel de la voiture dont on se sert
pour d�terminer le mouvement, d�pend de la direction, de la vitesse et du temps de
r�action du pilote, plus ce temps est long et plus le pilote tournera tard, plus il
est court et plus le pilote corrigera vite sa direction. Dans les faits ce n'est
pas exactement ce que fait cette formule, mais c'est la meilleure mani�re que j'ai
trouv� de vous l'expliquer simplement. Imm�diatement apr�s on va v�rifier que la
diff�rence entre l'angle actuel de la voiture et l'angle de la cible est sup�rieure
� 3 degr�s, ceci va �viter des corrections permanentes de la trajectoire pour des
angles assez petits que la voiture n'arrivera jamais a atteindre. Et enfin comme
pour le joueur, la direction revient lentement au centre si on cesse de tourner.
<code actionscript>
// gestion des degats
if (sante <= 0) {
removeEventListener(Event.ENTER_FRAME, update);
init(_X, _Y);
}
</code>
Dernier petit artifice, les d�g�ts, ils me servent essentiellement � �viter qu'une
voiture reste bloqu�e derri�re un mur trop longtemps. En effet il se peut qu'un mur
emp�che la voiture d'atteindre sa cible, pour m'�viter de nombreuses lignes de code
pour palier � cet inconv�nient, je vais tout simplement r�duire la sant� du
v�hicule quand il tape un mur, lorsque sa sant� est � z�ro la voiture est
repositionn�e sur la grille de d�part.
Pour cet exercice j'ai utilis� une technique qui s'appuie sur des Bitmaps, mais
sachez que vous pouvez les remplacer par des tuiles ou tout autre construction de
votre cru si vous trouvez plus simple. Mon but n'�tait encore une fois de vous
montrer LA solution parfaite, mais une m�thode utilis�e dans beaucoup de jeux pour
cr�er une IA pour un jeu de course. Si vous souhaitez affiner le comportement des
voitures pilot�es par l'ordinateur vous pouvez ajouter d'autres points de contr�le,
m�me si ils se trouvent en dehors de la voiture, par exemple un point plac� � une
cinquantaine de pixels devant la voiture pourrait permettre de d�tecter des
obstacles avant d'�tre dessus et ainsi de corriger la trajectoire pour les �viter
ou au contraire aller dessus (bonus, turbos, ...). Ce m�me point pourrait servir
pour anticiper les collisions, voire d�tecter une sortie de piste si la trajectoire
n'est pas corrig�e rapidement. Bref, plus vous aurez de points de contr�les bien
plac�s et plus vous pourrez affiner les comportements de l'ordinateur et ajouter
des facteurs al�atoire pour que chaque voiture r�agisse diff�remment des autres.
====== Les sources ======
<DOWNLOAD>
{{:tutoriaux:flashplatform:jeux:course:course_mb.zip|}} version CS6
</DOWNLOAD>
<DOWNLOAD>
{{:tutoriaux:flashplatform:jeux:course:course_mb_cs5.zip|}} version CS5
</DOWNLOAD>