This weekend I felt like playing tetris game. So thought why not make my own game. To share the fun of creating the game, here is how I went about it. Since this would be a long one, I’ll post it in parts.
Note that since I haven’t referred this from any other book or online article etc., this may or may not be the best approach. It is all what came to my mind and I started with it.Feel free to comment about it if you think something could be done in a better way.
You can download the entire source code for this game from here. Feel free to use the source code whatever way you can or want to. I reserve no rights for myself.
If you are just interested in the executable (game) file, download it from here. If the game doesn’t run, it could be possible that .NET framework is not installed on your PC. You can download and install Microsoft .NET framework (version 3.5) from Microsoft’s official download page, if you don’t have it already.
[Warning: As with any other file, scan the downloaded files for viruses/malware. I may not be having the best antivirus in the world ]
There are 7 different types of basic shape in our game. We name them I J L O S T Z for simplicity to match the nearest English alphabet they look like. Since the game has facility to rotate the shapes, this makes them 28 (i.e. 7×4 ) in total. See diagram below:
The image above shows the 7 basic shapes and the other variations of each one of them rotated clockwise.
Notice that all the shapes are made up of 4 cells. Also notice that except for I and O, all others can fit into a 3×3 grid. So we can take the 2×2 cell as the center and rotate the shape clockwise or anti-clockwise. I have marked the center cell with a small hole in the image above. Imagine that you can rotate the block around that fixed hole. I and O shapes are exceptions in the sense that we can’t determine a fixed center cell for them. The O-shape when rotated will remain the same, so we need not worry about it. We designate the 2×2 cell as its center. For the I-shape, we take the 2×2 cell as its center, since the next two rotations are insignificant. This makes the 2×2 cell as an ideal choice for the center for all shapes.
Now observe the I O S and Z shapes. We don’t need all of them. Some of them are duplicates. But still we keep them so that we get even falling blocks. e.g. If we keep just one O-shape, this would be least seen in the game. We don’t want this to happen. So we keep 4 for each type, even if it means duplicates.
Translating the concept into a program
To translate the concept into a program, we create three classes.
- TetrisBoard : The TetrisBoard class represents all the cells in the game. It is a 2 dimensional grid of cells, just like a spreadsheet. You may call it the canvas or playground for the game.
- TetrisCell : A TetrisCell represents each cell of the tetris board. So in effect anything in this game is ultimately made up of TetrisCells.
- TetrisBlock : A TetrisBlock represents a group of cells (TetrisCells) that form a meaningful block for us. Each of the shapes in the above diagram is a block.
The diagram below shows some examples of each of these class objects.
Here’s a quick summary about the capabilities of our classes:
A TetrisCell inherits from a label. Since a label has all what we want for this game, I just used it with a few additional properties I needed. However, a label isn’t designed for graphics and as a result may not be the best choice. (I plan to replace it with some more graphical object in the future. e.g. a RectangleShape etc.)
A TetrisCell knows its location (Row, Column) in the GameBoard. It knows what color it is (HighlightColor) and whether it is shown or hidden (Highlighted). It also knows whether it is empty or occupied (IsEmpty). Finally, it knows how to redraw itself when told to do so (Refresh method).
A TetrisBoard is nothing more than a collection (in fact 2D array) of TetrisCells arranged into rows and columns, with a few additional properties.
A TetrisBoard knows what container (Parent) it resides in, information about each TetrisCell it owns, their size, color and border style. It knows how many Rows and Columns it has.
It has methods to determine whether any of the rows it has is fully occupied or not (IsRowComplete method) and ways to remove any row when told to do so (RemoveRow method). When a row is removed, the rows above it fall down under gravity.
A TetrisBlock represents a group of TetrisCells on the board that forms a meaningful block. This is the heart of our game. Most of the part of the game resides in this class.
A TetrisBlock knows the cells that form the block (Cells property). It knows what shape it is (Shape property) and which TetrisBoard it is attached to (ParentBoard property).
A TetrisBlock has methods to know whether it is possible to move it to another location on the board (CanMove method) and also how to move itself if possible (Move method). It also has way to know whether it can rotate (CanRotate method) and rotate itself if it can (Rotate method). It knows how to paint itself when needed (Refresh and RefreshBackGround methods).
In part 2, we will see how we make use of these 3 classes in our game.