Someone told me that Tetris was a “hello world” of game programming. I whole heartedly disagree. Tetris may not be an awfully complex game, but it sure as hell is not trivial. The whole concept of a “hello world” is to show the simplest trivial example of functional code that actually does something. But if you think about it, Tetris is not all that simple. So I decided to actually implement the game to show that if you really sit down and try to put it together it is slightly more than just a hello world.
Now, I could just sit down and hack a working prototype relatively quickly but let’s do this the right way. Lets design it, rather than hack it.
Good place to start is to put the spec of the game down on paper. So, let’s just list everything we know about the game:
- the playing field is a grid of the size 10×20, 10×24 or 10×16
- all tetris pieces are composed out of exactly 4 blocks
- the pieces come in 7 shapes: J, L, T, Z, S, I and O
- each piece has an orientation and color
- pieces start at the top in the middle of the grid, and slowly fall downwards
- the speed at which the pieces fall increases with each level
- player can move the pieces left and right or rotate them (change their orientation)
- when a piece touches the bottom of the grid or top of another piece it becomes locked down
- there is a slight delay before the lock-down that allows the player to slide the piece into place
- if a full row on the grid is filled it will clear and add to the players score
- the original Nintendo formula for computing score is m(n + 1) where n is level, and m takes the value of 40, 100, 300, 1200 depending on the number of lines that were cleared simultaneously (40 is one line, 1200 is 4 lines)
- when a line clears, all the blocks above move down
- requirements for advancing to the next level depends on a game, but most start with around 40 lines, and the number gets progressively smaller to become 1 level per line around level 20-30
- some games implement gravity that makes blocks that do not rest on other blocs slide down causing chain reactions
- most games display the next piece next to the grid
- most games allow player to instantly drop the block down either via hard drop or soft drop
- some games implement a wall kick that allows for rotating pieces backed up against the wall
The 17 points above roughly describe the game and can be used as an initial specification. Remember, we are building a game that already exists in many different version, so we want to create something that is instantly recognizable as Tetris, but we do not necessarily need to include all the fancy features that were added to it over the years.
As they taught you in your software engineering class, pay attention to the nouns. They are your potential classes. Right now I see several really good candidates: Block, Grid and Piece. In fact, we could possibly define classes for each specific piece like LShapedPiece, JShapedPiece and etc… They would all be subclasses of Piece and would define the shape, color and orientation. Each of these classes would also implement rules on how the piece could be rotated. This way Grid class would only need to interact with a Piece class.
I actually can see a nice factory pattern forming here. Grid will call a Piece factory which will randomly generate one of the subclasses, and then return it as Piece. This may or may not be practical, but it seems like a good idea at the moment.
Also, the spec is just a rough sketch of the game. If we want to implement it, we must answer several questions and make some important design choices. For example, how big do we want the grid? Do we want to allow the player to rotate pieces clockwise and counter-clockwise or just in one direction (the later choice means you only need a single rotate button rather than two). Do we want to have hard drops or soft drops? Do we implement wall kicks or leave them out? We also need to pick several variables such as lock delay, the speed at which the pieces drop. We must decide if we want pieces to crawl (move one pixel at a time with specific velocity) or skip (move full block length down every n seconds).
We have a pretty good scoring formula, but just a very rough guideline on level advancement. That will need to change. Oh, and there is also that pesky matter of collision detection – somehow we will need to decide how do we detect that piece has hit a wall, or a locking element like floor or another piece.
We also need to pick platform and a language at some point, but that is not all that important at this point. Tetris can be written in any language, and while some might be better suited for this task than others, it ultimately won’t matter as long as we can use some graphic display libs and don’t have to re-implement a whole 2d display framework.
I’m going to address all these questions Part 2, and start drawing up some UML. I also want to look at actual game piece design – like sprites, and internal representations of a piece and a grid. I already have certain design in my head, but any suggestions are welcome. I also have a very specific language and framework that I’d like to use, but I’m not really designing with that language in mind so I’m not going to tell you yet. Good design should work in any OO language – and once we pick one, we can do necessary adjustments if needed.
Still, I’d like to see what language you guy would use for this. Let me know in the comments. If you suggest a good one, I might even change my mind. :)
[tags]games, game design, gaming, tetris, tetris clone, design, software engineering, factory pattern[/tags]