1)Introduction

1.1)Contexte

Les jeux vidéo prennent maintenant une grande place dans la société. Il existe des jeux en tout genre : combat, tir, aventure, etc… .Nous avons déjà tous joué à un jeu que ce soit sur console, sur ordinateur ou une application sur un Smartphone. Étant moi-même assez mordu de jeux vidéo, je me suis dit qu’il serait intéressant d’essayer d’en coder un. J’ai donc cherché un jeu qui ne serait pas trop dur à effectuer. L’idée de créer un snake m’a beaucoup plu car c’est un jeu que nous avons tous eu un jour ou l’autre sur nos téléphones portables et qu’il ne prend pas en compte beaucoup de paramètres. Après m’être renseigné sur divers forums, j’ai donc décidé de coder un snake en C# console, cela me paraissait être le meilleur moyen. Le contenu final devrait comprendre un jeu snake opérationnel ainsi que le menu du jeu et une fonction permettant d’intégrer une gestion des scores

1.2)Problème

Il y a plusieurs problèmes qui interviennent. Tout d’abord le langage à utiliser ne m’est pas du tout familier. Une fois un peu familiarisé avec le langage, j’aurais plusieurs étapes sur les quelles travailler. Premièrement il me faudra créer le tableau sur lequel le serpent va évoluer. Suite à quoi je devrais définir le serpent en lui-même. Une fois le tableau et le serpent créés, la base sera faite. Suite à quoi, il faudra programmer les boutons pour que le serpent réponde aux directions. Il faudra ensuite réfléchir à un moyen de faire apparaître aléatoirement la pomme que le serpent doit manger et en faire apparaître une autre à chaque fois qu’elle est mangée. Suite à quoi je dois faire prendre en compte qu’à chaque pomme que le serpent mange, il grandit. Le tout en insérant une fonction de score.

1.3)Solution

Afin de combler cette lacune en C# la principale partie de mon travail sera de chercher des informations quant au langage. Le site m’a beaucoup aidé. Quant aux différentes étapes ce sera beaucoup de réflexion, afin de trouver les moyens d’effectuer mes idées. Les solutions trouvées seront expliquées dans la suite et le code sera accompagné de beaucoup de commentaire afin de faciliter la compréhension, mon but étant de permettre à quelqu'un avec peu de notion de pouvoir comprendre mon code.

2)Matériel et méthodes

2.1)Matériel

Il n’y a pas beaucoup de secret pour le matériel. Il suffit d’avoir de quoi coder :

  • Ordinateur avec clavier
  • Un logiciel de codage

2.2)Méthode

Je décrirais ici les étapes les plus importantes telles que le score, le menu, etc… . Pour faciliter la compréhension j’ai rajouté des commentaires à un maximum de lignes de code afin de pouvoir comprendre à quoi ils servent. Afin de mieux comprendre le langage utilisé j’ai déclaré toutes mes variables avec un commentaire pour expliquer à quoi ils servent.

2.3)Afficher le serpent

Je commence par coder le serpent afin de pouvoir l’afficher plus tard. Pour ça il y a deux parties : la tête et le corps. On commence par déclarer une méthode avec « static void » et les différents paramètres entre parenthèses. Cela permettra de ne pas avoir à tout noter à chaque fois.

static void AfficherSerpent (int [,] tab_intSerPos, char chr_Dir, int int_LongSer)

Une fois cela fait, on peut commencer le code. On commence par mettre deux boucles « for » et pas une boucle « while » ou « do .. while » car le nombre de passages dans la boucle correspond à la longueur du serpent qui est connue. La première est pour le corps du serpent et la deuxième pour la tête. Une boucle « for » se compose comme ça : For(compteur ;conditions ;incrémentations/décrémentations)

 for (int_CptLongSer = 0; int_CptLongSer < int_LongSer; int_CptLongSer++)
 for (int_CptColSer = 0; int_CptColSer < int_ColSer; int_CptColSer++) 

Pour la tête il faut ensuite créer une condition pour que la tête et le corps se mette dans la direction du serpent. Pas de langage bien compliqué ici :

 if (int_CptLongSer == 0 && chr_Dir == 'H')//tete du serpent haut
 {
 Console.SetCursorPosition(tab_intSerPos[int_CptColSer, 1], tab_intSerPos[int_CptLongSer, 0]);//met le curseur a la tete du serpent
 Console.ForegroundColor = ConsoleColor.Green;
 Console.Write('▲');//affiche la tete du serpent
 Console.ForegroundColor = ConsoleColor.White;
 }//fin du if

Recommencer en mettant les conditions pour chaque direction.

2.4)Afficher terrain

On commence par nommer la méthode grâce au « static void » comme précédemment. On crée ensuite deux boucles à nouveau, une pour les lignes et l’autre pour les colonnes. Encore une fois l’utilisation d’une boucle « for » car on mettra plus tard les dimensions du terrain.

 for (int_CptLig = 0; int_CptLig < int_NbLig; int_CptLig++)
 {
 for (int_CptCol = 0; int_CptCol < int_NbCol; int_CptCol++)
 {

Une fois la boucle définit on met les conditions afin d’obtenir les cotés du terrain. Par exemple :

 if (int_CptLig == 0 || int_CptLig == int_NbLig - 1)
 tab_chrTerrain[int_CptLig, int_CptCol] = '═';

Recommencer en changeant les paramètres afin d’obtenir une bordure partout. Il faudra donc 6 conditions (les quatre coins, les cotés horizontaux et verticaux). Il ne reste qu’à définir les couleurs et ordonner à la console d’afficher le terrain, 2 codes qui servent pour changer les couleurs de toutes choses si nécessaire. :

 Console.ForegroundColor = ConsoleColor.Yellow;
 Console.Write(tab_chrTerrain[int_CptLig, int_CptCol]);//affiche le terrain
 Console.ForegroundColor = ConsoleColor.White; 

2.5)Menu

Ici rien de vraiment très compliqué. Il faudra utiliser une boucle « do…while » qui servira à afficher le menu tant que rien n’a été séléctionner. Il faut ouvrire la boucle avec le « do » puis il suffit d’utiliser « Console.WriteLine(« nom ») » suivi d’un nom afin de l’afficher lors du démarrage. Par exemple :

 Console.WriteLine("\n\n\n\t\tJouer");
 Console.Write('→');//fleche du choix de l'option 

Les « n » servent aux retours à la ligne et les « t » à la tabulation. Il suffit de mettre les lignes qu’on veut (il est important de noter à quelle ligne elle sera écrite, un « n » fait descendre de deux lignes). Une fois cela fait il reste à faire prendre en compte à l’ordi les croix directionnelles haut, bas et la touche enter. Pour cela il faut utiliser une condition (« if ») suivi de « cki.Menu.Key == ConsoleKey.direction » et mettre la réaction à cette condition.

 if (cki_Menu.Key == ConsoleKey.DownArrow)//si fleche bas
 int_Choix += 2;//descendre de deux 

Refaire l’opération pour la flèche du haut. Pour finir il faut mettre la boucle while qui permet de faire son choix une fois qu’on appuie sur Enter Ceci fait, on devrait obtenir un menu opérationnel, il ne reste plus qu’à remplir les différentes entrées comme bon nous semble.

MenuSnake.JPG

Pour changer la couleur, cela se fait en une ligne qu’il faut mettre avant votre « Console.WriteLine… » :

 Console.ForegroundColor = ConsoleColor.Red;

2.6)Mouvement

Pour les mouvements, il faut d’abord ouvrir une boucle while suivi des conditions if et leur direction associée pour qu’à chaque pression sur une flèche s’exécute en boucle la direction demandé jusqu’à une autre action. Voilà ce que la condition donnera :

 if (cki_Dir.Key == ConsoleKey.UpArrow && chr_DirCopie != 'B')//haut // si la copie = l'inverse => peut pas faire l'inverse!
 {
 chr_Dir = 'H';
 chr_DirCopie = 'H';//copie de la position pour ne pas faire demi tour
 }//fin du if

Ceci sert a définir les différentes touches. Il faut recommencer l’opération pour les autres cotés en changeant les flèchent et le « chr_Dir » (G pour gauche par exemple) Suite à quoi va venir s’additionner une autre condition « if » qui viendra contenir une boucle « for ». On a définit les touches, il faut maintenant définir à quoi elles servent. Pour le définir il faut indiquer la condition qui est le bouton pressé est une boucle définissant comment la console doit réagir et le changement de position :

 /*MONTER*/
 if (chr_Dir == 'H')
 {
 for (int_CptLongSer = int_LongSer - 1; int_CptLongSer > 0; int_CptLongSer--)
 {
 tab_intSerPos[int_CptLongSer, 0] = tab_intSerPos[int_CptLongSer - 1, 0];
 tab_intSerPos[int_CptLongSer, 1] = tab_intSerPos[int_CptLongSer - 1, 1];
 }
 tab_intSerPos[0, 0] = tab_intSerPos[1, 0] - 1;
 }

Pour les autres mouvements il s’agira de changer les chiffres de la dernière ligne.

2.7)La pomme

Pour commencer, comme pour le serpent. Il faut créer l’objet. Rien de bien nouveau ici :

 Console.SetCursorPosition(tab_intPomme[0], tab_intPomme[1]);
 Console.ForegroundColor = ConsoleColor.Red;
 Console.Write('☻');

Ainsi est crée la pomme ainsi que sa position (les « tab_intPomme » correspondent si on peut dire aux axes x et y). Il faut donc commencer par gérer la première pomme lorsque le jeu est lancé. Il faut créer la condition que si aucune pomme n’est là, il faut en générer une aléatoirement et que dès que le serpent passe dessus, une nouvelle doit être créée. Il faut donc commencer par la condition, puis ajouter les coordonnées que la pomme devra avoir et mettre une boucle qui prend en compte qu’à chaque fois que le serpent passe dessus, il faudra générer une nouvelle pomme.Ce qui nous donne :

 if (tab_intPomme[1] == 0 && tab_intPomme[0] == 0)//si debut du jeu
 {
 Random Pomme = new Random();
 tab_intPomme[1] = Pomme.Next(7, INT_NBLIG - 2);//genere la position vertical
 tab_intPomme[0] = Pomme.Next(2, INT_NBCOL - 2);//genere la position horizontal
 for (int_CptGO = 0; int_CptGO < int_LongSer; int_CptGO++)
 for (int_CptGO2 = 0; int_CptGO2 < int_ColSer; int_CptGO2++)
 if (tab_intPomme[0] == tab_intSerPos[int_LongSer - int_CptGO, 0] && tab_intPomme[1] == tab_intSerPos[int_LongSer - int_CptGO, 1])
 {
 tab_intPomme[1] = Pomme.Next(7, INT_NBLIG - 2);//genere la position vertical
 tab_intPomme[0] = Pomme.Next(2, INT_NBCOL - 2);//genere la position horizontal
 }
 Console.SetCursorPosition(tab_intPomme[0], tab_intPomme[1]);//met le curseur a la position generee
 Console.ForegroundColor = ConsoleColor.Red;
 Console.Write('☻');
 Console.ForegroundColor = ConsoleColor.White;
 }//fin du if @@

Voilà, il ne reste plus qu’à faire tenir compte qu’à chaque fois que le serpent mange une pomme, il grandit. Pour cela il faut commencer par mettre la condition que le serpent passe sur la pomme et en mettre les conséquences (par exemple « int_Score++ » qui va permettre d’augmenter le score de 1). Pour la longueur du serpent il suffit de mettre à la suite de ça :

 if (int_CptLongSer < 1000)
 int_LongSer++;

On peut s’amuser à mettre d’autres règles encore, les possibilités sont infinies.

2.8)Score

Pour le triage de score, j’ai copié et collé ce que j’ai pu trouver, en l’occurrence nommé RunQuery. On a vu avant qu’à chaque pomme mangée le score augmente de 1. Il faut maintenant créer une possibilité de fin au jeu pour pouvoir admirer son score final. Pour ça il faut créer les conditions qui entraînent le game over. Dans le cadre du snake il y a deux possibilités : toucher un bord ou se mordre. Pour la première possibilité il faut note que si le serpent touche la valeur du bord alors ça entraîne le game over :

 if (tab_intSerPos[0, 1] == INT_NBCOL - 1 || tab_intSerPos[0, 0] == INT_NBLIG + 4 || tab_intSerPos[0, 1] == 0 || tab_intSerPos[0, 0] == 5)
 bln_GameOver = false; 

On recommence pour le deuxième cas mais en nottant que si la valeur de la tête du serpent arrive sur la valeur de son corps, alors il y a game over.Pour pouvoir avoir un tableau des scores, il faut mettre une condition pour commencer qui crée le fichier score s’il n’existe pas :

 if (!File.Exists("./Score.csv"))//si le fichier score n'existe pas
 {
 StreamWriter Score = File.CreateText("./Score.csv");//crée

Et si le dossier existe :

 Else 
 {
 StreamWriter Score = File.AppendText("./Score.csv") ;

Puis il faut mettre une condition pour chaque zéros en plus que le score pourrait avoir (10 ;100 ;1000 ;…) qui permet de reprendre ton nom et le mettre avec ton score :

 if (int_Score < 10)
 {
 Score.WriteLine(str_Nom + ";" + "00000" + int_Score, "./Score.csv");//ecrit le score
 Score.Close();//ferme le fichier

ScoreSnake.JPG



Voilà, j’ai expliqué ce qui me paraissait le plus compliqué et nécessitant le plus d’explication. Pour le reste du code il s’agit beaucoup de finition qui est facilement compréhensible avec les notes que j’ai mises à coté. Comme on a pu le voir, le code n’est pas forcément compliqué mais c’est le fait de réfléchir à la façon de tourner les choses qui est compliqué.

3)Résultats

J'obtiens au final un snake fonctionnel qui a cette apparence:

JeuSnake.JPG

3.1)Discussion

Quelques petits bugs persistent au niveau notamment des scores ou lors ce que le serpent va en haut et mange une pomme, le coin du serpent disparaît. Je ne sais pas d'ou cela peut venir, il faudrait relire tout le code, il doit surement y avoir une faute de syntaxe quelque part. J'obtiens tout de même un jeu offrant un score et un menu doté de plusieurs entrées. Tout le reste à l'air de bien fonctionner. Ce projet m'a permis d'en apprendre d'avantage sur le C# mais aussi de pouvoir mettre un pas (aussi petit soit-il) dans le codage de jeu. Pour y arriver j'ai dû organiser mes idées, rechercher des informations et trier les différentes possibilités pour ensuite l'effectuer. J'espère que cela sera aussi bénéfique pour la personne qui lit mon billet que ça l'a été pour moi.

3.2) Future

Cette version du code est largement améliorable. Le but étant que n'importe qui puisse s'y retrouver dans mon code et donc l'utiliser pour l'améliorer. Il y a de nombreuses possibilité pour l'améliorer. On peut rajouter des fruits qui donnent chacun leur propre score ou leur effet, faire s'afficher plusieurs fruits en même temps, gérer variables telles que la vitesse ou la grandeur du tableau. Il est aussi tout à fait possible de créer une meilleure apparence, de changer les couleurs, les règles, ect... .

4)Conclusion

Voilà, mon projet est fini. Je suis fier de ce que j'ai pu faire et j'espère l'avoir rendu assez clair pour n'importe qui voulant simplement le voir ou bien même le reprendre. Le but pour moi de ce snake était de comprendre un peu mieux comment marcher un jeu et ce but a été acquis. J'ai pu créer et observer le "squelette" d'un snake. Un autre but étant d'acquérir les bases, mais surtout de permettre à quelqu'un qui n'a pas les bases de pouvoir comprendre de quoi le code est situé et pourquoi mettre tel code à telle place. Maintenant que le jeu à été créer, j'invite les plus courageux d'entre vous à le reprendre et à l'améliorer! À toutes accusations de plagiat. je tiens à préciser qu'effectivement j'ai reçu de l'aide pour m'expliquer le langage, apprendre à taper mon code de la meilleure manière possible et mieux me familiariser avec le C# mais le tout est de moi. J'ai travaillé longtemps sur ce projet, à chercher ce dont j'ai besoin (site du zéro) et j'ai appris beaucoup plus qu'en une année dans la classe d'informatique. Il suffit de vouloir apprendre, être intéressé et beaucoup de travail, mais voilà ce à quoi un élève mauvais en informatique peut réussir à faire avec de l'obstination.

références