The Tetris : A Simple Version

Motivation


Tetris is one of the iconic games that everybody has played at some point or the other. For some it has even become an addiction, with all the different versions of the game. 
Even though being so popular and played-by-all, it is one of the simplest games out there, if we consider the basic mechanics. Of course UI is something that is really hard to get right for a beginner, so I will not be discussing it right now. 

So, why build a tetris? I did it because I was feeling bored and had nothing to do for 5-6 hrs. It took me literally that much time to build it, and I am sure that experienced programmers will take even less time. If I would have built it now, it would have taken even lesser time, for I made that in 2015, a long time ago.

Structure

So the first thing that we have to notice is that tetris is basically a grid based game. You could make the blocks fall in a continuous manner or smooth manner, but when it finally falls, it is in fixed places of the grid squares.

Now, what better way to represent each of the small blocks than a class Block .  It will only store the color of that block, nothing else. 

Next, to make the various shapes using the block, we have the Group class. It is basically a 3 by 3 array that stores the block that is to be present in a particular shape.
It also has some other important methods like shiftUp(), shiftDown(), shiftRight(), shiftLeft(), rotate(), getBlockStatus(), getBlock() etc.

The last three methods are important.The first four methods just change the relative position of the shape to the grid.

The rotate method basically rotates the array clockwise (or anticlockwise, I don't remember the code). Now, to make the shape rotate in the different direction is just calling the rotate() method three times.
The method getBlockStatus() returns a boolean 2D array denoting whether there is a Block in those indices. The actual Block can be retrieved by the method getBlock(int,int).

Now, to creating the shapes. Here, what I did was just make a switch case statement and random number to determine what kind of block was to be formed, in the constructor of the  Group  itself. In each of the array indices, I then filled up with a Block if required in that shape, or null.

Example:

 switch(r){
            case 0:
            blockConfig[0][0]=null;
            blockConfig[0][1]=new Block(Color.GREEN);
            blockConfig[0][2]=null;
            blockConfig[1][0]=new Block(Color.GREEN);
            blockConfig[1][1]=new Block(Color.GREEN);
            blockConfig[1][2]=new Block(Color.GREEN);
            blockConfig[2][0]=null;
            blockConfig[2][1]=null;
            blockConfig[2][2]=null;
            break;
.
.
.


Input and Game Loop


There will only be one class for taking input, which I ever do innovatively named InputHandler. For the simplest implementation, just extends  the KeyAdapter class and override the keyPressed() method. From there, based on the key input, call the different methods of the GameEngine  class, which I will talk about in the next blog. Sure, this will not be thread safe as the keyPressed() method will not be called by the main thread.
In a more robust system, I would probably make Actions pertaining to each valid keypress and then make the GameEngine query the InputHandler for any new pending inputs, using features of Java concurrency. But for this game, unless you want to be really professional , so much is not required.

Another thing that I would highly advise is separating the GameLoop from the GameEngine  and make 1 loop call the tick() and render() method of the GameEngine separately. Better OO design. 

That's all for today. I will explain the GameEngine  in the next post.












Comments

Popular posts from this blog

Small-to-Large

Segment Tree Beats - An introduction

Getting prepared for RMO