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.
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 onepygame.Surface
object to another. You need to draw the objects on thescreen
but not on theboard
. You must redraw the entire scene in each frame: