This code is based on python3.6 and pygame1.9.4.
Tetris is one of the most classic childhood games. I wanted to write a Tetris when I first got into PyGame. But when you think about rotating, docking, erasing, and so on, it seems like it’s really hard, and when you actually write it, it’s only 300 lines of code, so it’s not that hard.
First look at a screenshot of the game, a little ugly, well, I don’t have any art cells, but the main functions are realized, can play.
I have created a small learning circle for Python learning to provide a platform for everyone to discuss learning Python together. Welcome everybody
Python Learning Group: 960410445Discuss video sharing learning together. Python is the future, and it is challenging our analytical abilities and the way we perceive the world, so we need to keep up with the changes, and grow. Mastering Python’s core technology is the real value of mastering it.
shape
The whole interface of Tetris is divided into two parts, one part is the game area on the left, the other part is the display area on the right, showing the score, speed, the style of the next block and so on. Instead of showing screenshots, just look at the image above.
The game area, like the snake, is made up of small squares, so I drew grid lines to make it more intuitive.
square
The next step is to define the cube, which has the following 7 shapes:
Type I
Type O
T
“S”
Z
L
J type
I made several changes here, because the maximum length of the square is long and is 4 squares, so I used 4 × 4 squares to define it. This is also possible, but later found inconvenient.
For intuition, the square is defined as a two-dimensional array, where. Represents empty and 0 represents solid. (The use of. To indicate empty is to make it easier to see, if you use Spaces it will be difficult to see.)
For example, row I is defined on a 4 × 4 square
[‘ 0.. ‘,
‘.0..’,
‘.0..’,
‘.0..’]
and
[‘….’,
‘….’,
‘0000’,
‘….’]
The most difficult thing about squares is that they need to be rotated. For example, type I has both horizontal and vertical shapes. The so-called rotation, on the surface, is to rotate the square 90 degrees clockwise, but in practice, we do not need to actually achieve the “rotation” effect.
In the end, all of these graphics are drawn on the interface, and every time we refresh, everything on the interface will be cleared and redrawn, so the rotation is to draw the current square instead of the previous shape, but the rotated shape.
This I, for example, is defined as a 4 by 4 shape, but it really only needs to be 1 by 4 or 4 by 1, and everything else is empty. It’s not like T, which is not a rectangle, and if you define it by a rectangle, there must be two empty positions. So, does type I really need to be defined as 4 by 4?
The answer is yes. So if you think about it, if you have a 4 by 1 bar, and you rotate it to be a 1 by 4 bar, how do you determine that position? It seems a little difficult. But if it is a 4 × 4 square, we just need to fix the starting coordinates (upper left corner) unchanged, and replace the 4 × 4 area of the vertical bar directly with the 4 × 4 area of the horizontal bar, right? And the position is easy to calculate.
The other thing is, in some cases you can’t rotate it. For example, the i-type vertical bar can not be rotated when it is close to the left and right borders. I remember that, I’m sure. But for other shapes, I am not very sure, I baidu search, find a web version of the Tetris to play, found that can not be. Such as:
It is impossible to rotate against the right border. It would be too boring to try to judge every shape. From the definition of the box, it can be very simple to achieve.
For example, a vertical bar is defined as:
[‘ 0.. ‘,
‘.0..’,
‘.0..’,
‘.0..’]
The bar is edging, so when it’s on the far left, the x-coordinate is negative 1, because the left bar is empty by definition. We just need to decide that the shape defined by the square (including the empty part) can only be rotated if it is completely within the game area.
I said before that it’s bad to define everything as 4 by 4, and that’s why you can’t do that for other shapes like T. So, for shapes such as T, we can define a 3 × 3 format:
[‘. 0. ‘,
‘000’,
‘… ‘]
There is also a case where rotation is impossible, that is, the position after rotation has been occupied by another square. In addition to falling, moving left and right, you have to make this judgment. Since these are consistent, we can use the same method to judge.
Define a game_area variable that holds the current state of the entire game area:
game_area = [[‘.’] * BLOCK_WIDTHfor_inrange(BLOCK_HEIGHT)]
The initial states are all empty, so we can initialize them all with.
In addition, some variables are required to define the state of the currently falling block
Cur_block = non # Current drop block
Cur_pos_x, cur_pos_y = 0, 0 # Coordinates of the current drop block
Squares are defined as a two-dimensional array with empty rows and columns, and this can be done if we walk through the two-dimensional array to determine whether the area in which they are located is already occupied by other squares in the current game area. Let’s consider another case, a vertical bar, the left row is empty, this empty row can be moved out of the game area, how to determine this? Every time you move to the left, check to see if the left row is empty. It’s too much trouble. And the cubes are fixed, so we can define these in advance. The final block is defined as follows:
A square needs to contain two methods: to get a random square and to get a rotated square when rotated
The method of determining whether you can rotate, fall, or move is also easy to implement
dock
The last problem is docking. When a block falls to the bottom or encounters another block, it can no longer fall. I call this “docking,” and there’s a name for it that’s a little easier to say.
The first step is to determine whether it can be docked. Once docked, draw the non-empty points of the current block onto the game_area. In other words, copy the non-empty points of the cur_block into the game_area. And if one row is completely filled, then all rows are eliminated.
So far, the main function of the whole Tetris is completed.
Many of the parameters can be adjusted, such as the definition of the block if the rotation is not comfortable, without changing the code logic.