We are now ready to have the falling piece respond to timer
events by dropping one row each time the timer fires.
A naive implementation would respond to timer events by
calling moveFallingPiece(+1,0), just as we do in response to a down-arrow
key press.
Actually, it's not a bad start, but this does point out two
obvious problems. First, the piece is falling too fast. And
second, when it gets to the bottom, it just sits there (until we hit a
non-arrow key to artificially reset the falling piece).
We can solve the first problem simply. One solution
might be to increase the timer interval. That
works, but it is limiting: for example, we may wish to fall faster at
higher levels. A better solution, then, is to only handle, say, every
third timer event. Then, as the player proceeds to higher levels in
our game, we can handle every second event, and eventually we can handle
every timer event. This lets our game speed up over time.
The second problem, again, is that pieces simply stop at the
bottom -- they do not get placed on the board. To remedy this, we
first need to know that it happened! That requires a small change to
some code we have written. We will change moveFallingPiece so that it
is a boolean instead of a void, and it returns true if the move occurred,
and false otherwise. This requires only a small change to our code.
Once we have done this, our timerFired method can test the return value from
moveFallingPiece to determine if the move failed. In that case, we
will use top-down design and call a method (that we are about to write) to
place the falling piece on the board, followed by a call to newFallingPiece,
to start a new piece falling from the top.
Writing placeFallingPiece:
This method is quite similar to paintFallingPiece, only rather than
paint the cells, we load the corresponding positions on the board with the
fallingColor. In this way, the piece is placed on the board.
This works quite well! But now we see another problem:
the game never ends. The pieces pile up to the top, but then they just
keep pouring out. We should fix this!
When should the game end? When we place a falling
piece and it is immediately illegal. We can test for this in
our timerFired method, right after we call newFallingPiece.
But what should we do when the game has ended? Here,
we will simply set the instance variable "isGameOver" to true. Then we
will change our paint method to test this variable and if it is
true simply paint a suitable message. Finally, we will let the user
start a new game at any time by hitting 'r' for 'restart'. Remember
also to disable your timer and key event handlers when the game is over
until the user restarts a new game (though, again, be sure your keyPressed
method continues to look for the 'r' key, even the the game is over, or else
it will be impossible to restart!).
Also at this time we will remove the test code in our keyPressed event
handler that called newFallingPiece in response to a non-arrow key press.
As for resetGame, this should simply set all the colors in the board to emptyColor, set isGameOver to false, and call newFallingPiece. It should be noted that this functionality is largely in the constructor, so in the interests of not duplicating code, we should place all this in resetGame, and then have our constructor call resetGame.
David Kosbie |