English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Primo, introduzione all'esperimento
1.1 Contenuto dell'esperimento
In questa sezione dell'esperimento realizzeremo la progettazione delle funzioni principali del Tetris, completiamo le funzionalità di base e eseguiamo.
1.2 Conoscenze sperimentali
Disegno della finestra
Progettazione della classe quadrato
Algoritmo di rotazione
Funzione di spostamento e rimozione
1.3 Ambiente sperimentale
Terminale xface
Compilatore g++
Libreria ncurses
1.4 Compilare il programma
L'ordine di compilazione deve includere l'opzione -l per introdurre la libreria ncurses:
g++ main.c -l ncurses
1.5 Eseguire il programma
./a.out
1.6 Risultato dell'esecuzione
Secondo, passi sperimentali
2.1 File di intestazione
Prima includere i file di intestazione e definire una funzione di scambio e una funzione casuale, utilizzate in seguito (la funzione di scambio viene utilizzata per ruotare i quadrati, la funzione casuale viene utilizzata per impostare la forma dei quadrati)
#include <iostream> #include <sys/time.h> #include <sys/types.h> #include <stdlib.h> #include <ncurses.h> #include <unistd.h> /* Scambiare a e b */ void swap(int &a, int &b){ int t=a; a = b; b = t; } /* Ottenere un numero intero casuale nell'intervallo (min,max) */ int getrand(int min, int max)} { return(min+rand()%(max-min+1)); }
2.2 Definisci la classe
Poiché il contenuto del programma è relativamente semplice, qui viene definita solo una classe Piece
class Piece { public: int score; //Punteggio int shape; //Rappresenta la forma del blocco corrente int next_shape; //Rappresenta la forma del prossimo blocco int head_x; //Posizione del primo box del blocco corrente, etichetta di posizione int head_y; int size_h; //Dimensioni del blocco corrente int size_w; int next_size_h; //Dimensioni del prossimo blocco int next_size_w; int box_shape[4][4]; //Array 4x4 per la forma del blocco corrente int next_box_shape[4][4]; //Array 4x4 per la forma del prossimo blocco int box_map[30][45]; //Usato per etichettare ogni box all'interno della scatola di gioco bool game_over; //Segnale di fine gioco public: void initial(); //Funzione di inizializzazione void set_shape(int &cshape, int box_shape[][4],int &size_w, int & size_h); //Imposta la forma del blocco void score_next(); //Mostra la forma e il punteggio del prossimo blocco void judge(); //Determina se il livello è pieno void move(); //Funzione di movimento controllata con ← → ↓ void rotate(); //Funzione di rotazione bool isaggin(); //Determina se il prossimo movimento andrà oltre i limiti o si sovrapporrà bool exsqr(int row); //Determina se la riga corrente è vuota };
2.3 Imposta la forma del blocco
Qui viene definita tramite la语句case 7 forme diverse di blocchi, che devono essere chiamate prima di ogni nuova caduta di blocco per impostare correttamente la forma e la posizione iniziale
void Piece::set_shape(int &cshape, int shape[][4],int &size_w,int &size_h) { /*Inizializza l'array 4x4 utilizzato per rappresentare con 0*/ int i,j; for(i=0;i<4;i++) for(j=0;j<4;j++) shape[i][j]=0; /*Imposta 7 forme iniziali e imposta le loro dimensioni*/ 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; } // Dopo aver impostato la forma, inizializzare la posizione iniziale del pezzo head_x=game_win_width/2; head_y=1; // Se si inizializza e si sovrappone immediatamente, la partita è finita~ if(isaggin()) /* GAME OVER ! */ game_over=true; }
2.4 Funzione di rotazione
Ecco un algoritmo semplice per ruotare il pezzo, simile alla rotazione di una matrice, prima si verifica la simmetria diagonale della matrice shape, poi la simmetria orizzontale, completando così la rotazione. È necessario verificare se il pezzo esce dai limiti o si sovrappone dopo la rotazione. Se lo fa, annulla la rotazione. Attenzione!
void Piece::rotate() { int temp[4][4]={0}; // Variabile temporanea int temp_piece[4][4]={0}; // Array di backup 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]; // Salva la forma attuale del pezzo, se la rotazione fallisce tornare alla forma attuale for(i=0;i<4;i++) for(j=0;j<4;j++) temp[j][i]=box_shape[i][j]; // Simmetria 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]; // Simmetria orizzontale /* Se la rotazione successiva causasse una sovrapposizione, tornare alla forma di backup dell'array */ 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; // Ricorda di tornare la size all'originale size_h=tmp_size_h; } /* Se la rotazione è riuscita, mostrala sullo schermo */ 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,' '); // Muoversi al punto di coordinate specifiche nel finestra game_win e stampare il carattere 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 Funzione di movimento
Se il giocatore non preme alcun tasto, la scatola deve cadere lentamente, quindi non possiamo bloccarci in getch() aspettando l'input del tasto, qui viene utilizzato select() per annullare il blocco.
/* Qui è stato estratto solo un parte del programma, per l'implementazione dettagliata si prega di consultare il codice sorgente */ struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec= 500000; if (select(1, &set, NULL, NULL, &timeout) == 0)
timeout è il tempo massimo di attesa per il tasto, qui è impostato a 500000us, se supera questo tempo non si aspetta più l'input di getch(), si procede direttamente al passo successivo.
Se viene rilevato un tasto entro il tempo di timeout, la seguente istruzione if è vera, si ottiene il valore di input key, attraverso la valutazione di diversi valori di key si eseguono operazioni come muoversi a sinistra, destra, in basso, ruotare ecc.
if (FD_ISSET(0, &set))
while ((key = getch()) == -1) ;
Il modo di gestione delle funzioni per muoversi a sinistra, destra e in basso è基本上相同,qui solo si spiega la funzione per muoversi in basso
/* Qui è stato estratto solo un parte del programma, per l'implementazione dettagliata si prega di consultare il codice sorgente */ /* Se il tasto premuto è ↓ */ if(key==KEY_DOWN){ head_y++; // Incrementa la coordinata y del blocco if(isaggin()){ // Se si sovrappone o esce dai limiti, annulla questa movimentazione head_y--; /* Se è stato fermato, allora impostare la box corrispondente sulla mappa come occupata, utilizzando 1 per rappresentare e 0 per rappresentare che non è occupata */ 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(); //Display the score and hint the next block } /*If it can move down, then cancel the display of the current block, move down one row for display, and pay attention to the line of the for loop from bottom to top 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 Repeated function
The function to be judged after each move or rotation. If the function returns true, it cannot move, and if it returns false, the next step can be taken.
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) //Out of bounds below return true; if(head_x+j > game_win_width-2 || head_x+i-1<0) //Out of bounds on the left and right return true; if(box_map[head_y+i][head_x+j]==1) //Overlaps with an occupied box return true; } } return false; }
2.7 Function of layer full
The last very important function is to clear the rows that are full of blocks. This needs to be judged every time a block stops moving downward.
void Piece::judge(){ int i,j; int line=0; //Used to record the number of full layers bool full; for(i=1;i<game_win_height-1;i++){ //Exclude boundaries full=true; for(j=1;j<game_win_width-1;j++){ if(box_map[i][j]==0) //There is an unoccupied box full=false; //It means that this layer is not full } if(full){ //If the layer is full line++; //Increase the number of full rows by 1 score+=50; //Add points~ for(j=1;j<game_win_width-1;j++) box_map[i][j]=0; //Clear this layer (mark as unoccupied) } } /*After the above judgment, check the value of line. If it is not 0, it means that a layer is full and needs to be cleared*/ 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); // Trova la riga esistente del blocco e muovila verso il basso for(j=1;j<game_win_width-1;j++){ box_map[i][j]=box_map[s][j]; // Spostamento del livello superiore box_map[s][j]=0; // Pulizia del livello superiore } } } /*Dopo aver pulito e spostato i segni, è necessario aggiornare lo schermo, ri stampare 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); } } } }
Terza sezione: Sommario sperimentale
Con questo, la presentazione di alcune funzioni chiave è completa. Comprendere le funzioni di queste funzioni e realizzarle, quindi consultare il codice sorgente per completare altre funzioni e la funzione main può essere eseguita! Naturalmente, ci sono molti modi per implementare il tetris russo, e il pensiero e i metodi di ciascuno possono essere diversi. Forse il tuo tetris russo sarà più semplice e più fluido! Enjoy it!:)
Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, è di proprietà del rispettivo autore, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, il sito web non detiene il diritto di proprietà, non è stato editato manualmente e non assume responsabilità per le relative responsabilità legali. Se trovi contenuti sospetti di copyright, ti preghiamo di inviare una e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare, fornendo prove pertinenti. Una volta verificata, il sito web rimuoverà immediatamente i contenuti sospetti di copyright.