|
| [TUTOGAMEBUINO] Programmation Snake | |
| Auteur | Message |
---|
FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| Msg n°1 Sujet: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 13:07 | |
| A la demande de BAF, voici un petit "cours" sur comment j'ai développé ce Snake. Snake est en fait une série de points qui sont contigus. Pour le faire avancer, c'est très simple, il suffit d'ajouter un point d'un côté et de le supprimer de l'autre. Ce qui donne cette impression d'avancement. Dans l'exemple ci-dessous, Snake avance vers la droite : [Vous devez être inscrit et connecté pour voir cette image]En programmation, on va représenter ça par un tableau qui contiendra, pour chaque point, ses coordonnées en x et y. Sur la Gamebuino, voici comment sont les coordonnées : [Vous devez être inscrit et connecté pour voir cette image]Sur l'écran, les coordonnées : - du coin haut gauche : 0,0 - du coin haut droite : LCDWIDTH-1,0 - du coin bas gauche: 0,LCDHEIGHT-1 - du coin bas droite : LCDWIDTH-1,LCDHEIGHT-1 Notre tableau doit donc contenir tous les points du serpent. Le serpent faisant 10 pixels pour lesquels on a deux valeurs (x et y), le tableau est créé comme ceci : - Code:
-
int Snake [10][2];
Mais comme notre serpent grandit au fur et à mesure qu'il mange des gommes, on ne peut pas laisser tel quel sinon il ne pourra pas grandir. Deux options : - soit on prévoit une taille suffisamment grande, mais on prend le risque d'utiliser de la mémoire pour rien - soit on redimensionne le tableau au fur et à mesure qu'on a de nouveaux points Pour le moment, je l'ai joué faignant, j'ai fait un tableau plus grand. Le redimensionnement en C n'est pas aussi simple qu'en VB par exemple, et n'est pas forcément plus performant : en effet, en C, on va créér un nouveau tableau plus grand et copier les valeurs de l'ancien dans le nouveau. Cela se joue quand même en micro ou millisecondes Donc mon tableau est construit comme ceci : - Code:
-
int Snake [255][2];
"int" car je vais stocker des entiers dans ce tableau. Une fois le tableau créé, il faut l'initialiser. J'ai décidé que le serpent partirait de la gauche de l'écran vers la droite, et de la mi-hauteur. L'ordonnée de tous les points sera donc LCDHEIGHT/2. Et pour les abscisses, on part de 0 et on ajoute 1 à chaque nouveau point : - Code:
-
for (i = 0; i <= len_snake; i++) { Snake[i][0] = i; Snake[i][1] = (LCDHEIGHT / 2); } len_snake est la variable dont je me sers pour déterminer la longueur en cours du serpent, 10 pour démarrer. Une fois ceci fait, il n'y a plus qu'à faire avancer le serpent. Et là je vais parler un petit peu du dev sur la Gamebuino.
Dernière édition par FreddyBoubil le Lun 12 Mai 2014, 15:11, édité 2 fois |
| | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| Msg n°2 Sujet: Re: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 13:37 | |
| Sur les programmes simples, il y a 4 "zones" de code : - l'appel des librairies de la Gamebuino - la déclaration des variables du programme - la fonction d'initialisation du programme - la boucle infinie qui fait tourner le jeu - Code:
-
//appel des librairies #include <SPI.h> #include <Gamebuino.h>
//déclaration des variables int mon_nombre = 0;
//la fonction d'initialisation du programme void setup() { gb.begin(F("Test nombre")); }
//la boucle infinie void loop() { if (gb.update()) { mon_nombre = random(0,255); gb.display.setCursor(20,20); gb.display.print(mon_nombre); } }
Dans la fonction setup(), j'y ai notamment mis mon initialisation du tableau de points pour que le serpent soit affiché à gauche, milieu en hauteur. La Gamebuino va donc rester dans la boucle infinie. A chaque nouvelle frame, gb.update() renvoie True. La console va donc rentrer dans le if et suivre le code qui s'y trouve. Dans l'exemple ci-dessus, à chaque nouvelle frame je tire un nombre aléatoire entre 0 et 255 et je l'affiche sur l'écran, à la position 20,20. Dans le cadre de Snake, le serpent va avancer à chaque frame. Mais ce qui va être important c'est de savoir vers où. En effet, si par défaut il va à droite, on peut le faire changer de direction. En fonction de la direction où il va, les coordonnées du nouveau point ne seront pas les mêmes. On se base toujours sur le dernier point disponible dans le tableau : - Code:
-
switch (cur_direction) { case 0 : new_x = Snake[len_snake][0] - 1; new_y = Snake[len_snake][1]; break; case 1 : new_x = Snake[len_snake][0] + 1; new_y = Snake[len_snake][1]; break; case 2 : new_x = Snake[len_snake][0]; new_y = Snake[len_snake][1] - 1; break; case 3 : new_x = Snake[len_snake][0]; new_y = Snake[len_snake][1] + 1; break; }
cur_direction est la variable qui me sert à savoir vers où va le serpent : 0 : vers la gauche (-1 sur l'abscisse, même ordonnée) 1 : vers la droite (+1 sur l'abscisse, même ordonnée) 2 : vers le haut (même abscisse, -1 sur l'ordonnée) 3 : vers le bas (même abscisse, +1 sur l'ordonnée) Une fois qu'on a déterminé les coordonnées du nouveau point, on fait au préalable avancer les autres. C'est simple : chaque point prend les coordonnées de son suivant dans le tableau : - Code:
-
for (i = 0; i < len_snake; i++) { Snake[i][0] = Snake[i+1][0]; Snake[i][1] = Snake[i+1][1]; }
Et il ne reste plus qu'à donner les nouvelles coordonnées au dernier point - Code:
-
Snake[len_snake][0] = new_x; Snake[len_snake][1] = new_y; Une fois que c'est fait, il n'y a plus qu'à afficher le serpent. Pour cela, on parcourt le tableau et on affiche chaque point à ses coordonnées : - Code:
-
for (i = 0; i <= len_snake; i++) { gb.display.drawPixel(Snake[i][0],Snake[i][1]); } Et tout ceci va bien entendu dans le if (gb.update()) . |
| | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| Msg n°3 Sujet: Re: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 13:49 | |
| Donc le serpent avance, c'est cool. Maintenant il faut le faire changer de direction. Là encore c'est très simple. Avant de déterminer les coordonnées du prochain point, on checke si le joueur a appuyé sur un bouton, auquel cas on change la valeur de cur_direction - Code:
-
if (gb.buttons.pressed(BTN_UP)) { cur_direction = 2; } else if (gb.buttons.pressed(BTN_DOWN)) { cur_direction = 3; } else if (gb.buttons.pressed(BTN_LEFT)) { cur_direction = 0; } else if (gb.buttons.pressed(BTN_RIGHT)) { cur_direction = 1; } Et c'est tout . Vous avez maintenant un serpent qui avance et peut changer de direction. Idéalement il faudrait qu'il ne puisse pas passer sur lui-même maintenant. Là encore c'est simple. Quand on détermine les coordonnées du nouveau point, il faut regarder s'il n'est pas déjà présent dans le tableau. Si oui, cela veut dire que le serpent est déjà présent à ces coordonnées, donc il se passe dessus : - Code:
-
for (i = 0; i < len_snake; i++) { if (Snake[i][0] == Snake[len_snake][0] && Snake[i][1] == Snake[len_snake][1]) { gameover = true; i = len_snake; } } Vous voyez la variable gameover. Elle me sert à savoir si le joueur est game over ou non, et d'afficher le cas échéant le message ainsi que son score (tout le traitement de faire avancer le serpent n'est pas fait dans ce cas). Pour peaufiner, on va ajouter le fait qu'il y a Game Over si le joueur sort de l'écran : - Code:
-
if (new_x < 0 || new_x > LCDWIDTH-1 || new_y < 0 || new_y > LCDHEIGHT-1) { gameover = true; } |
| | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| Msg n°4 Sujet: Re: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 14:34 | |
| Notre serpent avance, peut changer de direction, ne peut pas repasser sur lui-même ou sortir de l'écran. Maintenant on va ajouter les gommes. Les gommes sont tout simplement des carrés de 3 pixels de côté placés aléatoirement sur l'écran. - Code:
-
x_gum = random(0,LCDWIDTH - 4); y_gum = random(8,LCDHEIGHT - 4); gb.display.fillRect(x_gum, y_gum, 3, 3); La fonction fillRect prend en entrée les coordonnées x et y du coin haut gauche du rectangle, puis sa taille en largeur et hauteur. J'utilise ici LCDWIDTH et HEIGHT -4 car j'enlève les 3 pixels de la gomme, pour éviter qu'elle soit en partie hors de l'écran. On va ensuite détecter si le serpent passe dessus ou non. Pour cela, j'utilise la fonction collidePointRect : - Code:
-
if (gb.collidePointRect(Snake[len_snake][0], Snake[len_snake][1], x_gum, y_gum, 3, 3) || debut) { collidePointRect prend en entrée : - les coordonnées du point qu'on veut tester - les coordonnées du coin supérieur gauche du rectangle qu'on veut tester - ainsi que sa largeur et sa hauteur. Je me sers de la variable "debut" (qui est un booléen) pour créer la première gomme. En effet, la probabilité pour que la première gomme apparaisse sur le serpent est faible, ce qui fait que j'ai de grandes chances de ne pas avoir de gommes au démarrage du jeu. Quand le serpent passe sur la gomme il faut :1°) faire grandir le serpentJe vais utiliser une variable, enlarge_snake, qui sera incrémentée de 3 au passage sur une gomme. A chaque nouvelle frame, si cette variable est supérieure à 0, on ne va pas décaler tous les points dans le tableau comme habituellement, on va juste en ajouter des nouveaux à la fin : comme si le serpent grandissait côté tête. On lui enlève 1 et on fait cette opération à chaque frame, tant que la variable est supérieure à 0. Cette variable passe à 3 uniquement si le serpent ne risque pas dépasser sa taille max (255). Cette variable peut aussi être supérieure à 3 si le serpent passe sur deux gommes qui se suivent. - Code:
-
if (total_len_snake < max_len_snake - 4) { enlarge_snake += 3; } puis, sur le code déjà vu plus haut pour décaler les points, on le fait uniquement si le serpent n'est pas en train de grandir : - Code:
-
if (enlarge_snake == 0) { for (i = 0; i < len_snake; i++) { Snake[i][0] = Snake[i+1][0]; Snake[i][1] = Snake[i+1][1]; } } else { enlarge_snake --; len_snake ++; } 2°) Augmenter le scoreTrès simple, une variable initialisée à 0 en début de programme, qu'on incrémente de 5. - Code:
-
score += 5; 3°) Augmenter la vitesse du jeu si le score est un multiple de 25Là encore très simple, il suffit de jouer sur le framerate . Au lancement du jeu, j'ai initialisé le framerate à 10, avec une variable "framerate" dont la valeur est 10. J'augmente cette valeur de 2 tous les 25 points et je redéfinis le framerate : - Code:
-
if (score > 0 && score % 25 == 0) { framerate+=2; gb.setFrameRate(framerate); } 4°) Générer une nouvelle gommeOn définit une nouvelle valeur x et y pour créer le nouveau carré de 3 pixels. J'ai souhaité que cette nouvelle gomme ne puisse pas apparaitre sur le serpent. J'ai un peu galéré mais cela semble fonctionner. L'idée c'est de générer de nouvelles coordonnées tant que la gomme est en collision avec le serpent. - Code:
-
new_gum = true; while (new_gum) { x_gum = random(0,LCDWIDTH - 4); y_gum = random(8,LCDHEIGHT - 4); for (i = 0; i < total_len_snake; i++) { // Test that the new gum is not on the snake if (gb.collidePointRect(Snake[i][0], Snake[i][1], x_gum, y_gum, 3, 3)) { // The new gum is already on Snake // We will generate a new gum x_gum = random(0,LCDWIDTH - 4); y_gum = random(8,LCDHEIGHT - 4); } else { new_gum = false; } } // for } // while new_gum
Dernière édition par FreddyBoubil le Lun 12 Mai 2014, 15:31, édité 2 fois |
| | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| Msg n°5 Sujet: Re: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 14:40 | |
| Voilà Je n'ai pas détaillé l'ensemble du code, mais juste les parties pour comprendre comment mettre en place les différentes fonctionnalités du jeu. Je n'ai pas notamment expliqué comment faire le Game Over ou la Pause, mais ce n'est pas très compliqué. Je ne m'attarderai pas sur l'apprentissage du C. Si vous avez des questions à ce sujet, je vous invite quand même à consulter Google, ce ne sont pas les sites et forums qui manquent. Je l'ai fait moi-même lors de la rédaction de ce code. Et pour vous montrer que oui, c'est faisable, je n'y connaissais rien au PHP et au CSS et j'ai pourtant réussi à pondre le moteur de recherche Je n'ai pas non plus la prétention de dire que ce code est parfait, c'est toujours optimisable :)Et cadeau, je vous mets ici le code complet à l'heure où j'écris ces lignes (car il est possible qu'il évolue ): - Code:
-
#include <SPI.h> #include <Gamebuino.h>
Gamebuino gb = Gamebuino(); int Snake [255][2]; int i; int j; int new_x; int new_y; int x_gum = -1; int y_gum; int score = 0; int len_snake = 9; int enlarge_snake = 0; int total_len_snake; int max_len_snake = 255; int framerate = 10; int cur_direction = 1; // 0 = left, 1 = right, 2 = up, 3 = down. The current direction of the snake boolean paused = true; // game starts paused, the snake doesn't move boolean gameover = false; boolean new_gum = true; boolean debut = true;
void setup() { for (i = 0; i <= len_snake; i++) { Snake[i][0] = i; Snake[i][1] = (LCDHEIGHT / 2); } gb.begin(F("Snake by FreddyBoubil")); gb.battery.display(false); //hide the battery indicator gb.setFrameRate(framerate); }
void loop() { if (gb.update()) { if (!gameover) { if(gb.buttons.pressed(BTN_C)) { paused = !paused; } if(!paused){ if (gb.buttons.pressed(BTN_UP)) { cur_direction = 2; } else if (gb.buttons.pressed(BTN_DOWN)) { cur_direction = 3; } else if (gb.buttons.pressed(BTN_LEFT)) { cur_direction = 0; } else if (gb.buttons.pressed(BTN_RIGHT)) { cur_direction = 1; } switch (cur_direction) { case 0 : new_x = Snake[len_snake][0] - 1; new_y = Snake[len_snake][1]; break; case 1 : new_x = Snake[len_snake][0] + 1; new_y = Snake[len_snake][1]; break; case 2 : new_x = Snake[len_snake][0]; new_y = Snake[len_snake][1] - 1; break; case 3 : new_x = Snake[len_snake][0]; new_y = Snake[len_snake][1] + 1; break; } // Detection of Snake on a border of the screen if (new_x < 0 || new_x > LCDWIDTH-1 || new_y < 8 || new_y > LCDHEIGHT-1) { gameover = true; } else { // Does the snake over himself ? If so, game over for (i = 0; i < len_snake; i++) { if (Snake[i][0] == Snake[len_snake][0] && Snake[i][1] == Snake[len_snake][1]) { gameover = true; i = len_snake; } } } if (!gameover) { if (enlarge_snake == 0) { for (i = 0; i < len_snake; i++) { Snake[i][0] = Snake[i+1][0]; Snake[i][1] = Snake[i+1][1]; } } else { enlarge_snake --; len_snake ++; } Snake[len_snake][0] = new_x; Snake[len_snake][1] = new_y;
// Is Snake on the gum ? if (gb.collidePointRect(Snake[len_snake][0], Snake[len_snake][1], x_gum, y_gum, 3, 3) || debut) { total_len_snake = len_snake + enlarge_snake; if (!debut) { //Snake has a max size we can't go over if (total_len_snake < max_len_snake - 4) { enlarge_snake += 3; } score += 5; } else { debut = false; } if (score > 0 && score % 25 == 0) { framerate+=2; gb.setFrameRate(framerate); } new_gum = true; while (new_gum) { x_gum = random(0,LCDWIDTH - 4); y_gum = random(8,LCDHEIGHT - 4); for (i = 0; i < total_len_snake; i++) { // Test that the new gum is not on the snake if (gb.collidePointRect(Snake[i][0], Snake[i][1], x_gum, y_gum, 3, 3)) { // The new gum is already on Snake // We will generate a new gum x_gum = random(0,LCDWIDTH - 4); y_gum = random(8,LCDHEIGHT - 4); } else { new_gum = false; } } // for } // while new_gum } // if collide }// If !gameover } // Fermeture if !paused if (x_gum > -1) { gb.display.fillRect(x_gum, y_gum, 3, 3); } gb.display.setTextSize(1); gb.display.setCursor(1,1); gb.display.print("Score:"); gb.display.setCursor(25,1); gb.display.print(score); gb.display.setCursor(48,1); gb.display.print("Speed:"); gb.display.setCursor(72,1); gb.display.print(framerate); gb.display.drawFastHLine(1,7,LCDWIDTH-2); for (i = 0; i <= len_snake; i++) { gb.display.drawPixel(Snake[i][0],Snake[i][1]); } } // If !gameover else { gb.display.setTextSize(1); gb.display.setCursor(15,16); gb.display.print("Game over"); gb.display.setCursor(15,23); gb.display.print("Score : "); gb.display.setCursor(47,23); gb.display.print(score); //If player presses A button, let's play again if(gb.buttons.pressed(BTN_A)) { len_snake = 9; for (i = 0; i <= len_snake; i++) { Snake[i][0] = i; Snake[i][1] = (LCDHEIGHT / 2); } score = 0; enlarge_snake = 0; cur_direction = 1; paused = true; gameover = false; new_gum = true; debut = true; x_gum = -1; framerate = 10; gb.setFrameRate(framerate); } } // Fermeture de if !gameover } // Fermeture if gb.update } Ca peut vous permettre de mieux comprendre le fonctionnement en voyant l'ensemble |
| | | admin Team Open Consoles
Messages : 15193 Réputation : 399 Inscrit le : 13/10/2010
| | | | k0en Team Open Consoles
Messages : 10800 Réputation : 365 Age : 43 Inscrit le : 25/01/2011
TO7-70
Localisation : Devant son écran
Humeur : Indécis
| | | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| | | | SpikeSpiegel Membre d'honneur VIP
Messages : 6181 Réputation : 211 Age : 45 Inscrit le : 07/04/2012
RPI, PI-LEGOBOY, DINGOO A320, GCW-Zero, PocketCHIP
| | | | k0en Team Open Consoles
Messages : 10800 Réputation : 365 Age : 43 Inscrit le : 25/01/2011
TO7-70
Localisation : Devant son écran
Humeur : Indécis
| Msg n°10 Sujet: Re: [TUTOGAMEBUINO] Programmation Snake Lun 12 Mai 2014, 21:26 | |
| Oui oui allez-y les gars, moi même si ça à l'air limpide quand c'est expliqué par Freddy, j'y comprends toujours rien |
| | | FreddyBoubil Arcade gamer
Messages : 8441 Réputation : 241 Inscrit le : 03/01/2011
Arcade
Localisation : Devant ma borne
Humeur : Qu'importe le support, pourvu qu'on ait le fun.
| | | | SpikeSpiegel Membre d'honneur VIP
Messages : 6181 Réputation : 211 Age : 45 Inscrit le : 07/04/2012
RPI, PI-LEGOBOY, DINGOO A320, GCW-Zero, PocketCHIP
| | | | Contenu sponsorisé
| | | | |
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| La Timeline Open-Consoles |
|
|