Pygame 俄罗斯方块问题

Pygame Tetris Issue

我在 python 3.6 中为 Pygame 编写了一个非常初级的俄罗斯方块版本。到目前为止唯一的功能是方块下落,使它们下落得更快,左右移动,当一个方块撞到地面时,一个新的方块产生。

但是,问题来了。当第一个方块落地时,方块会无限期地出现在屏幕顶部。我搜索了代码,也给我的朋友看了,但我们找不到问题所在。我报废了代码并重写了它,问题仍然存在。这里有人看到了吗?

谢谢

P.S。 我很确定代码的前 2/3 不是问题。

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

问题出在 Blockfall 方法中。您只更改 y 属性,但永远不会移动块的 rect ,因此它实际上一直停留在屏幕顶部。所以删除 x, y 属性,只使用 self.rect.xself.rect.y,或者设置 self.rect.y = self.y.

为了调试我首先在 if locked: 行上方打印 print(locked, len(fallingblocks), len(setblocks)) 的代码,以确认在第一个块接触地面后 locked 总是 True。然后我尝试用 setblocks 注释掉碰撞检测并且连续产卵停止。下一步是打印 setblocks 和 fallingblocks 的矩形,它显示矩形的 y-pos 始终为 0 或 25,并且从未改变。我查看了 fall 方法中的移动代码,发现矩形没有移动。

还有更多问题,但我认为您应该先尝试继续调试,如果仍然有问题,请提出新问题。