Building Tetris in Pygame – Part V

# 009 Spawning blocks

Last time we got our basic display code up and running, but before we can go any further we need a way to spawn pieces.

Let’s switch back to our game_state git branch:

$ git status
# On branch display
nothing to commit (working directory clean)
$ git checkout master
Switched to branch 'master'
$ git merge display
Updating d2c7908..e4bcf30
Fast-forward
 tetris.py       |   36 +++++++++++++++++++++++++++++++++++-
 tetris/const.py |   29 +++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)
$ git checkout game_state
Switched to branch 'game_state'
$ git merge master
Updating d2c7908..e4bcf30
Fast-forward
 tetris.py       |   36 +++++++++++++++++++++++++++++++++++-
 tetris/const.py |   29 +++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 1 deletion(-)
$ git status
# On branch game_state
nothing to commit (working directory clean)

When we left off last, GameState still had no way of tracking the coordinates of the current piece. As always, test first:

tests/test_state.py

    # ...
    def test_spawn_piece_coords(self):
        self.state.spawn_piece()

        self.assertEquals(self.state.piece_x, 4)
        self.assertEquals(self.state.piece_y, 0)

(This test case may not be valid when we move up to the full tetriminos, but for now it will do.)

Add the test to run_tests.py, and run the test suite:

$ ./run_tests.py
Running tests:
STATE:      .....E

------------

In test_spawn_piece_coords (tests.test_state.TestGameState)
Traceback (most recent call last):
  File ".../tetris/tests/test_state.py", line 58, in test_spawn_piece_coords
    self.assertEquals(self.state.piece_x, 4)
AttributeError: 'GameState' object has no attribute 'piece_x'

------------

6 tests run in 0.000673 seconds, 0 failures, 0 skipped, 1 unexpected errors.

This is a pretty simple test to pass:

    # ...
    def spawn_piece(self):
        if self.next_piece == None:
            self.next_piece = self.get_new_piece()

        self.curr_piece = self.next_piece
        self.next_piece = self.get_new_piece()

        self.piece_x = 4
        self.piece_y = 0

This is… getting ugly. I’ll need to keep this section in mind for later cleanup and refactoring. For now, though, we have more pressing problems.

Even if we modify our main function to call spawn_piece(), we won’t get any blocks on screen, because we don’t actually draw the active piece! Oops.

Let’s switch back over to the display branch and fix that:

$ git add .
$ git status
...
$ git commit -m "Spawn piece at coordinates"
$ git checkout master
Switched to branch 'master'
$ git merge game_state
Updating e4bcf30..44833c8
Fast-forward
 run_tests.py        |    1 +
 tests/test_state.py |    6 ++++++
 tetris/state.py     |    3 +++
 3 files changed, 10 insertions(+)
$ git checkout display
Switched to branch 'display'
$ git merge master
Updating e4bcf30..44833c8
Fast-forward
 run_tests.py        |    1 +
 tests/test_state.py |    6 ++++++
 tetris/state.py     |    3 +++
 3 files changed, 10 insertions(+)

First, a quick addition to main() so that we get a piece spawned:

def main():
    # ...
    while True:
        # ...
        # Game logic
        if game_state.curr_piece == None:
            game_state.spawn_piece()

        # Display
        draw_screen(displaysurf, game_state)

Now let’s add code for drawing the current piece:
tetris.py

    # ... in draw_screen()

    # Draw current piece:
    curr_left = const.MARGIN_LEFT + (game_state.piece_x * const.BLOCK_SIZE)
    curr_top = const.MARGIN_TOP + (game_state.piece_y * const.BLOCK_SIZE)
    curr_color = const.C_LIST[game_state.curr_piece[0][0]]

    pygame.draw.rect(surface, curr_color,
        (curr_left, curr_top, const.BLOCK_SIZE, const.BLOCK_SIZE))

    pygame.display.flip()

Run the game, and you should get a random colored block at the top of the well.

Finally, at long last, we’re ready to work on the actual game logic — moving pieces and afixing them to the board once they land. We will work on that next time, but for now we will get everything commited to git:

$ git add .
$ git status
...
$ git commit -m "Draw current piece."
 [display 3965dcd] Draw current piece.
 2 files changed, 15 insertions(+), 5 deletions(-)
$ git checkout master
Switched to branch 'master'
$ git merge display
Updating 44833c8..3965dcd
Fast-forward
 tetris.py       |   14 ++++++++++++--
 tetris/const.py |    6 +++---
 2 files changed, 15 insertions(+), 5 deletions(-)