English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Première introduction à l'expérience
1.1 Contenu de l'expérience
Dans cette section de l'expérience, nous allons réaliser la conception des principales fonctions du Tetris, accomplir les fonctions de base et exécuter
1.2 Points de l'expérience
Dessin de la fenêtre
Conception de la classe de bloc
Algorithme de rotation
Fonctions de déplacement et d'élimination
1.3 Environnement de l'expérience
xface terminal
g++ Compilateur
Bibliothèque ncurses
1.4 Compiler le programme
Ajouter la commande de compilation -l Options pour inclure la bibliothèque ncurses :
g++ main.c -l ncurses
1.5 Exécuter le programme
./a.out
1.6 Résultat de l'exécution
Deuxième étape de l'expérience
2.1 Fichiers d'en-tête
Tout d'abord, incluez les fichiers d'en-tête et définissez une fonction d'échange et une fonction de nombre aléatoire, utilisées plus tard (la fonction d'échange est utilisée pour faire pivoter les blocs, et le nombre aléatoire est utilisé pour définir la forme des blocs)
#include <iostream> #include <sys/time.h> #include <sys/types.h> #include <stdlib.h> #include <ncurses.h> #include <unistd.h> /* Échange a et b */ void swap(int &a, int &b){ int t=a; a = b; b = t; } /* Obtient un entier aléatoire dans l'intervalle (min, max) int getrand(int min, int max) { return(min+rand()%(max-min+1)); }
2.2 Définir la classe
Étant donné que le contenu du programme est relativement simple, seule une classe Piece est définie ici
class Piece { public: int score; //Points int shape; //Représente la forme du bloc actuel int next_shape; //Représente la forme du prochain bloc int head_x; //La position de la première boîte du bloc actuel, position marquée int head_y; int size_h; //La taille actuelle du bloc int size_w; int next_size_h; //La taille du prochain bloc int next_size_w; int box_shape[4][4]; //Array de forme du cube actuel 4x4 int next_box_shape[4][4]; //Array de forme du cube suivant 4x4 int box_map[30][45]; //Utilisé pour marquer chaque box dans la boîte de jeu bool game_over; //Indicateur de fin de jeu public: void initial(); //Fonction d'initialisation void set_shape(int &cshape, int box_shape[][4],int &size_w, int & size_h); //Configuration de la forme du cube void score_next(); //Afficher la forme du cube suivant et le score void judge(); //Vérifier si le niveau est complet void move(); //Fonction de déplacement, contrôlée par ← → ↓ void rotate(); //Fonction de rotation bool isaggin(); //Vérifier si la prochaine action sort des limites ou se chevauche bool exsqr(int row); //Vérifier si la ligne actuelle est vide };
2.3 Configuration de la forme du cube
Ici, le cas est utilisé pour définir7Les formes du cube doivent être configurées avant chaque chute du cube suivant, pour définir sa forme et sa position initiale
void Piece::set_shape(int &cshape, int shape[][4],int &size_w,int &size_h) { /*Tout d'abord, l'array utilisé pour représenter4x4L'array est initialisé à 0*/ int i,j; for(i=0;i<4;i++); for(j=0;j<4;j++); shape[i][j]=0; /*Configuration7Les formes initiales et leur size sont configurées*/ switch(cshape) { case 0: size_h=1; size_w=4; shape[0][0]=1; shape[0][1]=1; shape[0][2]=1; shape[0][3]=1; break; case 1: size_h=2; size_w=3; shape[0][0]=1; shape[1][0]=1; shape[1][1]=1; shape[1][2]=1; break; case 2: size_h=2; size_w=3; shape[0][2]=1; shape[1][0]=1; shape[1][1]=1; shape[1][2]=1; break; case 3: size_h=2; size_w=3; shape[0][1]=1; shape[0][2]=1; shape[1][0]=1; shape[1][1]=1; break; case 4: size_h=2; size_w=3; shape[0][0]=1; shape[0][1]=1; shape[1][1]=1; shape[1][2]=1; break; case 5: size_h=2; size_w=2; shape[0][0]=1; shape[0][1]=1; shape[1][0]=1; shape[1][1]=1; break; case 6: size_h=2; size_w=3; shape[0][1]=1; shape[1][0]=1; shape[1][1]=1; shape[1][2]=1; break; } //Après avoir configuré la forme, initialiser la position de départ du cube head_x=game_win_width/2; head_y=1; //Si il se chevauche dès l'initialisation, la partie est finie~ if(isaggin()) /* GAME OVER ! */ game_over=true; }
2.4 Fonction de rotation
Ici, une algorithmes assez simple est utilisée pour faire pivoter le cube, similaire à la rotation d'une matrice, où d'abord l'array shape est symétrisé diagonalement, puis symétrisé horizontalement, ce qui complète la rotation. Il est important de vérifier si le cube sort des limites ou se chevauche après la rotation; si c'est le cas, annuler cette rotation.
void Piece::rotate() { int temp[4][4]= {0}; //Variable temporaire int temp_piece[4][4]= {0}; //Array de sauvegarde int i,j,tmp_size_h,tmp_size_w; tmp_size_w=size_w; tmp_size_h=size_h; for(int i=0; i<4;i++); for(int j=0;j<4;j++); temp_piece[i][j]=box_shape[i][j]; //Faites une sauvegarde de la forme actuelle du carré, retournez à la forme actuelle si la rotation échoue for(i=0;i<4;i++); for(j=0;j<4;j++); temp[j][i]=box_shape[i][j]; //Symétrie diagonale i=size_h; size_h=size_w; size_w=i; for(i=0;i<size_h;i++); for(j=0;j<size_w;j++); box_shape[i][size_w-1-j]=temp[i][j]; //Symétrie horizontale /*Si la rotation après redondance, retournez à la forme de l'array de sauvegarde*/ if(isaggin()){ for(int i=0; i<4;i++); for(int j=0;j<4;j++); box_shape[i][j]=temp_piece[i][j]; size_w=tmp_size_w; //N'oubliez pas que size doit retourner à la taille d'origine size_h=tmp_size_h; } /*Si la rotation est réussie, affichez-la sur l'écran*/ else{ for(int i=0; i<4;i++); for(int j=0;j<4;j++} if(temp_piece[i][j]==1} mvwaddch(game_win,head_y+i,head_x+j,' '); //Se déplacer à un certain coordinate dans la fenêtre game_win pour imprimer un caractère wrefresh(game_win); } } for(int i=0; i<size_h;i++); for(int j=0;j<size_w;j++} if(this->box_shape[i][j]==1} mvwaddch(game_win,head_y+i,head_x+j,'#'); wrefresh(game_win); } } } }
2.5 Fonction de déplacement
Si le joueur n'a pas appuyé sur aucune touche, le carré doit tomber lentement, donc nous ne pouvons pas être bloqués sur l'entrée getch() en attendant l'entrée de la touche, ici select() est utilisé pour annuler le blocage.
/* Voici une partie de ce programme, pour plus d'informations, veuillez consulter le code source */ struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec= 500000; if (select(1, &set, NULL, NULL, &timeout) == 0)
timeout est le temps maximum d'attente pour la touche, ici il est réglé 500000us, au-delà de ce temps, l'attente de l'entrée getch() n'est plus attendue et l'étape suivante est directement effectuée.
Si une touche est détectée dans le temps d'attente, l'expression if suivante est vraie, on obtient la valeur de la clé d'entrée, et des opérations telles que déplacement vers la gauche, la droite, le bas, ou rotation sont effectuées en fonction de la valeur de la clé.
if (FD_ISSET(0, &set))
while ((key = getch()) === -1) ;
Les fonctions de traitement des déplacements vers la gauche, la droite et le bas sont similaires, ici, ne prenons que la fonction de déplacement vers le bas comme exemple
/* Voici une partie de ce programme, pour plus d'informations, veuillez consulter le code source */ /* Si le raccourci est ↓ */ if(key==KEY_DOWN){ head_y++; //Coordonnées y du cube+1 if(isaggin()){ //Si il y a une collision ou une sortie des limites, annuler ce déplacement head_y--; /*Puisque c'est arrêté, mettez le box correspondant sur la carte en tant que box occupé, utilisez1Représente, 0 signifie non occupé for(int i=0;i<size_h;i++); for(int j=0;j<size_w;j++); if(box_shape[i][j]==1); box_map[head_y+i][head_x+j]=1; score_next(); //Afficher le score et l'indication du cube suivant } /*Si il peut descendre, alors annuler l'affichage du cube actuel, descendre une ligne pour l'affichage, ici, notez que la boucle for doit commencer du bas vers le haut else{ for(int i=size_h-1; i>=0;i--); for(int j=0;j<size_w;j++} if(this->box_shape[i][j]==1} mvwaddch(game_win,head_y-1+i,head_x+j,' '); mvwaddch(game_win,head_y+i,head_x+j,'#'); } } wrefresh(game_win); }
2.6 Fonction répétée
La fonction à juger après chaque déplacement ou rotation, si la fonction retourne true, il ne peut pas agir, si elle retourne false, elle peut passer à l'étape suivante.
bool Piece::isaggin(){ for(int i=0;i<size_h;i++); for(int j=0;j<size_w;j++} if(box_shape[i][j]==1} if(head_y+i > game_win_height-2); //Sortie du bas return true; if(head_x+j > game_win_width-2 || head_x+i-1<0) //Sortie des limites latérales return true; if(box_map[head_y+i][head_x+j]==1); //Coincidence avec les boxes occupés return true; } } return false; }
2.7 Fonction de couche pleine
La dernière fonction très importante est de supprimer les lignes pleines des cubes, il faut toujours faire le jugement après que chaque cube se déplace vers le bas et s'arrête.
void Piece::judge(){ int i,j; int line=0; //Utilisé pour enregistrer le nombre de lignes pleines bool full; for(i=1;i<game_win_height-1;i++} //Enlevant les bords full=true; for(j=1;j<game_win_width-1;j++} if(box_map[i][j]==0) //Il existe des boxes non occupés full=false; //Indique que la couche n'est pas pleine } if(full){ //Si la couche est pleine line++; //Ligne pleine+1 score+=50; //Ajouter des points~ for(j=1;j<game_win_width-1;j++); box_map[i][j]=0; //Vider ce niveau (marqué comme non utilisé) } } /*Après avoir fait ces jugements, regardez la valeur de line. Si elle n'est pas 0, cela signifie qu'un niveau est complet et doit être supprimé*/ if(line!=0){ for(i=game_win_height-2;i>=2;i--} int s=i; if(exsqr(i)==0){ while(s>1 && exsqr(--s)==0); //Recherche de la ligne où se trouve le carré, et le déplace vers le bas for(j=1;j<game_win_width-1;j++} box_map[i][j]=box_map[s][j]; //Déplacer le niveau supérieur vers le bas box_map[s][j]=0; //Vider le niveau supérieur } } } /*Après avoir vidé et déplacé les marqueurs, il faut actualiser l'écran et imprimer à nouveau game_win*/ for(int i=1;i<game_win_height-1;i++); for(int j=1;j<game_win_width-1;j++} if(box_map[i][j]==1} mvwaddch(game_win,i,j,'#'); wrefresh(game_win); } else{ mvwaddch(game_win,i,j,' '); wrefresh(game_win); } } } }
Troisième partie : Résumé de l'expérience
La présentation des quelques fonctions clés est terminée ici. Comprenez les fonctionnalités de ces fonctions et les implémentez, puis complétez d'autres fonctions et la fonction main en référence au code source pour pouvoir exécuter. Bien sûr, il y a plusieurs méthodes d'implémentation pour le Tetris, et les idées et méthodes de chaque personne peuvent être différentes. Peut-être que votre Tetris sera plus simple et plus fluide ! Profitez-en ! :)
Déclaration : Le contenu de cet article est issu du réseau, propriété des auteurs respectifs, contribué et téléchargé par les utilisateurs d'Internet de manière volontaire. Ce site ne détient pas de propriété, n'a pas été édité par l'homme, et n'assume aucune responsabilité juridique. Si vous trouvez du contenu susceptible de violer les droits d'auteur, veuillez envoyer un e-mail à : notice#oldtoolbag.com (veuillez remplacer # par @ lors de l'envoi d'un e-mail pour signaler une violation, et fournir des preuves pertinentes. Une fois vérifié, ce site supprimera immédiatement le contenu suspect de violation de droits d'auteur.)