I know that many people like to play and design platform games, and I did analyze some excellent platform games in Scratch such as New Super Mario Bros. However, in this post, I will analyze a very classic game – Tetris and explain how the author realized it by Scratch.
Frankly, the interface of the game is very common, or even could say “mediocre” (hope the author is not offended). What really amazed me and triggered my interest of analysis was how the author realized the function of Tetris by decomposing the function properly and using well-designed function blocks and algorithms to implement.
The project utilizes many lists to store and update data. Through this project, I believe you could recognize the powerful strengths of lists in organizing data.
If you want to open the project and experience it first, here is the project link: https://scratch.mit.edu/projects/320073171
The project is more complicated than other projects I analyzed before, if not much. Therefore, I will separate the analysis into 3 posts. So let’s start off now!
The Main Code Segment
The above code segment is the only segment driven by Start button. It calls other function blocks directly or indirectly through cascaded function blocks. The project has not used any paralleled programming but still can run very smoothly. I will give my comment on where the project can be improved in parallel programming later in the analysis.
At the initiation stage, the main code segment clears the Tetris area (use”reset grid”) and generates a new falling piece (use “generate new piece”). It then calls “reset key hold frames” function block to clear key press information.
After the initiation, it sets level and piece fall speed, and then begins rendering grid (use “render grid”), identifies key pressed events (left/right/up/down arrow keys and space key), and then updates the falling piece’s shape and position (use “update falling piece”). This process will repeat until the player clicks red button to stop the game or tiles are piled too high to result in game over.
“Reset Grid” Block Definition
In the above “reset grid” block, the game clears all the 22 items of “grid” list. What does it mean? the grid corresponds to the playing area surrounded by the black frame. Starting from the top to bottom, the area is segmented into 22 rows and 10 columns. Please note that the top visible row is row 3, and the bottom row is 22. For each row, there are 10 columns to put those colorful tiles. Tile’s color is represented by a number ranging from 0 to 7.
This “gird” list is very important in the game. Without it, the game could not update the tilt information, remove the filled row or put the falling piece into proper position. Let’s see how this “grid” list plays its role in the following analysis.
“Generate New Piece” Block Definition
This function is used to pick up a color randomly for a new falling piece. It uses a list called “random bag” to store numbers from 1 -7. Each time it picks up an item from “random bag” and assigns the item value to “piece type”, this item is then removed from “random bag”, so next time the game will not pick up the same color.
The advantage of this method is that it ensures every time the new piece will pick up a different color.
Another way is to use “set piece type to random (1 to 7)” directly, without using “random bag” list. It is simpler, but could not ensure that each time, piece type will pick up different color, so it might occur that several same color pieces fall consecutively.
After setting piece type, the function block sets variables “piece x” and “piece y” and calls function block “check if piece is valid” which is used to verify if the falling piece touches other existing pieces. If the new piece touches the existing ones at row 1, it means that existing pieces have reached the top of the area and game is over.
“Check if piece is valid” Block and “get piece coordinates” Block
This function block calls another function block “get piece coordinates”, so I will analyze the two functions together.
The above “check if piece is valid” block is not only used by “generate new piece” block, but also by several other blocks. It calls “get piece coordinates” function block, so here I first explain “get piece coordinates” function.
There is an important list called “piece templates” used by “get piece coordinates” function. The game designs 7 different shapes, which is shown above. If you once played Tetris before, you would know that the falling piece can rotate before dropping down to the bottom. Therefore, there are 4*7 = 28 shapes in piece templates.
So what do those numbers mean in the piece templates? Let me explain to you in the below example.
Structure of “piece tiles x” and “piece tiles y” Lists
x and y input parameters from “get piece coordinate” function is a reference position for the current falling piece in the grid. Remember that there are 22 rows and 10 columns in the white playing area? Assuming x =5, y =8, it means that the falling piece’s reference point has moved to column 5, row 8 (not row 5, column 8) position. Since the reference point only occupies one point in the grid, so how to know the position of the 4 tiles in the falling piece? That is why “piece templates” exists. The numbers in the “piece templates” list represent the offset amount to the input parameters x and y.
We use piece shape 7 as an example. It is an angled rectangle and listed in “piece templates” from item #25 – #28. If rotation is 0, it will refer to item #25; if rotated once, it will refer to item #26, and so on. When using item #25, the 4 tiles’ position information is stored as “01112120”, representing the offset amount from reference point.
After “get piece coordinates” function fills the information to “piece tiles x” and “piece tiles y” list, “check if piece is valid” function will use “piece tiles x” and “piece tiles y” information to verify if the falling tiles overlap with the existing pieces. If “is valid?” variable is true, which means that the falling piece could move to the current position and continue dropping. otherwise, the falling piece might overlap with other existing tiles and have to retrieve one step.
“Reset key hold frames” Block Definition
This function is much simpler. It just initiates all the items of “key hold frames” list. Then where is it used? I will explain in the next post.
Till now, I have analyzed the initiation part of the main code segment. Please note that several function blocks (“generate new piece” and “check if piece is valid”) introduced here will be heavily used in other areas, not just limited to the purpose of initiation.
To say the fact, it is really a bit challenging to explain the project clearly. Hope you are not confused till now. So see you later.