Tetris for Intro/Intermediate Programmers (Spring 2020 version)
Step 6: Dropping and Placing the fallingPiece on the Board and Handling Game-Over
We are now ready to have the falling piece respond to time events by dropping one row on each call to timerFired. To start, we can have our timerFired function call moveFallingPiece(app, +1, 0), just as we do in response to a down-arrow key press. This is not a bad start, but when it gets to the bottom, it just sits there (until we hit a non-arrow key to artificially reset the falling piece).
To remedy this, we first need to know when the piece stops moving! That requires a small change to some code we have written. We will change moveFallingPiece so that now it returns True if the move occurred, and False if the move failed for any reason (the piece moved off the board, or the piece collided with something on the board). This requires only a small change to our code.
Once we have done this, our timerFired 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 function (that we are about to write) to place the falling piece on the board.
Hint: Remember that we only want to place the piece when timerFired tries to move the piece and fails. We should not place the piece when the user tries to make an illegal move, for example, or else we might get pieces sticking to the side of the board or frozen in odd positions.
Writing the placeFallingPiece() function:
This function (which only takes app, and not canvas) is quite similar to drawFallingPiece, only rather than draw the cells, we load the corresponding cells of the fallingPiece onto the board with the fallingPieceColor. In this way, the piece is placed on the board.
Finally, add a line right after the call to placeFallingPiece that uses newFallingPiece to start a new piece falling from the top. Once you get this working, our game springs to life! 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, right after we call newFallingPiece. There we can create a new app value "isGameOver" (which is set to False in appStarted) and set it to True once we reach our game-over state.
But what should we do when the game has ended? We will update our keyPressed and timerFired functions to check for this variable, and stop all game interaction once the game is over. Also, if the variable is True, the draw function should draw a suitable message stating that the game is over.
Finally, we will let the user start a new game at any time by hitting 'r' for 'restart', and calling the appStarted function in response. Be sure your keyPressed continues to look for the 'r' key, even the the game is over, or else it will be impossible to restart!
At this time we will also remove our test code from prior steps, both the call to newFallingPiece in response to a non-arrow key press and the four corners in appStarted.
At the end of this stage, your Tetris board should be able to do this:
David Kosbie
Carnegie Mellon University koz@cmu.edu