To use the C language to implement Tetris, you must first solve the following problems:
1. How to draw a graphical interface using C language
EasyX graphics library (http://www.easyx.cn) is TC graphics library porting under VC.
Include library # include
Initialize the graphic window first
Initgraph (WINDOW_WIDTH, WINDOW_HIGH); WINDOW_WIDTH indicates the bandwidth of the window, and WINDOW_HIGH indicates the height of the window.
Clear a drawing device
Cleardevice ();
Set paint color
Setcolor (RED );
Set line style
Setlinestyle (PS_SOLID, NULL, 0 );
Draw a rectangle
Rectangle
There are also functions such as draw lines and display text. You can refer to the help documentation.
Note: Because we use the EasyX graphics library, the source file suffix must be. cpp, but the content is in the C syntax.
2. How to store and express the shape of the Russian square
In a computer, how does one set a string of 01 numbers to represent Tetris?
1. We can use numbers. Different numbers represent different Russian squares. According to the numbers, we can write the methods of different squares in the code.
There must be 19 types of corresponding code to describe the square. In addition, the scalability is poor. If a new square is designed in the future, a large amount of source code needs to be changed.
2. We naturally think that it can be expressed in the form of a modulo dot matrix, that is, to set an array of four rows and four columns. If the element is set to 1, it indicates that the position is small.
The element 0 indicates that there is no small square at this position. The entire 4*4 array forms the shape of the Russian square.
1000
1000
1100
0000
This method is quite reliable, but we can also optimize it: instead of 4*4 arrays, we use 16 bit bits to represent this dot matrix. This makes it easy to store, so we use the low 16 bits of the unsigned int to represent the dot matrix of the square.
We can use a mask and a bit representing the Russian square to identify and draw blocks on the screen.
For details, see the DrawRock function in GUI. cpp.
// One-bit scan a low 2 byte dot matrix consisting of unsigned int // 16 digits (which represents the 4*4 square shape) mask = (unsigned int) 1 <15; for (I = 1; I <= 16; I ++) {// if (rockArray [rockIndex]. rockShapeBits & mask )! = 0) {// draw this square rectangle (rockX + 2, rockY + 2, rockX + ROCK_SQUARE_WIDTH-2, rockY + ROCK_SQUARE_WIDTH-2) on the screen );} // wrap each 4 times to continue painting in the next line I % 4 = 0? (RockY + = ROCK_SQUARE_WIDTH, rockX = currentLocatePtr-> left): rockX + = ROCK_SQUARE_WIDTH; mask >>=1 ;}
We have stored the digits of the Russian square dot matrix in rockArray. We can convert the modulo dot matrix of the 19 squares into hexadecimal notation in advance, and then assign values during the initialization of the rockArray array.
However, this is a little effort-free, and the scalability is not very good. If you add new block types to the future design, you need to change the values in the array rockArray.
We can considerStored in the configuration fileRead files during program initialization, convert these lattice variables into unsigned int variables and store them in rockArray.
In this way, you only need to add a new dot matrix to the configuration file.
@###
@###
@@##
#### (To make it more eye-catching, we use @ to represent 1 and # To represent 0)
3. How to make the image work
If no buttons are displayed, the blocks are automatically dropped.
How to achieve automatic fall? Use the DrawRock function to draw a square on the screen at a certain position, and then erase it (that is, use the background color to re-paint the square at the original position ), finally, use the DrawRock function to draw the Russian block on the screen at the next position of the fall. In this loop, use a timer interval to control the falling speed.
Similarly, the same is true for pressing the left and right buttons on the screen. However, when you press the keyboard, You can recalculate the position of the square.
So how can I flip the square when I press the arrow key?
In the configuration file, we put the clockwise flip form of the square together:
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
Each time we press the arrow key, we can change the shape of the square. If you press the upper key all the time, the shape should roll cyclically.
We thought of the data structure of the circular linked list to achieve this effect.
However, if we concatenate various forms of these blocks into a circular linked list, it is difficult for us to generate blocks randomly each time we regenerate the blocks.
So we still need to use Arrays for storage, but we need to have the function of circular linked list, so we thoughtStatic cyclic linked list.
We use struct as an element of a square in rockArray.
Typedef struct ROCK
{// Used to represent the shape of the Square (each byte is 8 bits, each 4 bits represent a row in the square)
Unsigned int rockShapeBits;
Int nextRockIndex; // The subscript of the next square in the array.
} RockType;
In this way, when we press the up arrow key, change the rockIndex in the input function DrawRock to the nextRockIndex in the current block structure.
For details, see the ProccessUserHit function in play. cpp.
4. How to determine when a square is stopped and when the full row is scored
The square keeps falling, and finally it will stop. We need to set a boundary to constrain the moving range of the square. We divide the current game interface into squares in the Russian square, and use a two-dimensional array g_gameBoard to represent the status of these squares. 1 indicates that there are squares at this position, 0 indicates that this location is null.
When we calculate the two-dimensional array based on the size of the interface and the size of the square, we will set a circle of "Walls", that is, adding two more rows and two columns, and initialize their values to 1.
When the square is about to fall or move left and right, check whether the position to be dropped is empty before the prerequisite. If it is not empty, stop falling, set the square occupied by the current Russian square to 1.
For details, see the moveAbled function in play. cpp.
Determine full rows:
Check g_gameBoard from the last row. If one row is set to 1, it indicates that the row is full, this row is wiped out, and all rows above this row are moved down to one unit.
For details, see the ProcessFullRow function in play. cpp.
5. Other details:
How to quickly fall
For details, see the FastFall function in play. cpp.
How to pause
For details, see the ProccessUserHit function in play. cpp.
The main logic of this game program is the PlayGame function in play. cpp.
Click here for source code