Tutorial #2
Subscribe to Tech with Tim
Drawing the Grid
This function will simply draw the grey grid lines in the play area so that we can see which square our pieces are in. You may recall us calling this function in our draw_window function from the last tutorial.
def draw_grid(surface, row, col): # This function draws the grey grid lines that we see sx = top_left_x sy = top_left_y for i in range(row): pygame.draw.line(surface, (128,128,128), (sx, sy+ i*30), (sx + play_width, sy + i * 30)) # horizontal lines for j in range(col): pygame.draw.line(surface, (128,128,128), (sx + j * 30, sy), (sx + j * 30, sy + play_height)) # vertical lines
Converting Shape Formats
At this point in time each of our pieces is represented by a multidimensional list. We need something that can translate this list into a form that the computer can understand. Ideally given a shape format we want to convert it to a list of positions that we can then return. That is what convert_shape_format() will do for us.
If you'd like a detailed explanation of this code please watch the video starting at 4:30.
def convert_shape_format(shape): positions = [] format = shape.shape[shape.rotation % len(shape.shape)] for i, line in enumerate(format): row = list(line) for j, column in enumerate(row): if column == \'0\': positions.append((shape.x + j, shape.y + i)) for i, pos in enumerate(positions): positions[i] = (pos[0] - 2, pos[1] - 4) return positions
Determine a Valid Space
When we are moving and rotating our shape we need to make sure that it is moving into a valid space. We are going to use the valid_space() function to check this. This function will have two parameters: grid and shape. We will check the grid to ensure that the current position we are trying to move into is not occupied. We can do this by seeing if any of the positions in the grid that the shape is attempting to move into have a color. If they have a color other than black than that means they are occupied, otherwise they are free.
def valid_space(shape, grid): accepted_positions = [[(j, i) for j in range(10) if grid[i][j] == (0,0,0)] for i in range(20)] accepted_positions = [j for sub in accepted_positions for j in sub] formatted = convert_shape_format(shape) for pos in formatted: if pos not in accepted_positions: if pos[1] > -1: return False return True
Checking if We Lose the Game
In order to end the game we need to constantly be checking if the user has lost the game. The check_lost() function will do this for us. We are simply going to check if any position in the given list is above the screen. If it is we have reached the top and therefore lost the game.
def check_lost(positions): for pos in positions: x, y = pos if y < 1: return True return False
Modifying the Game Loop
Now we are going to add some code into game loop that will move our pieces down the screen at a certain time interval.
Look for the comments to see which code it new.
def main(): global grid locked_positions = {} # (x,y):(255,0,0) grid = create_grid(locked_positions) change_piece = False run = True current_piece = get_shape() next_piece = get_shape() clock = pygame.time.Clock() fall_time = 0 while run: # -------NEW CODE--------- fall_speed = 0.27 grid = create_grid(locked_positions) fall_time += clock.get_rawtime() clock.tick() # PIECE FALLING CODE if fall_time/1000 >= fall_speed: fall_time = 0 current_piece.y += 1 if not (valid_space(current_piece, grid)) and current_piece.y > 0: current_piece.y -= 1 change_piece = True # --------END NEW CODE--------- for event in pygame.event.get(): if event.type == pygame.QUIT: run = False pygame.display.quit() quit() if event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: current_piece.x -= 1 if not valid_space(current_piece, grid): current_piece.x += 1 elif event.key == pygame.K_RIGHT: current_piece.x += 1 if not valid_space(current_piece, grid): current_piece.x -= 1 elif event.key == pygame.K_UP: # rotate shape current_piece.rotation = current_piece.rotation + 1 % len(current_piece.shape) if not valid_space(current_piece, grid): current_piece.rotation = current_piece.rotation - 1 % len(current_piece.shape) if event.key == pygame.K_DOWN: # move shape down current_piece.y += 1 if not valid_space(current_piece, grid): current_piece.y -= 1 # -------NEW CODE-------- shape_pos = convert_shape_format(current_piece) # add color of piece to the grid for drawing for i in range(len(shape_pos)): x, y = shape_pos[i] if y > -1: # If we are not above the screen grid[y][x] = current_piece.color # IF PIECE HIT GROUND if change_piece: for pos in shape_pos: p = (pos[0], pos[1]) locked_positions[p] = current_piece.color current_piece = next_piece next_piece = get_shape() change_piece = False #-------END NEW CODE------- draw_window(win, grid) #------NEW CODE-------- # Check if user lost if check_lost(locked_positions): run = False #------END NEW CODE--------