Win a copy of Java 9 Modularity: Patterns and Practices for Developing Maintainable Applications this week in the Java 9 forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Tetris Game using Java Swing  RSS feed

 
R Ferreira
Greenhorn
Posts: 14
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I completed the final exercise from chapter 11 in the book "Learning Java through Games by Lubomir Stanchev".

I worked under the assumption that a block will only collide with another block or the edges of the screen if its not hidden, and I used blocks because after the Tetris shape hits the bottom of the screen, or another block, the Tetris(composed by four blocks) explodes(like in AutoCAD explode feature) and every block contained in the Tetris will be saved in an ArrayList that gets constantly iterated in search for a completed row. This was my way of implementing it, using what I've learned so far about OOP.

The main class, that just adds the frame and runs the program.


The Frame class, that adds the panel and sets the size of the window and the playing area.



The Block class. Since a Tetris shape contains four blocks, I created this class, attempting a bottoms-up design. Only thing tricky about this class are the virtual future block methods, in which I return a block with new coordinates in the direction I want to move it(left, right or down), in order to intersect the virtual block with any other block before they overlap each other.


The TetrisShape class, which is the abstract class from which all other shapes will be created. This class works a lot like the Block class, only 10 times more difficult, because it works with a two dimension array of blocks. The same methods as the Block class just iterate the array and call the Block methods with the same name, like, hide(), draw(), move(), etc.. The intersect method iterates all the active blocks in the TetrisShape and checks if any of them intersect with another Block (not another TetrisShape, because the Tetris will be transformed into blocks after the player no longer controls them). I spend a lot of time in this class, because of a shallow copy problem with the virtual future Tetris shapes, I tried to used the cloneable interface but failed, so I tried something easier: iterate the Tetris, looking for all the blocks that are active, and save them into an ArrayList, then, I can change the coordinates of the blocks, moving them in any direction.. Created methods that receive an ArrayList to work around the shallow copy issue. Also, for the rotation of the Tetris, I rotate it, then I save the active blocks in a new ArrayList, and return the original Tetris to its previous rotation. I then use the copy of the future rotation of the Tetris to check for collisions. All Tetris share the same methods, except the ones that display and rotate the shape, so I made those abstract.


The TetrisShapeI class, which was the first I implemented and also the hardest, since its the largest one. Since I'm working with a 4x4 array even when the shape is only 1x4 or 4x1, I had to spend a little time on the method to rotate the shape, in order to prevent the shape from rotating and going out of bounds or colliding with another block.


The TetrisShapeT class


The TetrisShapeO class


The TetrisShapeL class


The TetrisShapeJ class


The TetrisShapeS class


The TetrisShapeZ class


The panel class, where the game loop is and all the methods and variables to make it work.


I invested about 30 hours to get this working, because I got stuck getting the collisions to work properly and the method to delete a line and move all the blocks above.. after the first shape was working, implementing the other 6 took me like 20 minutes. And they all worked well, in fact I could expand the game and add any 4x4 or smaller shape and it will work. If I were to improve this program, I would change the draw method in the Block class and choose a better looking block, maybe add an image and use that instead. Also, the game has no sound, does native Java handle sounds? either way, its out of my league at the moment lol.
 
R Ferreira
Greenhorn
Posts: 14
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A picture of the game
1.jpg
[Thumbnail for 1.jpg]
preview
 
Rob Camick
Ranch Foreman
Posts: 2818
15
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting project. Tetris seems to be an interesting game to try to implement, I also did a basic implementation

Also, the game has no sound, does native Java handle sounds?


Here is a simple example that demonstrates how to play a .wav file:

 
Rob Camick
Ranch Foreman
Posts: 2818
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My implementation is similar to yours. It doesn't implement any game logic or provide increases in speed. It only contain 4 classes

1. TetrisIcon - custom painting of an Icon to represent a single block. It is designed to look like the Tetris block found on the Tetris game in Windows 7.

2. TetrisPiece - contains a 4x4 array indication which cell of the array should be painted. It also support a generic rotation algorithm to rotate any piece

3. TetrisBoard - contains the list of individual TetrisIcons to be painted. Also contains the current TestisPiece that can be rotated, moved left/right or dropped. Is also responsible for removed a row from the board when full

4. Tetris - create the game and add initial TetrisPiece to the TetrisBoard


This forum won' t allow me to post my code here since I use "r" as a variable in some of my looping code and the forums wants me to "speak English".

If you want to take a look at my code you can find it here: http://stackoverflow.com/questions/42517544/adding-additional-shapes-in-a-tetris-project-loop-logic-assistance/42518798#42518798
 
R Ferreira
Greenhorn
Posts: 14
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
oh, so it is a lot like loading an image.. so clip.setFramePosition(0) means replay the sound from the start right? I'll try that sample code in a minute. Thanks.

You are right, your implementation is a lot like mine.. You did a better job at drawing the block though, mine is pretty basic. Also, good idea with the rotation method, I hard coded my rotations, your implementation is far better, It didn't even cross my mind, switching rows for columns..
In your implementation, when a row is completed, it gets deleted, how did you solve the problem of moving all the Tetris icons above that row?  does it do it? move all blocks above?

I see this, yet is not that clear as to what this is doing, it re adds all the columns in the board, only they are displaced one position down? you should try to comment your code more, at least the tricky parts.
 
Rob Camick
Ranch Foreman
Posts: 2818
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You should try to comment your code more, at least the tricky parts.


Yes, I just wrote the code for fun for myself so I wasn't to worried about documentation.

  when a row is completed, it gets deleted, how did you solve the problem of moving all the Tetris icons above that row? 


The first variable of the TetrisBoard class is the "board" variable which a List. Each item in the List represents a row of TetrisPieces.

When you delete a "row" from a List the items below that row move up one position in the List.  (ie. see the for loop above the code you pasted)

So the code you quoted then shows how I add an empty row back to the top of the List so the board always contains the specified number of rows.

So the net effect is the rows below the deleted rows move up and then all the rows move down after the empty rows have been added. Of course repaint() is only invoked once so you only see all the rows in the proper place.
 
R Ferreira
Greenhorn
Posts: 14
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
so your list stores rows of Tetris pieces, while mine stores every individual piece.. so what happens under the hood is, you delete a row in the middle, and all the rows below the row you deleted go up, but then you insert a new row at the top and every row gets pushed down to its proper place, right? so all your code has to do every tick is check if a row is completed, while mine has to determine which piece belongs to which row, and then check if the row is completed. Not that you ever notice any difference in the performance I guess. Its great how there can be so many different paths to program something.
 
R Ferreira
Greenhorn
Posts: 14
1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I remember playing Tetris years ago, on the handheld devices, there was a delay once a row was completed, the completed row flashed a couple of times in another color, and then it was deleted, you could also see the gap the row left for like half a second before all the other rows above would fall down. I was thinking about implementing that behavior, but I don't see how, the timer allows me to pause the game, but since the game loop is already inside the ActionListener, I don't think its possible, right?
 
Rob Camick
Ranch Foreman
Posts: 2818
15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Its great how there can be so many different paths to program something. 


Which is one reason why I spend time answering questions. Always learning new/different ways to do things.

but I don't see how, the timer allows me to pause the game, but since the game loop is already inside the ActionListener, I don't think its possible, right?


If you have a reference to the Timer variable then you should be able to pause it. Somewhere in the game you must speed up the Timer when you move to a new level. So you should also be able to pause it and display fancy graphics before restarting.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!