Bienvenue sur le site francophone des TI-83 Plus et des TI-83 Plus Silver Edition   Le matériel Câble TI-PC fait maison et bon marché Télécharger Émulation Jouer en réseau avec deux TI Écouter de la musique sur sa TI
Espace programmation Tutoriels FAQ, Questions fréquemment posées Forum Trafiquer sa TI-83 Plus Liens vers les meilleurs sites sur les TI
 

Sondage Chat
Nouveautés
Contactez-moi

 
Découvrez le jeu Web de serpent addictif
réalisé par l'auteur de ce site :


Poster carte du monde satellite et politique XL 91,5 x 121,6 cm (noms en français)
Affiche murale géante de carte du monde moderne et artistique :
visuel réaliste, issu d'images satellites de la NASA, aux couleurs vives.
Image très détaillée et informative : les noms des pays et villes sont en Français.

Accueil / Espace programmation / Dossiers de programmation / Créer un jeu de serpent en BASIC

Beacoup de programmeurs qui débutent en TI-BASIC 83+ (et en programmation en général) me demandent comment faire un jeu de serpent.
Certe ce jeu est très simple à jouer, mais en y regardant de plus près sa programmation n'est pas toujours évidente lorsque l'on débute.
Cet exemple est assez complexe pour voir pas mal d'aspects de la programmation et en est ainsi ludique.
Nous ne dévelloperont ici que l'essentiel, c'est à dire le moteur. Celui-ci sera basic : à vous de l'adapter, de créer vos propres modes et de faire une interface digne de ce nom...

1/ Initialisations :
- Començons par le commencement : réfléchissons à l'utilisation des variables.
Nous prendrons X et Y pour la position actuelle du serpent.
Nous prendrons ensuite H et V pour l'incrémentation horizontale et verticale (expliqué un peu plus tard).
Les variables I et J stoqueront les coordonnées de la pomme qui doit être mangée.
Enfin, K stoquera la touche appuyée.
- Pour plus de simplicité, le jeu se joura sur l'écran graphique (et en plus c'est plus beau pour un jeu) pour pouvoir bénéficier de pxl-Test(). En effet, sur écran texte il faudrai utiliser une matrice...
Donc, configurons l'écran graphique :
Nous prendrons 0->Xmin:94->Xmax:0->Ymin:62->Ymax.
Il s'agit d'une configuration que je prend toujours. Elle est très pratique car un point sur le graph correspond à un pixel sur l'écran.
Rapellons que l'origine (0,0) de la notation en points se situe en bas à gauche avec cette configuration graphique. La notation en pixel a toujours une origine (0,0) en haut à gauche de l'écran.
Ainsi, avec cette configuration graphique les X en points ou en pixels sont les même. Par contre, pour traduire une ordonnée Y, il suffit de faire une seule soustraction 62-Y, et ce dans les deux sens.
Line() demande une notation en points et pxl-Test() une notation en pixels : prennez toujours l'habitude d'utiliser cette configuration. Une autre configuration possible serait 0->Xmin:94->Xmax:-62->Ymin:0->Ymax. Dans ce cas la transformation en Y se fait juste par -Y. C'est plus simple mais on travaille avec des entiers négatifs pour Y : à vous de faire le choix que vous convenez le meilleur. Nous prendrons la première configuration dans ce dossier.
- L'écran sera effacé avec ClrDraw et nous dessineront le rectangle de jeu avec quatres lignes : Line(1,0,1,61):Line(1,61,94,61):Line(94,61,94,0):Line(94,0,1,0).
Au préalable, nous utiliseront AxesOff pour ne pas voir... les axes !
- Il faudra maintenant initialiser les variables.
Arbitrairement, nous feront débuter le serpent dans la position 47->X et 31->Y : le milieu de l'écran.
Il se dirigera vers le haut. Comme nous le verrons en 3 cela correspond à 0->H et -1->V.
- I et J recevront une valeur aléatoire entre 2 et 60 pour I et entre 2 et 93 pour J. Ces limites sont imposées par le rectangle du jeu dessiné ci-avant. Puis nous affichons cette pomme avec Pxl-On().
>> Voici donc se que la partie initialisation donne :
0->Xmin:94->Xmax
0->Ymin:62->Ymax
AxesOff
ClrDraw
Line(1,0,1,61
Line(1,61,94,61
Line(94,61,94,0
Line(94,0,1,0
47->X:31->Y
0->H:-1->V
randInt(2,93->I
randInt(2,60->J
Pxl-On(J,I
2/ Le squelette du moteur :
- Ce jeu ne devant pas finir (dans le meilleur des cas, celui où vous ne vous êtes pas encore planté). Comme la grande majorité des jeux cela nécessite une boucle infinie.
Vu que l'on apprend ici, autant apprendre les meilleures choses et parir sur de bonnes bases : l'une des plus grande règle de programmation est de n'utiliser de labels qu'en cas d'extrème nécéssités (sinon ils sont source de trop grandes erreurs). Ainsi, notre boucle sera faite avec une boucle Repeat qui offre aussi l'avantage d'être plus rapide que Goto (qui, rappelons-le parcours tous le programme à la recherche du label, ce qui fait perdre du temps, surtout dans ce genre de jeu qui demande le plus de rapidité possible). Repeat veut dire jusqu'à ce que la condition soit égale à 1. En faissant Repeat 0, la condition n'est jamais vraie donc la boucle infinie. Le moteur du jeu sera donc entièrement contenu dans cette boucle.
3/ Déplacer le serpent :
- C'est encore assez simple. La première chose à faire est de stoquer la touche pressée dans K avec getKey->K.
- Ensuite, voici comment utiliser les variables H et V :
If K=24:-1->H
If K=26:1->H
If K=24 Or K=26:0->V
If K=25:-1->V
If K=34:1->V
If K=25 Or K=34:0->H

Ok ! Comment cela fonctionne ?
C'est simple : si on va vers la droite, K=26, H vaudra alors 1 et V=0 :: on ce déplace horizontalement de 1 (positivement) et on ne se déplace pas en vertical. Idem pr les trois autres directions...
Avec ça le serpent ne se déplace toujours pas mais on sait dans quelle direction il irra. Note : si aucune touche n'est appuyée, H eet V garderont leur valeurs respectives et on continuera d'avancer.
Passons à l'utilisation que l'on va en faire :
X+H->X
Y+V->Y

ET C'EST TOUT !!! C la magie des optimisations :-)
Pour explication, si H vaux 1 alors X augmentera et s'il vo -1 il baissera, et le serpent se déplacera. C tout con !
- Maintenant qu'on a la nouvelle position du serpent, on l'affiche avec Pxl-On().
- Pour savoir si on se mange la queue ou si on rentre dans un mur, on faira juste un pxl-Test().
Pour optimiser le tout, on placera cette commande dans le test de Repeat. Ce qui donne Repeat pxl-Test(Y,X).
Comme cela, la boucle est exécutée, le test est fait et s'il est vrai c'est que l'on a perdu : la boucle est alors interompue et on continue le programme avec l'annonce de la terrible nouvelle au joueur. Si la condition est fausse, la boucle continue alors.
- Seulement, le Pxl-On() allumera le pixel et ensuite la boucle le testera. Dans ce cas on perdra toujours. On affichera alors le pixel AVANT de calculer la nouvelle position.
>> Récapitulons la boucle de jeu. Insérez-la dans un nouveau programme en n'oubliant pas de mettre d'abord la partie initialisations : vous pourrez alors vous déplacer !
Repeat pxl-Test(Y,X
Pxl-On(Y,X
getKet->K
If K=24:-1->H If K=26:1->H
If K=24 or K=26:0->V
If K=25:-1->V
If K=34:1->V
If K=25 or K=34:0->H
X+H->X
Y+V->Y
End
4/ Faire "avancer" le serpent :
Voilà : on peut se déplacer. Mais seulement, il va falloir effacer les pixels au fur et à mesure que l'on en affiche d'autres, pour faire croire qu'il avance vraiment.
- Pour cela, nous allons avoir besoin de stoquer les coordonnées du serpent pour pouvoir ensuite effacer les pixels au bon endrois.
Comme le serpent va grandir de plus en plus il va y avoir de plus en plus de coordonnées à stoquer. Elles seront donc stoquées dans des listes. Deux listes pour être plus précis, car il y a deux variables par coordonnées (X et Y).
Nous prendrons donc L1 et L2. La longueur de ces listes sera stoquée dans L.
- Voyons comment cela fonctionera :
Il va nous falloir une autre variable, pour savoir à quelle position de la liste stoquer les coordonnées courantes. Nous prendrons P.
On incrémentera P pour trouver les nouvelles coordonnées qui se trouveront dans L1(P) et L2(P) (ces coordonnées ont été stoquées précédemment comme décrit un peu plus bas).
On effacera ce pixel, et on remplacera les valeurs dans la liste (vu qu'on vient d'effacer le pixel ces cases sont libres) par les nouvelles coordonées (celles en cours, qui serviront plus tard à effacer ce pixel comme décrit un peu plus haut), puis on affichera ce pixel. Il faut aussi prévoir que P sorte de la liste (vu qu'on incrémente toujours). Dans ce cas, P reviendra tout simplement à 1 et ainsi de suites...
>> Nous allons donc rajouter du code dans la partie initialisations :
{X->L1:{Y->L2
1->L:1->P

- Explications : notre serpent nait avec une queue de 1 pixel. Les listes ont donc une seule cas chacune mais doivent aussi contenir d'office le pixel de départ pour qu'il puisse être effacé correctement. On y met donc X et Y, initialisées plus haut.
Ensuite, L contient 1 vu que les dimentions des listes sont de 1. La position P est bien entendu 1.
- Maintenant, voyons comment faire dans la boucle de jeu : on a dit qu'on incrémentait P : P+1->P. Ensuite, il faut gérer le cas où P sorte des listes. Ceci est fait simplement : If P>L:1->P. Et on continue de pzarcourir toutes les cases des listes... Rappelons que L contient la dimension de ces listes. Ensuite, on efface le pixel à la queue du serpent avec Pxl-Off(L2(P),L1(P)). Pour ne pas donner l'impression que l'on efface un pixel puis que l'n en affiche un autre, on va tout de suite après afficher le pixel à la tête du serpent : l'animation sera ainsi fluide et on aura vraiment l'impression que c'est le serpent qui bouge (dans le cas contraire, si on place beaucoup d'instructions entre leffacement du dernier pixel et l'allumage du premier, le joueur aurra l'impression que le serpent se rétrécit puis peu de temps après se régrandit). Ne pas oublier de stoquer les coordonnées actuelles dans les listes à la position P : X->L1(P:Y->L2(P.
>> Voici donc un résumé de ce qu'il faut introduire dans la boucle de jeu à la place de Pxl-On(Y,X :

P+1->P
If P>L:1->P
Pxl-Off(L2(P),L1(P
Pxl-On(Y,X
X->L1(P:Y->L2(P
5/ Gestion des pommes et faire grandir le serpent :
Maintenant il faut gréer le cas où le serpent mange une pomme. Cela se traduit par le fait que X=I et Y=J.
Comme il faudra exécuter plusieurs instructions, nous engloberont la condition par un If:Then:End.
Que faut-il faire lorsque l'on mange une pomme ?
- D'abord le serpent va grandir (de 1 pixel dans notre jeu pour ne pas compliquer les choses), donc les listes devront être plus grandes de une case. L augmentera de 1, nous stoqueront se résultat dans la dimention de L1 et de L2.
- Ensuite il faudra aficher une nouvelle pomme : ce sera fait de la même manière que lors des initialisations puis on l'affichera également.
Et c'est tout !
- Mais vous vous appercevez que lorsque l'on essaye de jouer, le programme s'arrête quand vous touchez une pomme.
Pourquoi ? Cela vient de la condition d'arrêt de la boucle Repeat : la pomme étant un pixel allumé (au même titre que le queue ou les murs), le jeu croit que vous vous plantez. Nous allons la modifier pour qu'elle ne s'arrête plus dans ce cas. C'est à dore dans le cas où X=I et Y=J. La nouvelle condition sera :
Repeat pxl-Test(Y,X) and not(X=I and Y=J

- Ainsi not(X=I and Y=J) renverra toujours 1 (à cause du not()) dans le cas où on ne mange pas la pomme. Ainsi, tout dépendra du Pxl-Test(). S'il renvoi 1 (donc on touche un pixel, qui n'est pas la pomme dans ce cas) alors 1 and 1 donnera 1 : la boucle sera arrêtée. Si le Pxl-Test() renvoi 0, 0 and 1 donnera toujours 0 : la boucle se poursuivra. Au cas où not(X=I and Y=J) renverrai 0, cela voudrais dire que l'on est sur la pomme. qqc and 0 vaut toujours 0 et même si Pxl-Test() renvoi 1 (ce qui sera toujours vrai dans ce cas), la boucle n'en tiendra pas compte et continuera.
>> Résumons donc ce qu'il faut rajouter juste après le code qui fait avancer le serpent :

If X=I and Y=J
Then
L-1->L
Ans->dim(L1
Ans->dim(L2
randInt(2,93->I
randInt(2,60->J
Pxl-On(J,I
End
6/ Conclusion :
- Vous remarquerez quece jeu est vraiment basic et que personne n'aurait envi d'y jouer.
Je vous ai juste donné l'essentiel pour faire un jeu de serpent : le moteur le plus basic possible, le plus petit et très rapide (pas le plus rapide car les optimisations nécessaires auraient beaucoup compliqué les choses pour un gain mineur de vitesse et que ce n'est pas le sujet de ce dossier).
>> Récapitulons une dernière fois le résultat que cela doit donner :
0->Xmin:94->Xmax
0->Ymin:62->Ymax
AxesOff
ClrDraw
Line(1,0,1,61
Line(1,61,94,61
Line(94,61,94,0
Line(94,0,1,0
47->X:31->Y
0->H:-1->V
randInt(2,93->I
randInt(2,60->J
Pxl-On(J,I
{X->L1:{Y->L2
1->L:1->P
Repeat pxl-Test(Y,X) and not(X=I and Y=J
P+1->P
If P>L:1->P
Pxl-Off(L2(P),L1(P
Pxl-On(Y,X
X->L1(P:Y->L2(P
If X=I and Y=J
Then
L-1->L
Ans->dim(L1
Ans->dim(L2
randInt(2,93->I
randInt(2,60->J
Pxl-On(J,I
End
getKet->K
If K=24:-1->H If K=26:1->H
If K=24 or K=26:0->V
If K=25:-1->V
If K=34:1->V
If K=25 or K=34:0->H
X+H->X
Y+V->Y
End
Télécharger des extensions pour ce programme (cartes sous windows)Télécharger le programme SERPENT au complet