You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pygame开发俄罗斯方块:方块无法显示问题求助

俄罗斯方块方块不显示问题修复

核心问题分析

  1. 方块生成逻辑错误:create_piece和rotate函数中使用row.split()处理形状字符串是错误操作。形状的每一行是连续字符(如'..00..'),无空格分隔,split()会返回空列表,导致遍历不到任何字符,最终生成的Sprite组为空,自然看不到方块。
  2. 底部碰撞检测缺失:仅检测了与静止方块的碰撞,未判断方块是否到达游戏区域底部,方块会直接下落出屏幕。
  3. Sprite引用失效:旋转方块后,旧的Sprite列表未更新,导致后续碰撞检测失效。

修复后的完整代码

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 = (
            (BOARD_WIDTH // 2 - 2*TILE_SIZE[0]) + x * TILE_SIZE[0],
            y * TILE_SIZE[1]
        )
        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()
    # 直接遍历字符串的每个字符,不要用split()
    for y, row in enumerate(shape_rot):
        for x, char in enumerate(row):
            if char == "0":
                final_shape.add(Block(color, x, y, rotation))
    return final_shape, shape_index

def rotate(shape_index, rotation):
    # 处理旋转索引越界
    rotation %= len(shapes[shape_index])
    new_shape = shapes[shape_index][rotation]
    color = shape_colors[shape_index]
    final_shape = pygame.sprite.Group()
    for y, row in enumerate(new_shape):
        for x, char in enumerate(row):
            if char == '0':
                # 保持旋转后位置居中,基于原形状中心偏移
                final_shape.add(Block(color, x, y, rotation))
    return final_shape

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

    while running:
        screen.fill((0,0,0))
        screen.blit(board, (0, 0))

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and shape_index is not None:
                    rotation += 1
                    shape = rotate(shape_index, rotation)
                if event.key == pygame.K_LEFT and shape is not None:
                    # 左移,先检测碰撞
                    for block in shape:
                        block.rect.x -= TILE_SIZE[0]
                    if pygame.sprite.groupcollide(shape, not_falling, False, False) or any(block.rect.x < 0 for block in shape):
                        for block in shape:
                            block.rect.x += TILE_SIZE[0]
                if event.key == pygame.K_RIGHT and shape is not None:
                    # 右移,检测碰撞
                    for block in shape:
                        block.rect.x += TILE_SIZE[0]
                    if pygame.sprite.groupcollide(shape, not_falling, False, False) or any(block.rect.x + TILE_SIZE[0] > BOARD_WIDTH for block in shape):
                        for block in shape:
                            block.rect.x -= TILE_SIZE[0]
                if event.key == pygame.K_DOWN and shape is not None:
                    # 快速下落
                    shape.update()

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

        if shape is not None:
            # 检测是否到底部或碰撞静止方块
            hit_bottom = any(block.rect.y + TILE_SIZE[1] > BOARD_HEIGHT for block in shape)
            collision = pygame.sprite.groupcollide(shape, not_falling, False, False)
            
            if hit_bottom or collision:
                not_falling.add(shape)
                falling = False
            else:
                shape.update()

            shape.draw(board)
        not_falling.draw(board)

        pygame.display.flip()
        clock.tick(FPS)

if __name__ == '__main__':
    mainGame()

关键修复点说明

  • 修正方块生成逻辑:将row.split()改为直接遍历字符串字符,确保正确识别形状中的0并生成Block。
  • 添加底部碰撞检测:主循环中检查方块是否到达游戏区域底部,结合静止方块碰撞判断是否停止下落。
  • 移除无效引用:直接使用shape组进行碰撞检测和绘制,避免旧Sprite列表引用失效。
  • 优化初始位置:将方块初始位置设置为游戏区域上方居中,避免生成在屏幕外。
  • 补充移动逻辑:实现左右移动的碰撞检测,防止方块移出游戏区域或与静止方块重叠。

内容的提问来源于stack exchange,提问作者Colin Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 07:38:17