Pygame Tetris blocks not showing

90 views Asked by At

I am trying to build Tetris in pygame and I am working on just making a shape appear on screen. My idea was to create each block as a sprite to keep track of them so when you create the piece it creates a sprite group of blocks and this group is updated to move down until it collides with stationary pieces or the bottom. The block checks if its reached the bottom in the update method in the Block class and the collision every run through the game loop and if it doesnt detect either then it will shift the blocks y (self.rect.y) down the height of a Tile (or block). The logic seems straight forward and I've had iterations of the code work before with minor issues but I struggle to debug and track down these issues. Here is the entirety of my code:

import pygame
import random
####### SETTINGS ########
FPS = 60
SCREEN_WIDTH = 500
BOARD_WIDTH = 300
BOARD_HEIGHT = 600
TILE_SIZE = [30, 30]

S = [['.....',
      '......',
      '..00..',
      '.00...',
      '.....'],
     ['.....',
      '..0..',
      '..00.',
      '...0.',
      '.....']]

Z = [['.....',
      '.....',
      '.00..',
      '..00.',
      '.....'],
     ['.....',
      '..0..',
      '.00..',
      '.0...',
      '.....']]

I = [['..0..',
      '..0..',
      '..0..',
      '..0..',
      '.....'],
     ['.....',
      '0000.',
      '.....',
      '.....',
      '.....']]

O = [['.....',
      '.....',
      '.00..',
      '.00..',
      '.....']]

J = [['.....',
      '.0...',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..00.',
      '..0..',
      '..0..',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '...0.',
      '.....'],
     ['.....',
      '..0..',
      '..0..',
      '.00..',
      '.....']]

L = [['.....',
      '...0.',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..0..',
      '..0..',
      '..00.',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '.0...',
      '.....'],
     ['.....',
      '.00..',
      '..0..',
      '..0..',
      '.....']]

T = [['.....',
      '..0..',
      '.000.',
      '.....',
      '.....'],
     ['.....',
      '..0..',
      '..00.',
      '..0..',
      '.....'],
     ['.....',
      '.....',
      '.000.',
      '..0..',
      '.....'],
     ['.....',
      '..0..',
      '.00..',
      '..0..',
      '.....']]

shapes = [S, Z, I, O, J, L, T]
shape_colors = [(0, 255, 0), (255, 0, 0), (0, 255, 255),
                (255, 255, 0), (255, 165, 0), (0, 0, 255), (128, 0, 128)]

class Block(pygame.sprite.Sprite):
    def __init__(self, color, x, y, rotation):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface(TILE_SIZE)
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.topleft = ((x * TILE_SIZE[0]), (y * TILE_SIZE[1]))  # Set the top-left corner of the rect
        self.rotation = rotation

    def update(self):
        self.rect.y += TILE_SIZE[1]
        
    def rotate(self):
        self.rotation += 1


def createBoard():
    board = pygame.Surface((BOARD_WIDTH, BOARD_HEIGHT))
    board.fill((255, 255, 255))
    return board

def create_piece():
    rotation = 0
    shape = random.choice(shapes)
    shape_rot = shape[rotation]
    shape_index = shapes.index(shape)
    color = shape_colors[shape_index]
    final_shape = pygame.sprite.Group()
    for i in range(len(shape_rot)):
        row = shape_rot[i].split()
        for j in range(len(row)):
            if row[j] == "0":
                final_shape.add(Block(color, j, i, rotation))
    return final_shape, shape_index

def rotate(shape_index, rotation):
    y = 0
    new_shape = shapes[shape_index][rotation]
    color = shape_colors[shape_index]
    final_shape = pygame.sprite.Group()
    for row in range(len(new_shape)):
        x = 0
        for col in range(len(new_shape[row].split())):
            if new_shape[row][col] == '0':
                final_shape.add(Block(color, x, y, rotation))
            x += 1
        y += 1
        x = 0
    return final_shape

def mainGame():
    pygame.init()
    screen = pygame.display.set_mode((SCREEN_WIDTH, BOARD_HEIGHT))
    clock = pygame.time.Clock()
    running = True
    falling = False
    rotation = 0
    not_falling = pygame.sprite.Group()
    shape = None
    shape_index = None
    board = createBoard()
    screen.blit(board, (0, 0))

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    rotation += 1
                    shape = rotate(shape_index, rotation)
                if event.key == pygame.K_DOWN:
                    # Implement moving the shape down
                    pass
                if event.key == pygame.K_LEFT:
                    # Implement moving the shape to the left
                    pass
                if event.key == pygame.K_RIGHT:
                    # Implement moving the shape to the right
                    pass

        if not falling:
            shape_var = create_piece()
            shape_index = shape_var[1]
            shape = shape_var[0]
            blocks = shape_var[0].sprites()
            falling = True

        shape.update()
        collision = pygame.sprite.groupcollide(blocks, not_falling, False, False, None)
        for block in blocks:
            if block in collision:
                not_falling.add(blocks)
                falling = False

        
        shape.draw(board)
        not_falling.draw(board)
        pygame.display.flip()
        clock.tick(FPS)



if __name__ == '__main__':
    mainGame()

I have tried changing how the x and y pos are passed to the block and I have also tried changing how to blocks are displayed and its been a few days but I've come up with nothing.

1

There are 1 answers

4
Rabbid76 On BEST ANSWER

If you change a surface object that has already been drawn to the screen with blit, these changes will not magically become visible on the screen. blit means "bit block transfer" and does nothing more than copying pixels from one pygame.Surface object to another. You need to draw the objects on the screen but not on the board. You must redraw the entire scene in each frame:

while running:
    # [...]

    screen.blit(board, (0, 0))
    shape.draw(screen)
    not_falling.draw(screen)
    pygame.display.flip()