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
问题出在 Block
的 fall
方法中。您只更改 y
属性,但永远不会移动块的 rect
,因此它实际上一直停留在屏幕顶部。所以删除 x, y
属性,只使用 self.rect.x
和 self.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
方法中的移动代码,发现矩形没有移动。
还有更多问题,但我认为您应该先尝试继续调试,如果仍然有问题,请提出新问题。
我在 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
问题出在 Block
的 fall
方法中。您只更改 y
属性,但永远不会移动块的 rect
,因此它实际上一直停留在屏幕顶部。所以删除 x, y
属性,只使用 self.rect.x
和 self.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
方法中的移动代码,发现矩形没有移动。
还有更多问题,但我认为您应该先尝试继续调试,如果仍然有问题,请提出新问题。