Cahier des charges ISN





Nom du projet : Snake

Problématique : Comment créé un jeu Snake ?

Introduction : Tout au long de la création du projet nous allons essayer d’écrire un algorithme pour faire un jeu Snake. L’algorithme sera écrit en python mais nous en écrirons un autre en parallèle afin d’expliquer le langage python de l’algorithme.

Etape de la création de l’algorithme :

*Pour nous guider nous allons lire des cours sur le python

*Ensuite nous regarderons des modèles d’algorithme sur internet

*Ensuite nous écrirons notre algorithme

*Puis nous le ferons marcher







































1/ Initialisations :

Nous prendrons X et Y pour la position actuelle du serpent.

Nous prendrons ensuite H et V pour l'incrémentation horizontale et verticale

Les variables I et J stockeront les coordonnées de la pomme qui doit être mangée.

Enfin, K stockera la touche appuyée.

- Pour plus de simplicité, le jeu se jouera sur l'écran graphique pour pouvoir bénéficier de pxl-Test().

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 graphe correspond à un pixel sur l'écran.

Rappelons 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 : prenez 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 quatre lignes : Line(1,0,1,61):Line(1,61,94,61):Line(94,61,94,0):Line(94,0,1,0).

- 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 :

Vu que l'on apprend ici, autant apprendre les meilleures choses et partir 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écessités .Ainsi, notre boucle sera faite avec une boucle Repeat

qui offre aussi l'avantage d'être plus rapide que Goto . Repeat veut dire jusqu'à ce que la condition soit égale à 1. En faisant 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 :

La première chose à faire est de stocker 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

si on va vers la droite, K=26, H vaudra alors 1 et V=0 :: on ce déplace horizontalement de 1 et on ne se déplace pas en vertical.

Avec ça le serpent ne se déplace toujours pas mais on sait dans quelle direction il ira. Note : si aucune touche n'est appuyée, H et 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

Pour explication, si H vaux 1 alors X augmentera et si vo -1 il baissera, et le serpent se déplacera. - 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 fera 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 interrompue 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

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 :

- Pour cela, nous allons avoir besoin de stocker les coordonnées du serpent pour pouvoir ensuite effacer les pixels au bon endroit.

Comme le serpent va grandir de plus en plus il va y avoir de plus en plus de coordonnées à stocker. Elles seront donc stocké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 stockée dans L.

Il va nous falloir une autre variable, pour savoir à quelle position de la liste stocker les coordonnées courantes. Nous prendrons P.

On mettra P pour trouver les nouvelles coordonnées qui se trouveront dans L1(P) et L2(P) (ces coordonnées ont été stocké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 coordonnées , puis on affichera ce pixel. Il faut aussi prévoir que P sorte de la liste .

>> Nous allons donc rajouter du code dans la partie initialisations :

{X->L1:{Y->L2

1->L:1->P

- Explications : notre serpent née 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 dimensions 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 parcourir 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'On 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 l'effacement du dernier pixel et l'allumage du premier, le joueur aura l'impression que le serpent se rétrécit puis peu de temps après se ragrandit). Ne pas oublier de stocker 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 stockeront se résultat dans la dimension de L1 et de L2.

- Ensuite il faudra afficher une nouvelle pomme : ce sera fait de la même manière que lors des initialisations puis on l'affichera également.

- Mais vous vous apercevez 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.

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 :

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