Python俄罗斯方块源码

作者: admin | 创建时间: 2025-02-24 14:30:55 文章分类: python

文章简介: 以下是一个基于Python和Pygame实现的俄罗斯方块完整源码,包含详细注释:

一.代码编写

以下是一个基于Python和Pygame实现的俄罗斯方块完整源码,包含详细注释:

import pygame
import random

# 初始化Pygame
pygame.init()

# 定义颜色
COLORS = [
    (0, 0, 0),         # 黑色(背景)
    (255, 0, 0),       # 红色
    (0, 150, 0),       # 绿色
    (0, 0, 255),       # 蓝色
    (255, 120, 0),     # 橙色
    (255, 255, 0),     # 黄色
    (180, 0, 255),     # 紫色
    (0, 220, 220)      # 青色
]

# 定义方块形状(7种经典形状)
SHAPES = [
    [[1, 1, 1, 1]],                   # I型
    [[1, 1], [1, 1]],                 # O型
    [[1, 1, 1], [0, 1, 0]],           # T型
    [[1, 1, 1], [1, 0, 0]],           # L型
    [[1, 1, 1], [0, 0, 1]],           # J型
    [[1, 1, 0], [0, 1, 1]],           # S型
    [[0, 1, 1], [1, 1, 0]]            # Z型
]

# 游戏参数配置
BLOCK_SIZE = 30        # 单个方块像素大小
GAME_WIDTH = 10        # 游戏区域宽度(单位:方块)
GAME_HEIGHT = 20       # 游戏区域高度
BORDER = 2             # 边框厚度

# 计算窗口尺寸
WINDOW_WIDTH = BLOCK_SIZE * (GAME_WIDTH + 8)
WINDOW_HEIGHT = BLOCK_SIZE * GAME_HEIGHT

class Tetris:
    def __init__(self):
        self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
        pygame.display.set_caption("Python 俄罗斯方块")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont('arial', 25, bold=True)

        # 初始化游戏状态
        self.reset_game()

    def reset_game(self):
        """重置游戏状态"""
        self.game_map = [[0] * GAME_WIDTH for _ in range(GAME_HEIGHT)]
        self.score = 0
        self.current_shape = self.new_shape()
        self.next_shape = self.new_shape()
        self.game_over = False
        self.fall_speed = 45  # 下落速度(值越小越快)
        self.fall_counter = 0

    def new_shape(self):
        """生成新方块"""
        shape = random.choice(SHAPES)
        color = random.randint(1, len(COLORS)-1)
        return {
            'shape': shape,
            'color': color,
            'x': GAME_WIDTH // 2 - len(shape[0]) // 2,
            'y': 0
        }

    def check_collision(self, shape, offset_x=0, offset_y=0):
        """检测碰撞"""
        for y, row in enumerate(shape['shape']):
            for x, cell in enumerate(row):
                if cell:
                    new_x = shape['x'] + x + offset_x
                    new_y = shape['y'] + y + offset_y
                    if new_x < 0 or new_x >= GAME_WIDTH:
                        return True
                    if new_y >= GAME_HEIGHT:
                        return True
                    if new_y >=0 and self.game_map[new_y][new_x]:
                        return True
        return False

    def rotate_shape(self):
        """旋转方块"""
        rotated = list(zip(*self.current_shape['shape'][::-1]))
        # 检查旋转后是否碰撞
        original_shape = self.current_shape['shape']
        self.current_shape['shape'] = rotated
        if self.check_collision(self.current_shape):
            self.current_shape['shape'] = original_shape  # 还原
        return

    def merge_shape(self):
        """合并当前方块到游戏地图"""
        for y, row in enumerate(self.current_shape['shape']):
            for x, cell in enumerate(row):
                if cell:
                    self.game_map[self.current_shape['y'] + y][self.current_shape['x'] + x] = self.current_shape['color']
        # 检查并消除满行
        self.check_lines()
        # 生成新方块
        self.current_shape = self.next_shape
        self.next_shape = self.new_shape()
        # 检查游戏结束
        if self.check_collision(self.current_shape):
            self.game_over = True

    def check_lines(self):
        """消除满行并计分"""
        lines_cleared = 0
        for y in range(len(self.game_map)):
            if 0 not in self.game_map[y]:
                del self.game_map[y]
                self.game_map.insert(0, [0]*GAME_WIDTH)
                lines_cleared += 1
        # 更新分数
        if lines_cleared:
            self.score += [40, 100, 300, 1200][lines_cleared-1]
            self.fall_speed = max(15, self.fall_speed - 2)  # 加速下落

    def draw_block(self, x, y, color):
        """绘制单个方块"""
        pygame.draw.rect(self.screen,
                        COLORS[color],
                        (x * BLOCK_SIZE + BORDER,
                         y * BLOCK_SIZE + BORDER,
                         BLOCK_SIZE - 2*BORDER,
                         BLOCK_SIZE - 2*BORDER))

    def draw_game(self):
        """绘制游戏界面"""
        self.screen.fill(COLORS[0])  # 背景

        # 绘制游戏区域
        for y in range(GAME_HEIGHT):
            for x in range(GAME_WIDTH):
                if self.game_map[y][x]:
                    self.draw_block(x, y, self.game_map[y][x])

        # 绘制当前方块
        if self.current_shape:
            for y, row in enumerate(self.current_shape['shape']):
                for x, cell in enumerate(row):
                    if cell:
                        self.draw_block(self.current_shape['x'] + x,
                                      self.current_shape['y'] + y,
                                      self.current_shape['color'])

        # 绘制下一个方块预览
        preview_x = GAME_WIDTH + 2
        preview_y = 4
        for y, row in enumerate(self.next_shape['shape']):
            for x, cell in enumerate(row):
                if cell:
                    self.draw_block(preview_x + x, preview_y + y, self.next_shape['color'])

        # 绘制分数
        score_text = self.font.render(f'Score: {self.score}', True, (255,255,255))
        self.screen.blit(score_text, (BLOCK_SIZE*(GAME_WIDTH+2), BLOCK_SIZE*2))

        pygame.display.update()

    def run(self):
        """游戏主循环"""
        while True:
            self.clock.tick(60)

            # 处理事件
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    pygame.quit()
                    return
                elif event.type == pygame.KEYDOWN:
                    if self.game_over:
                        self.reset_game()
                    else:
                        if event.key == pygame.K_LEFT:
                            if not self.check_collision(self.current_shape, -1):
                                self.current_shape['x'] -= 1
                        elif event.key == pygame.K_RIGHT:
                            if not self.check_collision(self.current_shape, 1):
                                self.current_shape['x'] += 1
                        elif event.key == pygame.K_DOWN:
                            if not self.check_collision(self.current_shape, 0, 1):
                                self.current_shape['y'] += 1
                        elif event.key == pygame.K_UP:
                            self.rotate_shape()
                        elif event.key == pygame.K_SPACE:  # 快速下落
                            while not self.check_collision(self.current_shape, 0, 1):
                                self.current_shape['y'] += 1
                            self.merge_shape()

            # 自动下落
            if not self.game_over:
                self.fall_counter += 1
                if self.fall_counter >= self.fall_speed:
                    self.fall_counter = 0
                    if not self.check_collision(self.current_shape, 0, 1):
                        self.current_shape['y'] += 1
                    else:
                        self.merge_shape()

            # 绘制界面
            self.draw_game()

            # 游戏结束显示
            if self.game_over:
                text = self.font.render('Game Over! Press Any Key', True, (255,255,255))
                self.screen.blit(text, (BLOCK_SIZE*2, BLOCK_SIZE*8))
                pygame.display.update()

if __name__ == '__main__':
    game = Tetris()
    game.run()

二.运行说明:

1.安装依赖库:

pip install pygame

2.运行游戏:

python tetris.py

三.操作说明:

  1. ← → 键:左右移动方块

  2. ↑ 键:旋转方块

  3. ↓ 键:加速下落

  4. 空格键:直接落到底部

  5. 任意键:游戏结束后重新开始

四. 游戏功能特点:

  • 经典7种方块形状

  • 实时分数统计

  • 下一个方块预览

  • 下落速度随得分增加

  • 游戏结束提示

  • 自适应窗口大小

  • 碰撞检测与边界控制

五.代码结构说明:

  • Tetris 类封装游戏主要逻辑

  • check_collision 方法处理碰撞检测

  • rotate_shape 实现方块旋转

  • merge_shape 处理方块固定和消除行

  • 使用双缓冲技术保证画面流畅

  • 包含完整的游戏状态管理(开始/结束/重置)

六.可以通过修改以下参数自定义游戏:

  • 调整 BLOCK_SIZE 改变方块大小

  • 修改 COLORS 数组改变颜色方案

  • 调整 fall_speed 相关参数改变下落速度

  • 修改 SHAPES 数组添加自定义形状

这个实现保留了经典俄罗斯方块的核心机制,同时代码结构清晰适合学习和扩展。

俄罗斯方块

评论

目录

    关闭