I've been writing a very rudimentary version of Tetris for Pygame in python 3.6. The only features so far are the blocks falling, making them fall faster, moving left and right, and when a block hits the ground, a new one spawns.
However, there is the issue. When the first block hits the ground, blocks spawn indefinitely at the top of the screen. I scoured the code and also showed it to my friend, and we couldn't find the issue. I scrapped the code and rewrote it, and the problem persisted. Does anyone here see it?
Thanks
P.S. I'm pretty sure that the top 2/3 of the code is not the issue.
import pygame, random
screen = pygame.display.set_mode((400,600))
pygame.display.set_caption("Tetris")
done = False
fast = False
locked = False
fallingblocks = []
setblocks = []
clock = pygame.time.Clock()
fallcooldown = 0
class Block:
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
fallingblocks.append(self)
self.rect = pygame.Rect(self.x + 1, self.y, 23, 25) #game only cares if falling block collides on the top or bottom, not side
def fall(self):
self.y += 25
def move(self):
if pressed[pygame.K_a] or pressed[pygame.K_LEFT]: self.x -= 25
if pressed[pygame.K_d] or pressed[pygame.K_RIGHT]: self.x += 25
def drawblock(self): #just to make it look nice
pygame.draw.rect(screen, self.color[0], pygame.Rect(self.x,self.y,25,25))
pygame.draw.polygon(screen, self.color[1], ((self.x,self.y),(self.x+3,self.y+3),(self.x+21,self.y+3),(self.x+24,self.y)))
pygame.draw.polygon(screen, self.color[2], ((self.x,self.y),(self.x+3,self.y+3),(self.x+3,self.y+21),(self.x,self.y+24)))
pygame.draw.polygon(screen, self.color[3], ((self.x,self.y+24),(self.x+3,self.y+21),(self.x+21,self.y+21),(self.x+24,self.y+24)))
pygame.draw.polygon(screen, self.color[4], ((self.x+24,self.y+24),(self.x+21,self.y+21),(self.x+21,self.y+3),(self.x+24,self.y)))
def spawn():
blocknum = random.randint(0,6)
if blocknum == 0:
#I block
colors = [(129,184,231),
(179,223,250),
(146,202,238),
(76,126,189),
(96,157,213)]
Block(175,0,colors)
Block(175,25,colors)
Block(175,50,colors)
Block(175,75,colors)
elif blocknum == 1:
#J block
colors = [(77,110,177),
(149,178,229),
(104,145,203),
(49,63,136),
(63,85,158)]
Block(200,0,colors)
Block(200,25,colors)
Block(200,50,colors)
Block(175,50,colors)
elif blocknum == 2:
#L block
colors = [(219,127,44),
(243,191,122),
(229,158,69),
(166,71,43),
(193,98,44)]
Block(175,0,colors)
Block(175,25,colors)
Block(175,50,colors)
Block(200,50,colors)
elif blocknum == 3:
#O block
colors = [(248,222,49),
(246,243,139),
(245,235,86),
(183,160,54),
(213,190,55)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(200,25,colors)
elif blocknum == 4:
#S block
colors = [(156,195,76),
(204,218,127),
(174,208,79),
(109,157,75),
(140,183,93)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(150,25,colors)
elif blocknum == 5:
#Z block
colors = [(204,42,40),
(226,138,132),
(213,90,69),
(151,34,42),
(181,37,43)]
Block(175,0,colors)
Block(225,25,colors)
Block(200,0,colors)
Block(200,25,colors)
else:
#T block
colors = [(147,68,149),
(187,145,194),
(156,101,167),
(108,45,123),
(128,47,135)]
Block(175,0,colors)
Block(175,25,colors)
Block(200,0,colors)
Block(150,0,colors)
spawn()
#Pretty sure that everything above here is not the issue
while not done: #main loop
screen.fill((0,0,32))
pressed = pygame.key.get_pressed()
for fallingblock in fallingblocks:
fallingblock.drawblock()
fallingblock.move()
for setblock in setblocks:
setblock.drawblock()
if fallcooldown >= 50: #makes all pieces fall at once
for fallingblock in fallingblocks:
fallingblock.fall()
fallcooldown = 0
pygame.display.flip()
if pressed[pygame.K_SPACE]: #if you want the piece to go the ground instantly
fast = True
if fast: fallcooldown = 50 #falling movements
elif pressed[pygame.K_DOWN]: fallcooldown += 8 #goes faster
else: fallcooldown += 1 #default speed
for fallingblock in fallingblocks:
for setblock in setblocks:
if fallingblock.rect.colliderect(setblock.rect): #if fallingblock collides with setblock
locked = True
if fallingblock.y >= 575 and not locked: #if block hits the bottom
locked = True
if locked: #if block is in final state
setblocks += fallingblocks
fallingblocks = []
spawn()
locked = False
clock.tick(50)
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
The problem is caused in the fall
method of the Block
. You only change the y
attribute but never move the rect
of the block, so it actually stays at the top of the screen the whole time. So remove the x, y
attributes and just use self.rect.x
and self.rect.y
, or alternatively set self.rect.y = self.y
.
To debug the code I first printed print(locked, len(fallingblocks), len(setblocks))
above the if locked:
line to confirm that locked
was always True
after the first block touched the ground. Then I tried to comment out the collision detection with the setblocks
and the continuous spawning stopped. The next step was to print the rects of the setblocks and fallingblocks and it revealed that the y-pos of the rects was always 0 or 25 and never changed. I looked at the movement code in the fall
method and noticed that the rect doesn't get moved.
There are more issues, but I think you should try to continue with the debugging first and ask new questions if you still have trouble.