The goal for this step is to select a random falling piece
in a random color, to position it in the top-middle of the board, and paint
it over the board. Note that the "falling piece" will not be falling
after this step. That comes later. For now, it will remain at
the top-middle of the board. Also, for testing purposes, we will add
temporary code that changes the falling piece whenever any key is pressed.
This code will be removed after this step.
Recall that the falling piece is not part of the board, but
painted over the board. It becomes part of the board when it can no
longer fall and we place it on the board, which will not happen until
several steps from now in our design process.
Defining the piece types:
In this design, the falling piece is represented by a 2-dimensional array of
booleans, indicating whether the given cell is or is not painted in this
piece. For example, here is the definition of an S piece:
private static final boolean[][] S_PIECE = {
{ false, true,
true},
{ true,
true, false }
};
This defines a 2-dimensional boolean array with 2 rows and 3 columns.
The "true" values have been highlighted to make it clear that they form an
S
pattern. This is how we know which cells are
part of the falling piece.
Here are all the piece types, with the "true" values highlighted to make the shapes easier to discern (note that they are provided in their standard configurations -- how they should enter the board from the top -- so, for excample, the T piece is upside down):
//Seven "standard" pieces (tetrominoes) private static final boolean[][] I_PIECE = { { true, true, true, true} }; private static final boolean[][] J_PIECE = { { true, false, false }, { true, true, true} }; private static final boolean[][] L_PIECE = { { false, false, true}, { true, true, true} }; private static final boolean[][] O_PIECE = { { true, true}, { true, true} }; private static final boolean[][] S_PIECE = { { false, true, true}, { true, true, false } }; private static final boolean[][] T_PIECE = { { false, true, false }, { true, true, true} }; private static final boolean[][] Z_PIECE = { { true, true, false }, { false, true, true} };
For this design, we need to place all 7 of these piece types
into a single array, tetrisPieces. That will be an array of
2-dimensional arrays, so it is in fact a 3-dimensional array! Here it
is:
private static
boolean[][][] TETRIS_PIECES = {
I_PIECE, J_PIECE, L_PIECE, O_PIECE, S_PIECE, T_PIECE, Z_PIECE
};
We also need to define colors corresponding to each of these
pieces, and place them in an array of the same size, which we do as such:
private static Color[]
TETRIS_PIECE_COLORS = {
Color.red, Color.yellow, Color.magenta, Color.pink,
Color.cyan, Color.green, Color.orange
};
Writing newFallingPiece:
The newFallingPiece method is responsible for randomly choosing a new piece,
setting its color, and positioning it in the middle of the top row.
The first step is to randomly choose an index from the tetrisPieces array
(using an instance of the java.util.Random class that is stored in a static
variable), then to set the instance
variables holding the fallingPiece and the fallingPieceColor to the
respective elements from the arrays of pieces and colors.
Next, we set the top row of the falling piece (fallingPieceRow) to the
top row of the board (that is, to zero). And then we set the left column of the new falling piece
(fallingPieceCol). As we want
the piece to emerge at the top-middle of the board, we might set this to the
center, or this.cols/2. However, this will place the new falling piece
a bit off to the right, since its full width would extend beyond the middle.
To compensate for this fact, we subtract half the width of the falling
piece, or this.fallingPieceCols/2, from the middle of the board
Painting the falling piece:
After the main paint method calls paintBoard, it should then call
paintFallingPiece, so it is painted over the board.
To paint the falling piece (in the paintFallingPiece method), we iterate over each cell in the fallingPiece,
and if the value of that cell is "true", then we should paint it
reusing the same paintCell that paintBoard uses, but in the color of the fallingPiece (rather than the color stored
in the board for that row and column). However, we have to add the
offset of the left-top row and column (that is, this.fallingPieceRow and
this.fallingPieceCol) so that the fallingPiece is properly positioned on the
board.
Initial falling piece:
We must add one line to our constructor to select the first falling piece of
the game.
Temporary test code:
As noted above, for testing purposes, we will add temporary code that
changes the falling piece whenever any key is pressed. This code will
be removed after this step. This involves the following simple key
event handler:
public void
keyPressed(char key) {
// for now, for testing purposes, just choose a new falling piece
// whenever ANY key is pressed!
newFallingPiece();
}
David Kosbie |