English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Utilisation de C++Suite à l'implémentation du Tetris

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.)

Vous pourriez aussi aimer