English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
First, experimental introduction
1.1 Experimental content
In this section of the experiment, we will implement the design of the main functions of Tetris, complete the basic functions, and run it.
1.2 Experimental knowledge points
Window drawing
Design of the block class
Rotation algorithm
Move, eliminate functions
1.3 Experimental environment
xface terminal
g++ Compiler
ncurses library
1.4 Compile the program
The compilation command must include -l Options to introduce the ncurses library:
g++ main.c -l ncurses
1.5 Run the program
./a.out
1.6 Running results
Second, experimental steps
2.1 Header files
Firstly, include header files and define a swap function and a random number function, which will be used later (the swap function is used to rotate the blocks, and the random number is used to set the shape of the blocks)
#include <iostream> #include <sys/time.h> #include <sys/types.h> #include <stdlib.h> #include <ncurses.h> #include <unistd.h> /* Swap a and b */ void swap(int &a, int &b){ int t=a; a = b; b = t; } /* Get a random integer in the (min, max) interval int getrand(int min, int max) { return(min+rand()%(max-min+1)); }
2.2 Define class
Since the program content is relatively simple, only one Piece class is defined here
class Piece { public: int score; //Score int shape; //Represents the shape of the current block int next_shape; //Represents the shape of the next block int head_x; //Position of the first box of the current block, marked position int head_y; int size_h; //Size of the current block int size_w; int next_size_h; //Size of the next block int next_size_w; int box_shape[4][4]; //Current block shape array 4x4 int next_box_shape[4][4]; //Next block shape array 4x4 int box_map[30][45]; //Used to mark each box in the game frame bool game_over; //Game over flag public: void initial(); //Initialization function void set_shape(int &cshape, int box_shape[][4], int &size_w, int & size_h); //Set block shape void score_next(); //Display the shape of the next block and the score void judge(); //Judge whether the layer is full void move(); //Move function, controlled by ← → ↓ void rotate(); //Rotation function bool isaggin(); //Judge whether the next move will go out of bounds or overlap bool exsqr(int row); //Judge whether the current row is empty };
2.3 Set block shape
Here, the case statement defines7Set the shape of the block, and call it before each new block falls to set its shape and initial position
void Piece::set_shape(int &cshape, int shape[][4], int &size_w, int &size_h) { /*First, use the4x4Array initialization to 0*/ int i,j; for(i=0;i<4;i++); for(j=0;j<4;j++); shape[i][j]=0; /*Set7Set the initial shape and set their size*/ 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; } //After setting the shape, initialize the starting position of the block head_x=game_win_width/2; head_y=1; //If it overlaps as soon as it is initialized, the game is over~ if(isaggin()) /* GAME OVER ! */ game_over=true; }
2.4 Rotation function
Here is a relatively simple algorithm used to rotate the block, similar to the rotation of a matrix. First, the shape array is symmetrized diagonally, and then it is symmetrized horizontally and vertically to complete the rotation. It is necessary to judge whether the block goes out of bounds or overlaps after rotation. If so, cancel this rotation.
void Piece::rotate() { int temp[4][4]= {0}; //Temporary variables int temp_piece[4][4]= {0}; //Backup array 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]; //Backup the current block, if the rotation fails, return to the current shape for(i=0;i<4;i++); for(j=0;j<4;j++); temp[j][i]=box_shape[i][j]; //Diagonal symmetry 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]; //Symmetry along the vertical and horizontal axes /*If the block overlaps after rotation, return to the backup array shape*/ 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; //Remember to change the size back to the original size size_h=tmp_size_h; } /*If the rotation is successful, then display it on the screen*/ 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,' '); //Move to a coordinate in the game_win window to print a character 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 Move function
If the player does not press any keys, the block needs to fall slowly, so we cannot block on getch() waiting for key input. Here, select() is used to cancel the blocking.
/* This is just a part of the program, for the specific implementation, please refer to the source code */ struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec= 500000; if (select(1, &set, NULL, NULL, &timeout) == 0)
timeout is the maximum time we can wait for a key press, and it is set to 500000us, if this time is exceeded, we no longer wait for input from getch() and proceed to the next step directly.
If a key press is detected within the timeout period, the following if statement is true, obtaining the input key value, and performing operations such as moving left, right, down, and rotating based on different key values.
if (FD_ISSET(0, &set))
while ((key = getch()) === -1) ;
The handling methods of the functions for moving left, right, and down are basically the same, here only the function for moving down is explained
/* This is just a part of the program, for the specific implementation, please refer to the source code */ /* If the input key is ↓ */ if(key==KEY_DOWN){ head_y++; //The y-coordinate of the block+1 if(isaggin()){ //If it overlaps or goes out of bounds, cancel this move head_y--; /*Since it has stopped, set the corresponding box on the map to occupied, using1Indicates, 0 means not occupied 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 prompt the next block } /*If it can move down, then cancel the current block's display, move down one row for display, here pay attention to 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 Repeat function
This is a function to be judged after each move or rotation, if the function returns true, then it cannot act, and if it returns false, then 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); //Below the boundary return true; if(head_x+j > game_win_width-2 || head_x+i-1<0) //Left and right out of bounds return true; if(box_map[head_y+i][head_x+j]==1); //It overlaps with the occupied box return true; } } return false; }
2.7 Layer full function
The last very important function is to eliminate the rows that are full of blocks, and it 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 rows that are full in the layer bool full; for(i=1;i<game_win_height-1;i++} //Excluding the boundary 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 indicates that this layer is not full } if(full){ //If this layer is full line++; //row is full+1 score+=50; //Add points~ for(j=1;j<game_win_width-1;j++); box_map[i][j]=0; //Clear the layer (mark as unoccupied) } } /*After the above judgment, look at the value of line. If it is not 0, it means that a layer is full and needs to be eliminated*/ 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); //Find the row where the block exists and move it down for(j=1;j<game_win_width-1;j++} box_map[i][j]=box_map[s][j]; //Upper move down box_map[s][j]=0; //Upper clear } } } /*After clearing and moving the marks, the screen needs to be refreshed and re-print 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); } } } }
3. Experimental Summary
The introduction of several key functions is completed here. Understand the functions of these functions and implement them, and then refer to the source code to complete other functions and the main function to run! Of course, there are many ways to implement Tetris, and everyone's ideas and methods may be different. Perhaps you can write a more concise and smooth Tetris! Enjoy it! :)
Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (Please replace # with @ when sending an email to report abuse, and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.)