Python实现经典俄罗斯方块游戏开发指南

Python实现经典俄罗斯方块游戏开发指南

完整代码在文章底部

一、环境准备

pip install pygame

二、核心功能实现

1. 游戏元素定义

  • 七种经典方块:I、L、J、O、S、T、Z型
  • 颜色系统:每个方块类型对应不同颜色
  • 网格系统:10x20的游戏区域

2. 核心算法解析

方块旋转算法
# 矩阵转置+逆序实现旋转
self.shape = [list(row) for row in zip(*self.shape[::-1])]
碰撞检测
def check_collision(self, grid, dx=0, dy=0):
    # 边界检测和已有方块检测
    ...
消行算法
def clear_lines(self):
    # 遍历所有行,移除满行并补充新空行
    ...

3. 游戏控制逻辑

  • 方向键:左右移动
  • 上方向键:旋转方块
  • 空格键:硬降到底
  • 自动下落速度:0.5秒/格

三、代码结构说明

1. 主要类说明

类名功能描述
Tetromino处理单个方块的形状、颜色和旋转
Tetris管理游戏状态和核心逻辑

2. 关键方法

  • move_down(): 处理方块下落逻辑
  • lock_piece(): 锁定已落地方块
  • hard_drop(): 快速下落实现

四、运行效果

  • 游戏区域:300x600像素
  • 得分规则:消1行100分,消2行400分,消3行900分,消4行1600分
  • 预览功能:显示下一个即将出现的方块

五、扩展开发建议

  1. 难度系统:随着分数增加加快下落速度
  2. 音效系统:添加消除音效和背景音乐
  3. 排行榜功能:记录历史最高分
  4. 特效系统:添加消除动画效果
  5. 手柄支持:扩展控制器输入

六、常见问题解答

  1. 方块旋转出界:通过碰撞检测自动修正位置
  2. 画面闪烁问题:使用双缓冲技术 pygame.display.flip()
  3. 控制响应延迟:优化事件处理循环

实现效果示意图
在这里插入图片描述

项目完整代码

import pygame
import random
import time

# 初始化Pygame
pygame.init()

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
COLORS = [
    (0, 255, 255),   # I型-青色
    (255, 165, 0),   # L型-橙色
    (0, 0, 255),     # J型-蓝色
    (255, 255, 0),   # O型-黄色
    (0, 255, 0),     # S型-绿色
    (255, 0, 255),   # T型-紫色
    (255, 0, 0)      # Z型-红色
]

# 游戏设置
WIDTH = 300
HEIGHT = 600
BLOCK_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20

# 方块形状定义(4x4矩阵)
SHAPES = [
    [[1, 1, 1, 1]],                   # I型
    [[1, 0, 0], [1, 1, 1]],           # L型
    [[0, 0, 1], [1, 1, 1]],           # J型
    [[1, 1], [1, 1]],                 # O型
    [[0, 1, 1], [1, 1, 0]],           # S型
    [[0, 1, 0], [1, 1, 1]],           # T型
    [[1, 1, 0], [0, 1, 1]]            # Z型
]

class Tetromino:
    def __init__(self, x, y):
        self.shape = random.choice(SHAPES)
        self.color = COLORS[SHAPES.index(self.shape)]
        self.x = x
        self.y = y
        self.rotation = 0

    def rotate(self):
        # 保存原始状态用于回滚
        original_shape = self.shape
        original_x = self.x

        # 矩阵转置+逆序实现旋转
        self.shape = [list(row) for row in zip(*self.shape[::-1])]

        # 旋转后自动校正位置避免越界
        offset_x = 0
        while self.check_collision() and offset_x < 3:  # 最多尝试调整3次
            if self.x < GRID_WIDTH // 2:
                # 尝试右移
                self.x += 1
                offset_x += 1
            else:
                # 尝试左移
                self.x -= 1
                offset_x += 1

        # 如果调整后仍碰撞则恢复原状
        if self.check_collision():
            self.shape = original_shape
            self.x = original_x

    def check_collision(self, grid=None, dx=0, dy=0):
        if grid is None:
            grid = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)]

        for y, row in enumerate(self.shape):
            for x, cell in enumerate(row):
                if cell:
                    new_x = self.x + x + dx
                    new_y = self.y + y + dy
                    # 边界检查
                    if new_x < 0 or new_x >= GRID_WIDTH:
                        return True
                    if new_y >= GRID_HEIGHT:
                        return True
                    # 已有方块检查
                    if new_y >= 0 and grid[new_y][new_x]:
                        return True
        return False

class Tetris:
    def __init__(self):
        self.grid = [[0] * GRID_WIDTH for _ in range(GRID_HEIGHT)]
        self.current_piece = None
        self.next_piece = Tetromino(0, 0)
        self.score = 0
        self.spawn_new_piece()

    def spawn_new_piece(self):
        self.current_piece = self.next_piece
        self.next_piece = Tetromino(0, 0)
        self.current_piece.x = GRID_WIDTH // 2 - len(self.current_piece.shape[0]) // 2
        self.current_piece.y = 0

        # 生成即碰撞说明游戏结束
        if self.current_piece.check_collision(self.grid):
            print("Game Over! Score:", self.score)
            pygame.quit()
            exit()

    def move_down(self):
        if not self.current_piece.check_collision(self.grid, dy=1):
            self.current_piece.y += 1
            return True
        self.lock_piece()
        return False

    def lock_piece(self):
        # 将当前方块写入网格
        for y, row in enumerate(self.current_piece.shape):
            for x, cell in enumerate(row):
                if cell:
                    gy = self.current_piece.y + y
                    gx = self.current_piece.x + x
                    if 0 <= gy < GRID_HEIGHT and 0 <= gx < GRID_WIDTH:  # 防止索引越界
                        self.grid[gy][gx] = self.current_piece.color
        self.clear_lines()
        self.spawn_new_piece()

    def clear_lines(self):
        lines_cleared = 0
        new_grid = []
        for row in self.grid:
            if 0 not in row:
                lines_cleared += 1
            else:
                new_grid.append(row)

        self.score += lines_cleared ** 2 * 100
        # 补充新行到顶部
        self.grid = [[0] * GRID_WIDTH for _ in range(lines_cleared)] + new_grid

    def move_horizontal(self, dx):
        if not self.current_piece.check_collision(self.grid, dx=dx):
            self.current_piece.x += dx

    def hard_drop(self):
        while self.move_down():
            pass

# 初始化游戏
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("俄罗斯方块")
clock = pygame.time.Clock()
game = Tetris()

def draw_grid():
    for y in range(GRID_HEIGHT):
        for x in range(GRID_WIDTH):
            color = game.grid[y][x]
            if color:
                pygame.draw.rect(screen, color,
                                 (x * BLOCK_SIZE + 1, y * BLOCK_SIZE + 1,
                                  BLOCK_SIZE - 2, BLOCK_SIZE - 2))

def draw_current_piece():
    for y, row in enumerate(game.current_piece.shape):
        for x, cell in enumerate(row):
            if cell:
                pygame.draw.rect(screen, game.current_piece.color,
                                 ((game.current_piece.x + x) * BLOCK_SIZE + 1,
                                  (game.current_piece.y + y) * BLOCK_SIZE + 1,
                                  BLOCK_SIZE - 2, BLOCK_SIZE - 2))

running = True
fall_time = 0
fall_speed = 0.5

while running:
    screen.fill(BLACK)

    current_time = time.time()
    delta_time = current_time - fall_time

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                game.move_horizontal(-1)
            elif event.key == pygame.K_RIGHT:
                game.move_horizontal(1)
            elif event.key == pygame.K_UP:
                game.current_piece.rotate()
            elif event.key == pygame.K_DOWN:
                game.move_down()
            elif event.key == pygame.K_SPACE:
                game.hard_drop()

    if delta_time >= fall_speed:
        game.move_down()
        fall_time = current_time

    draw_grid()
    draw_current_piece()
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值