关注

Python小游戏实战:打造高颜值俄罗斯方块小游戏

在这里插入图片描述

在这里插入图片描述

Python小游戏实战:打造高颜值俄罗斯方块小游戏

Python小游戏实战:打造高颜值俄罗斯方块小游戏,俄罗斯方块是一款经典的休闲益智游戏,其核心玩法是通过控制下落的方块,使其在游戏区域内拼接成完整的行并消除,从而获得积分。本次实战将使用 Python 结合 pygame 库,开发一款功能完善、界面美观的俄罗斯方块小游戏

在这里插入图片描述

一、前言

    Python作为一门简洁、易读、功能强大的编程语言,其基础语法是入门学习的核心。掌握好基础语法,能为后续的编程实践打下坚实的基础。本文将全面讲解Python3的基础语法知识,适合编程初学者系统学习。Python以其简洁优雅的语法和强大的通用性,成为当今最受欢迎的编程语言。本专栏旨在系统性地带你从零基础入门到精通Python核心。无论你是零基础小白还是希望进阶的专业开发者,都将通过清晰的讲解、丰富的实例和实战项目,逐步掌握语法基础、核心数据结构、函数与模块、面向对象编程、文件处理、主流库应用(如数据分析、Web开发、自动化)以及面向对象高级特性,最终具备独立开发能力和解决复杂问题的思维,高效应对数据分析、人工智能、Web应用、自动化脚本等广泛领域的实际需求。

在这里插入图片描述


在这里插入图片描述

🥇 点击进入Python入门专栏,Python凭借简洁易读的语法,是零基础学习编程的理想选择。本专栏专为初学者设计,系统讲解Python核心基础:变量、数据类型、流程控制、函数、文件操作及常用库入门。通过清晰示例与实用小项目,助你快速掌握编程思维,打下坚实根基,迈出自动化办公、数据分析或Web开发的第一步。

🥇 点击进入Python小游戏实战专栏, 寓教于乐,用Python亲手打造经典小游戏!本专栏通过开发贪吃蛇、飞机大战、猜数字、简易版俄罗斯方块等趣味项目,在实践中掌握Python核心语法、面向对象编程、事件处理、图形界面(如Pygame)等关键技能,将枯燥的代码学习转化为可见的成果,让学习编程充满乐趣与成就感,快速提升实战能力。

🥇 点击进入Python小工具实战专栏,告别重复劳动,用Python打造效率神器!本专栏教你开发文件批量处理、自动邮件通知、简易爬虫、桌面提醒、密码生成器、天气查询等实用小工具。聚焦os、shutil、requests、smtplib、schedule等核心库,通过真实场景案例,快速掌握自动化脚本编写技巧,解放双手,显著提升工作与生活效率,让代码真正服务于你的日常。

🥇 点击进入Python爬虫实战专栏,解锁网络数据宝库!本专栏手把手教你使用Python核心库(如requests、BeautifulSoup、Scrapy)构建高效爬虫。从基础网页解析到动态页面抓取、数据存储(CSV/数据库)、反爬策略应对及IP代理使用,通过实战项目(如电商比价、新闻聚合、图片采集、舆情监控),掌握合法合规获取并利用网络数据的核心技能,让数据成为你的超能力。

🥇 点击进入Python项目实战专栏,告别碎片化学习,挑战真实项目!本专栏精选Web应用开发(Flask/Django)、数据分析可视化、自动化办公系统、简易爬虫框架、API接口开发等综合项目。通过需求分析、架构设计、编码实现、测试部署的全流程,深入掌握工程化开发、代码复用、调试排错与团队协作核心能力,积累高质量作品集,真正具备解决复杂问题的Python实战经验。


✨ 正文开始

我将以Python的pygame库为基础,分步骤教你实现俄罗斯方块小游戏。先介绍开发环境搭建,再依次讲解游戏核心模块、界面绘制、游戏逻辑等,确保每个功能实现都清晰易懂。

Python 实战:打造高颜值俄罗斯方块小游戏

一、项目介绍

俄罗斯方块是一款经典的休闲益智游戏,其核心玩法是通过控制下落的方块,使其在游戏区域内拼接成完整的行并消除,从而获得积分。本次实战将使用 Python 结合 pygame 库,开发一款功能完善、界面美观的俄罗斯方块小游戏,实现如下核心功能:

  1. 实时显示下一个方块的形状,帮助玩家提前规划布局
  2. 支持通过键盘按键旋转方块方向,增加游戏策略性
  3. 实现积分系统,消除行数越多,得分越高
  4. 提供游戏暂停/继续功能,提升游戏体验
  5. 包含游戏开始、结束界面,完善游戏流程

二、开发环境准备

2.1 安装必要库

本次开发主要依赖 pygame 库用于游戏窗口创建、图形绘制和事件监听,安装命令如下:

pip install pygame

2.2 环境要求

  • Python 版本:3.6 及以上
  • 操作系统:Windows、macOS、Linux 均可(pygame 跨平台支持良好)

三、游戏核心模块设计

整个游戏将分为 5 个核心模块,各模块职责如下:

模块名称核心功能
方块类(Tetromino)定义方块的形状、颜色、旋转逻辑
游戏区域类(Board)管理游戏区域网格、方块放置、行消除判断
游戏控制类(Game)整合各模块,处理游戏主循环、事件监听
界面绘制模块绘制游戏区域、下一个方块预览、积分面板
数据管理模块管理游戏分数、等级、游戏状态(开始/暂停/结束)

四、代码实现步骤

4.1 初始化游戏窗口与基础设置

首先创建游戏主文件 tetris.py,完成 pygame 初始化、窗口创建及基础参数设置:

import pygame
import random

# 初始化pygame
pygame.init()

# 游戏常量定义
SCREEN_WIDTH = 400  # 窗口宽度
SCREEN_HEIGHT = 600  # 窗口高度
BLOCK_SIZE = 30  # 方块大小(像素)
BOARD_WIDTH = 10  # 游戏区域列数
BOARD_HEIGHT = 20  # 游戏区域行数

# 颜色定义(使用RGB值,打造清新配色)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)
COLORS = [
    (0, 255, 255),   # 青色
    (0, 0, 255),     # 蓝色
    (255, 165, 0),   # 橙色
    (255, 255, 0),   # 黄色
    (0, 255, 0),     # 绿色
    (128, 0, 128),   # 紫色
    (255, 0, 0)      # 红色
]

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Python 俄罗斯方块")

# 设置字体(用于显示分数、文字)
font = pygame.font.Font(None, 36)
small_font = pygame.font.Font(None, 24)

4.2 实现方块类(Tetromino)

方块是游戏的核心元素,需要定义 7 种基础形状(I、O、T、L、J、S、Z),并实现旋转逻辑:

class Tetromino:
    # 定义7种方块形状(0表示空白,1表示方块)
    SHAPES = [
        [[1, 1, 1, 1]],  # I型
        [[1, 1], [1, 1]],  # O型
        [[0, 1, 0], [1, 1, 1]],  # T型
        [[0, 0, 1], [1, 1, 1]],  # L型
        [[1, 0, 0], [1, 1, 1]],  # J型
        [[0, 1, 1], [1, 1, 0]],  # S型
        [[1, 1, 0], [0, 1, 1]]   # Z型
    ]

    def __init__(self):
        # 随机选择方块形状和颜色
        self.shape = random.choice(self.SHAPES)
        self.color = random.choice(COLORS)
        # 初始位置(居中顶部)
        self.x = BOARD_WIDTH // 2 - len(self.shape[0]) // 2
        self.y = 0

    def rotate(self):
        """旋转方块(矩阵转置)"""
        # 矩阵转置实现旋转效果
        rotated = list(zip(*self.shape[::-1]))
        # 将元组转换为列表
        self.shape = [list(row) for row in rotated]

    def get_blocks(self):
        """获取方块的所有方块坐标(相对于游戏区域)"""
        blocks = []
        for y, row in enumerate(self.shape):
            for x, cell in enumerate(row):
                if cell:
                    blocks.append((self.x + x, self.y + y))
        return blocks

4.3 实现游戏区域类(Board)

游戏区域负责管理方块的放置、行消除、碰撞检测等核心逻辑:

class Board:
    def __init__(self):
        # 初始化游戏区域网格(BOARD_HEIGHT行,BOARD_WIDTH列,0表示空白)
        self.grid = [[0 for _ in range(BOARD_WIDTH)] for _ in range(BOARD_HEIGHT)]
        self.score = 0  # 游戏分数
        self.level = 1  # 游戏等级
        self.lines_cleared = 0  # 已消除行数

    def check_collision(self, tetromino, dx=0, dy=0):
        """检测方块移动后的碰撞(边界碰撞或与已放置方块碰撞)"""
        for x, y in tetromino.get_blocks():
            new_x = x + dx
            new_y = y + dy
            # 检测边界碰撞
            if new_x < 0 or new_x >= BOARD_WIDTH:
                return True
            if new_y >= BOARD_HEIGHT:
                return True
            # 检测与已放置方块碰撞(忽略y<0的情况,方块从顶部生成时可能暂时超出区域)
            if new_y >= 0 and self.grid[new_y][new_x] != 0:
                return True
        return False

    def lock_tetromino(self, tetromino):
        """将方块锁定到游戏区域(方块无法继续下落时)"""
        for x, y in tetromino.get_blocks():
            if y >= 0:  # 只锁定在游戏区域内的部分
                self.grid[y][x] = tetromino.color
        # 锁定后检查是否有可消除的行
        self.clear_lines()

    def clear_lines(self):
        """消除完整的行,并更新分数和等级"""
        lines_cleared = 0
        new_grid = []
        for row in self.grid:
            if all(cell != 0 for cell in row):
                # 完整行,不加入新网格(即消除)
                lines_cleared += 1
            else:
                new_grid.append(row)
        # 在顶部补充空白行(消除行数等于新增空白行数)
        for _ in range(lines_cleared):
            new_grid.insert(0, [0 for _ in range(BOARD_WIDTH)])
        # 更新游戏区域
        self.grid = new_grid
        # 更新分数(消除1行100分,2行300分,3行500分,4行800分,鼓励消除多行)
        score_map = {1: 100, 2: 300, 3: 500, 4: 800}
        self.score += score_map.get(lines_cleared, 0) * self.level
        # 更新已消除行数和等级(每消除10行升1级)
        self.lines_cleared += lines_cleared
        self.level = self.lines_cleared // 10 + 1

    def is_game_over(self, tetromino):
        """判断游戏是否结束(新生成的方块刚出现就碰撞)"""
        return self.check_collision(tetromino)

4.4 实现游戏控制类(Game)

整合各模块,处理游戏主循环、事件监听、游戏状态管理:

class TetrisGame:
    def __init__(self):
        self.board = Board()
        self.current_tetromino = Tetromino()  # 当前下落的方块
        self.next_tetromino = Tetromino()  # 下一个方块(预览)
        self.game_over = False  # 游戏结束标志
        self.paused = False  # 游戏暂停标志
        self.fall_time = 0  # 方块下落计时
        self.fall_speed = 1000  # 方块下落速度(毫秒,值越小越快)

    def switch_tetromino(self):
        """切换当前方块和下一个方块(当前方块锁定后)"""
        self.current_tetromino = self.next_tetromino
        self.next_tetromino = Tetromino()
        # 检查游戏是否结束
        if self.board.is_game_over(self.current_tetromino):
            self.game_over = True

    def handle_events(self):
        """处理键盘事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False  # 退出游戏
            if event.type == pygame.KEYDOWN:
                if self.game_over:
                    # 游戏结束时按R键重新开始
                    if event.key == pygame.K_r:
                        self.__init__()
                else:
                    # 按P键暂停/继续游戏
                    if event.key == pygame.K_p:
                        self.paused = not self.paused
                    if not self.paused:
                        # 左移
                        if event.key == pygame.K_LEFT and not self.board.check_collision(self.current_tetromino, dx=-1):
                            self.current_tetromino.x -= 1
                        # 右移
                        if event.key == pygame.K_RIGHT and not self.board.check_collision(self.current_tetromino, dx=1):
                            self.current_tetromino.x += 1
                        # 下移(加速下落)
                        if event.key == pygame.K_DOWN and not self.board.check_collision(self.current_tetromino, dy=1):
                            self.current_tetromino.y += 1
                            self.board.score += 1  # 下移加速得分
                        # 旋转(上键或空格键)
                        if event.key in (pygame.K_UP, pygame.K_SPACE):
                            self.current_tetromino.rotate()
                            # 如果旋转后碰撞,恢复原状
                            if self.board.check_collision(self.current_tetromino):
                                self.current_tetromino.rotate()
                                self.current_tetromino.rotate()
                                self.current_tetromino.rotate()
        return True

    def update(self, delta_time):
        """更新游戏状态(方块自动下落)"""
        if not self.game_over and not self.paused:
            self.fall_time += delta_time
            # 根据等级调整下落速度(等级越高,速度越快)
            adjusted_speed = self.fall_speed - (self.board.level - 1) * 50
            adjusted_speed = max(adjusted_speed, 200)  # 最低速度限制
            # 达到下落时间,自动下移
            if self.fall_time >= adjusted_speed:
                if not self.board.check_collision(self.current_tetromino, dy=1):
                    self.current_tetromino.y += 1
                else:
                    # 无法下移,锁定当前方块并切换新方块
                    self.board.lock_tetromino(self.current_tetromino)
                    self.switch_tetromino()
                self.fall_time = 0

    def draw(self):
        """绘制游戏界面"""
        # 填充背景色
        screen.fill(GRAY)

        # 绘制游戏区域边框
        board_x = (SCREEN_WIDTH - BOARD_WIDTH * BLOCK_SIZE) // 2  # 游戏区域居中
        board_y = 50  # 游戏区域顶部距离
        pygame.draw.rect(screen, WHITE, (board_x - 2, board_y - 2, BOARD_WIDTH * BLOCK_SIZE + 4, BOARD_HEIGHT * BLOCK_SIZE + 4), 2)

        # 绘制游戏区域网格和已放置的方块
        for y in range(BOARD_HEIGHT):
            for x in range(BOARD_WIDTH):
                color = self.board.grid[y][x]
                if color != 0:
                    pygame.draw.rect(
                        screen,
                        color,
                        (board_x + x * BLOCK_SIZE + 1, board_y + y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2)
                    )

        # 绘制当前下落的方块
        for x, y in self.current_tetromino.get_blocks():
            if y >= 0:  # 只绘制在游戏区域内的部分
                pygame.draw.rect(
                    screen,
                    self.current_tetromino.color,
                    (board_x + x * BLOCK_SIZE + 1, board_y + y * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2)
                )

        # 绘制下一个方块预览面板
        next_x = board_x + BOARD_WIDTH * BLOCK_SIZE + 30  # 预览面板在游戏区域右侧
        next_y = board_y + 100
        # 绘制预览面板边框
        pygame.draw.rect(screen, WHITE, (next_x - 2, next_y - 2, 100, 100), 2)
        # 绘制"下一个"文字
        next_text = small_font.render("下一个", True, WHITE)
        screen.blit(next_text, (next_x + 20, next_y - 30))
        # 绘制下一个方块
        for x, y in self.next_tetromino.get_blocks():
            pygame.draw.rect(
                screen,
                self.next_tetromino.color,
                (next_x + (x - 1) * BLOCK_SIZE + 1, next_y + (y) * BLOCK_SIZE + 1, BLOCK_SIZE - 2, BLOCK_SIZE - 2)
            )

        # 绘制分数、等级信息
        score_text = font.render(f"分数: {self.board.score}", True, WHITE)
        screen.blit(score_text, (30, 20))
        level_text = font.render(f"等级: {self.board.level}", True, WHITE)
        screen.blit(level_text, (SCREEN_WIDTH - 150, 20))

        # 绘制暂停提示
        if self.paused:
            pause_text = font.render("暂停 (P键继续)", True, (255, 0, 0))
            screen.blit(pause_text, (SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2))

        # 绘制游戏结束提示
        if self.game_over:
            game_over_text = font.render("游戏结束", True, (255, 0, 0))
            restart_text = small_font.render("按R键重新开始", True, WHITE)
            screen.blit(game_over_text, (SCREEN_WIDTH // 2 - 70, SCREEN_HEIGHT // 2 - 50))
            screen.blit(restart_text, (SCREEN_WIDTH // 2 - 80, SCREEN_HEIGHT // 2))

        # 更新显示
        pygame.display.flip()

    def run(self):
        """游戏主循环"""
        clock = pygame.time.Clock()
        running = True
        while running:
            delta_time = clock.tick(60)  # 控制帧率为60FPS
            running = self.handle_events()  # 处理事件
            self.update(delta_time)  # 更新游戏状态
            self.draw()  # 绘制界面
        pygame.quit()

4.5 完整代码和运行效果

import pygame
import random
import sys

# 初始化pygame
pygame.init()

# 确保中文显示正常
pygame.font.init()
default_font = pygame.font.get_default_font()  # 获取系统默认字体

# 游戏常量定义
SCREEN_WIDTH = 500  # 进一步增加窗口宽度
SCREEN_HEIGHT = 680  # 进一步增加窗口高度
BLOCK_SIZE = 28  # 略微减小方块大小,增加显示空间
BOARD_WIDTH = 10  # 游戏区域列数
BOARD_HEIGHT = 20  # 游戏区域行数

# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)
LIGHT_GRAY = (200, 200, 200)
COLORS = [
    (0, 255, 255),  # 青色
    (0, 0, 255),  # 蓝色
    (255, 165, 0),  # 橙色
    (255, 255, 0),  # 黄色
    (0, 255, 0),  # 绿色
    (128, 0, 128),  # 紫色
    (255, 0, 0)  # 红色
]

# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Python 俄罗斯方块")

# 设置字体(确保中文正常显示)
try:
    # 尝试加载中文字体
    font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "SimSun"], 36)
    small_font = pygame.font.SysFont(["SimHei", "Microsoft YaHei", "SimSun"], 24)
except:
    # 加载失败时使用默认字体
    font = pygame.font.Font(default_font, 36)
    small_font = pygame.font.Font(default_font, 24)


class Tetromino:
    # 定义7种方块形状
    SHAPES = [
        [[1, 1, 1, 1]],  # I型
        [[1, 1], [1, 1]],  # O型
        [[0, 1, 0], [1, 1, 1]],  # T型
        [[0, 0, 1], [1, 1, 1]],  # L型
        [[1, 0, 0], [1, 1, 1]],  # J型
        [[0, 1, 1], [1, 1, 0]],  # S型
        [[1, 1, 0], [0, 1, 1]]  # Z型
    ]

    def __init__(self):
        self.shape = random.choice(self.SHAPES)
        self.color = random.choice(COLORS)
        self.x = BOARD_WIDTH // 2 - len(self.shape[0]) // 2
        self.y = 0

    def rotate(self):
        """旋转方块(矩阵转置)"""
        rotated = list(zip(*self.shape[::-1]))
        self.shape = [list(row) for row in rotated]

    def get_blocks(self):
        """获取方块的所有方块坐标"""
        blocks = []
        for y, row in enumerate(self.shape):
            for x, cell in enumerate(row):
                if cell:
                    blocks.append((self.x + x, self.y + y))
        return blocks


class Board:
    def __init__(self):
        self.grid = [[0 for _ in range(BOARD_WIDTH)] for _ in range(BOARD_HEIGHT)]
        self.score = 0
        self.level = 1
        self.lines_cleared = 0

    def check_collision(self, tetromino, dx=0, dy=0):
        """检测碰撞"""
        for x, y in tetromino.get_blocks():
            new_x = x + dx
            new_y = y + dy
            if new_x < 0 or new_x >= BOARD_WIDTH:
                return True
            if new_y >= BOARD_HEIGHT:
                return True
            if new_y >= 0 and self.grid[new_y][new_x] != 0:
                return True
        return False

    def lock_tetromino(self, tetromino):
        """锁定方块到游戏区域"""
        for x, y in tetromino.get_blocks():
            if y >= 0:
                self.grid[y][x] = tetromino.color
        self.clear_lines()

    def clear_lines(self):
        """消除完整行并更新分数"""
        lines_cleared = 0
        new_grid = []
        for row in self.grid:
            if all(cell != 0 for cell in row):
                lines_cleared += 1
            else:
                new_grid.append(row)

        for _ in range(lines_cleared):
            new_grid.insert(0, [0 for _ in range(BOARD_WIDTH)])

        self.grid = new_grid

        # 分数计算
        score_map = {1: 100, 2: 300, 3: 500, 4: 800}
        self.score += score_map.get(lines_cleared, 0) * self.level
        self.lines_cleared += lines_cleared
        self.level = self.lines_cleared // 10 + 1

    def is_game_over(self, tetromino):
        """判断游戏是否结束"""
        return self.check_collision(tetromino)


class TetrisGame:
    def __init__(self):
        # 重新初始化游戏状态
        self.board = Board()
        self.current_tetromino = Tetromino()
        self.next_tetromino = Tetromino()
        self.game_over = False
        self.paused = False
        self.fall_time = 0
        self.fall_speed = 1000  # 毫秒
        self.move_delay = 150  # 按键连续移动的延迟(毫秒)
        self.last_move_time = 0  # 上次移动时间

    def reset_game(self):
        """重置游戏状态(解决重新开始问题)"""
        self.__init__()  # 重新初始化所有属性

    def switch_tetromino(self):
        """切换到下一个方块"""
        self.current_tetromino = self.next_tetromino
        self.next_tetromino = Tetromino()
        if self.board.is_game_over(self.current_tetromino):
            self.game_over = True

    def handle_continuous_moves(self, delta_time):
        """处理持续按键的移动"""
        if self.game_over or self.paused:
            return

        self.last_move_time += delta_time

        # 只有达到延迟时间才处理连续移动
        if self.last_move_time < self.move_delay:
            return

        keys = pygame.key.get_pressed()

        # 左移
        if keys[pygame.K_LEFT] and not self.board.check_collision(self.current_tetromino, dx=-1):
            self.current_tetromino.x -= 1
            self.last_move_time = 0

        # 右移
        if keys[pygame.K_RIGHT] and not self.board.check_collision(self.current_tetromino, dx=1):
            self.current_tetromino.x += 1
            self.last_move_time = 0

        # 下移(快速下落)
        if keys[pygame.K_DOWN] and not self.board.check_collision(self.current_tetromino, dy=1):
            self.current_tetromino.y += 1
            self.board.score += 1  # 加速下落得分
            self.last_move_time = 0

    def handle_events(self):
        """处理一次性按键事件"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return False

            if event.type == pygame.KEYDOWN:
                # 无论游戏状态如何,R键都可以重新开始
                if event.key == pygame.K_r:
                    self.reset_game()
                    return True

                if self.game_over:
                    return True

                # 暂停/继续游戏
                if event.key == pygame.K_p:
                    self.paused = not self.paused

                if not self.paused:
                    # 旋转(上键或空格键)
                    if event.key in (pygame.K_UP, pygame.K_SPACE):
                        self.current_tetromino.rotate()
                        # 旋转碰撞检测
                        if self.board.check_collision(self.current_tetromino):
                            # 恢复原状(旋转3次回到原来的方向)
                            for _ in range(3):
                                self.current_tetromino.rotate()
        return True

    def update(self, delta_time):
        """更新游戏状态"""
        if not self.game_over and not self.paused:
            # 处理连续按键移动
            self.handle_continuous_moves(delta_time)

            # 方块自动下落
            self.fall_time += delta_time
            adjusted_speed = max(self.fall_speed - (self.board.level - 1) * 50, 200)

            if self.fall_time >= adjusted_speed:
                if not self.board.check_collision(self.current_tetromino, dy=1):
                    self.current_tetromino.y += 1
                else:
                    self.board.lock_tetromino(self.current_tetromino)
                    self.switch_tetromino()
                self.fall_time = 0

    def draw(self):
        """绘制游戏界面"""
        screen.fill(GRAY)

        # 计算游戏区域位置(左侧放置,留出右侧足够空间)
        board_x = 30  # 左侧留出30像素
        board_y = 50

        # 绘制游戏区域边框
        pygame.draw.rect(screen, WHITE,
                         (board_x - 2, board_y - 2,
                          BOARD_WIDTH * BLOCK_SIZE + 4,
                          BOARD_HEIGHT * BLOCK_SIZE + 4), 2)

        # 绘制已放置的方块
        for y in range(BOARD_HEIGHT):
            for x in range(BOARD_WIDTH):
                color = self.board.grid[y][x]
                if color != 0:
                    pygame.draw.rect(
                        screen,
                        color,
                        (board_x + x * BLOCK_SIZE + 1,
                         board_y + y * BLOCK_SIZE + 1,
                         BLOCK_SIZE - 2, BLOCK_SIZE - 2)
                    )

        # 绘制当前方块
        for x, y in self.current_tetromino.get_blocks():
            if y >= 0:
                pygame.draw.rect(
                    screen,
                    self.current_tetromino.color,
                    (board_x + x * BLOCK_SIZE + 1,
                     board_y + y * BLOCK_SIZE + 1,
                     BLOCK_SIZE - 2, BLOCK_SIZE - 2)
                )

        # 右侧信息面板 - 确保有足够空间
        panel_x = board_x + BOARD_WIDTH * BLOCK_SIZE + 40  # 与游戏区分开40像素
        panel_y = board_y

        # 绘制下一个方块预览
        next_title = small_font.render("下一个", True, WHITE)
        screen.blit(next_title, (panel_x, panel_y))

        # 下一个方块预览区域
        preview_area_size = 140
        pygame.draw.rect(screen, WHITE,
                         (panel_x - 2, panel_y + 30 - 2,
                          preview_area_size, preview_area_size), 2)

        # 计算下一个方块的预览位置(居中显示)
        next_shape_height = len(self.next_tetromino.shape)
        next_shape_width = len(self.next_tetromino.shape[0])
        preview_offset_x = (preview_area_size - next_shape_width * BLOCK_SIZE) // 2
        preview_offset_y = (preview_area_size - next_shape_height * BLOCK_SIZE) // 2

        for x, y in self.next_tetromino.get_blocks():
            pygame.draw.rect(
                screen,
                self.next_tetromino.color,
                (panel_x + preview_offset_x + (x - self.next_tetromino.x) * BLOCK_SIZE + 1,
                 panel_y + 30 + preview_offset_y + (y - self.next_tetromino.y) * BLOCK_SIZE + 1,
                 BLOCK_SIZE - 2, BLOCK_SIZE - 2)
            )

        # 绘制分数信息
        score_title = small_font.render("分数", True, WHITE)
        score_text = font.render(str(self.board.score), True, WHITE)
        screen.blit(score_title, (panel_x, panel_y + 200))
        screen.blit(score_text, (panel_x, panel_y + 230))

        # 绘制等级信息
        level_title = small_font.render("等级", True, WHITE)
        level_text = font.render(str(self.board.level), True, WHITE)
        screen.blit(level_title, (panel_x, panel_y + 280))
        screen.blit(level_text, (panel_x, panel_y + 310))

        # 绘制已消除行数
        lines_title = small_font.render("消除行数", True, WHITE)
        lines_text = font.render(str(self.board.lines_cleared), True, WHITE)
        screen.blit(lines_title, (panel_x, panel_y + 360))
        screen.blit(lines_text, (panel_x, panel_y + 390))

        # 绘制操作说明
        controls_title = small_font.render("操作说明", True, WHITE)
        screen.blit(controls_title, (panel_x, panel_y + 440))

        controls = [
            "← → 移动",
            "↑(空格)旋转",
            "↓ 加速下落",
            "P 暂停/继续",
            "R 重新开始"
        ]

        for i, text in enumerate(controls):
            control_text = small_font.render(text, True, LIGHT_GRAY)
            screen.blit(control_text, (panel_x, panel_y + 470 + i * 30))

        # 绘制暂停提示
        if self.paused:
            s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
            s.fill((0, 0, 0, 128))  # 半透明黑色遮罩
            screen.blit(s, (0, 0))

            pause_text = font.render("暂停中", True, (255, 0, 0))
            continue_text = small_font.render("按P键继续", True, WHITE)

            screen.blit(pause_text, (SCREEN_WIDTH // 2 - pause_text.get_width() // 2,
                                     SCREEN_HEIGHT // 2 - 30))
            screen.blit(continue_text, (SCREEN_WIDTH // 2 - continue_text.get_width() // 2,
                                        SCREEN_HEIGHT // 2 + 20))

        # 绘制游戏结束提示
        if self.game_over:
            s = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
            s.fill((0, 0, 0, 128))  # 半透明黑色遮罩
            screen.blit(s, (0, 0))

            over_text = font.render("游戏结束", True, (255, 0, 0))
            restart_text = small_font.render("按R键重新开始", True, WHITE)

            screen.blit(over_text, (SCREEN_WIDTH // 2 - over_text.get_width() // 2,
                                    SCREEN_HEIGHT // 2 - 50))
            screen.blit(restart_text, (SCREEN_WIDTH // 2 - restart_text.get_width() // 2,
                                       SCREEN_HEIGHT // 2))
            final_score_text = small_font.render(f"最终分数: {self.board.score}", True, WHITE)
            screen.blit(final_score_text, (SCREEN_WIDTH // 2 - final_score_text.get_width() // 2,
                                           SCREEN_HEIGHT // 2 + 40))

        pygame.display.flip()

    def run(self):
        """游戏主循环"""
        clock = pygame.time.Clock()
        running = True
        while running:
            delta_time = clock.tick(60)  # 60 FPS
            running = self.handle_events()
            self.update(delta_time)
            self.draw()

        pygame.quit()
        sys.exit()


if __name__ == "__main__":
    game = TetrisGame()
    game.run()

运行效果:

在这里插入图片描述

暂停效果:

在这里插入图片描述

4.6 启动游戏

在文件末尾添加游戏启动代码:

if __name__ == "__main__":
    game = TetrisGame()
    game.run()

五、游戏功能测试与操作说明

5.1 运行游戏

执行 python tetris.py 即可启动游戏,游戏启动后将显示初始界面,包含游戏区域、下一个方块预览、分数和等级信息。

5.2 操作指南

按键功能
左箭头方块向左移动
右箭头方块向右移动
下箭头方块加速下落(获得额外分数)
上箭头/空格键旋转方块
P键暂停/继续游戏
R键游戏结束后重新开始
关闭窗口按钮退出游戏

5.3 功能验证

  1. 下一个方块预览:游戏右侧面板下面是俄罗斯方块游戏的完整代码,整合了之前介绍的所有功能,包括方块旋转、下一个方块预览、积分系统和暂停功能等:

代码说明

这个完整的俄罗斯方块游戏代码包含以下核心组件:

  1. 常量定义:设置了游戏窗口大小、方块尺寸、颜色方案等基础参数
  2. Tetromino类:管理方块的形状、颜色和旋转逻辑
  3. Board类:处理游戏区域的网格管理、碰撞检测、行消除和分数计算
  4. TetrisGame类:游戏主控制器,负责事件处理、游戏状态更新和界面绘制

如何运行

  1. 确保已安装pygame库:pip install pygame
  2. 将代码保存为tetris.py
  3. 运行命令:python tetris.py

游戏操作简单直观,通过方向键控制方块移动和旋转,P键暂停游戏,游戏结束后按R键重新开始。随着等级提升,方块下落速度会逐渐加快,增加游戏挑战性。

🔥🔥🔥 相关热门书籍推荐:

书名说明
在这里插入图片描述讲解 Python 中贝叶斯建模计算,理论与实践结合,适合数据科学领域学习贝叶斯方法的读者。 🥇 点击购买
在这里插入图片描述专注 Python 高性能技术,助力高效处理大数据集,提升编码与数据分析效率。 🥇 点击购买
在这里插入图片描述依托 PyTorch 和 Google Colab,深入深度学习核心,兼具理论与实践,适合学习者进阶。 🥇 点击购买

附录:扩展学习资源

  1. 官方资源
  2. 本专栏特色资源
    • 代码资源仓库:CSDN专属资源在线获取
    • 海量Python教程:关注公众号:xcLeigh,获取网盘地址
    • 一对一答疑:添加微信与博主在线沟通(备注“Python专栏”

联系博主

    xcLeigh 博主全栈领域优质创作者,博客专家,目前,活跃在CSDN、微信公众号、小红书、知乎、掘金、快手、思否、微博、51CTO、B站、腾讯云开发者社区、阿里云开发者社区等平台,全网拥有几十万的粉丝,全网统一IP为 xcLeigh。希望通过我的分享,让大家能在喜悦的情况下收获到有用的知识。主要分享编程、开发工具、算法、技术学习心得等内容。很多读者评价他的文章简洁易懂,尤其对于一些复杂的技术话题,他能通过通俗的语言来解释,帮助初学者更好地理解。博客通常也会涉及一些实践经验,项目分享以及解决实际开发中遇到的问题。如果你是开发领域的初学者,或者在学习一些新的编程语言或框架,关注他的文章对你有很大帮助。

    亲爱的朋友,无论前路如何漫长与崎岖,都请怀揣梦想的火种,因为在生活的广袤星空中,总有一颗属于你的璀璨星辰在熠熠生辉,静候你抵达。

     愿你在这纷繁世间,能时常收获微小而确定的幸福,如春日微风轻拂面庞,所有的疲惫与烦恼都能被温柔以待,内心永远充盈着安宁与慰藉。

    至此,文章已至尾声,而您的故事仍在续写,不知您对文中所叙有何独特见解?期待您在心中与我对话,开启思想的新交流。


     💞 关注博主 🌀 带你实现畅游前后端!

     🏰 大屏可视化 🌀 带你体验酷炫大屏!

     💯 神秘个人简介 🌀 带你体验不一样得介绍!

     🥇 从零到一学习Python 🌀 带你玩转Python技术流!

     🏆 前沿应用深度测评 🌀 前沿AI产品热门应用在线等你来发掘!

     💦 :本文撰写于CSDN平台,作者:xcLeigh所有权归作者所有)https://xcleigh.blog.csdn.net/,如果相关下载没有跳转,请查看这个地址,相关链接没有跳转,皆是抄袭本文,转载请备注本文原地址。


在这里插入图片描述

     📣 亲,码字不易,动动小手,欢迎 点赞 ➕ 收藏,如 🈶 问题请留言(或者关注下方公众号,看见后第一时间回复,还有海量编程资料等你来领!),博主看见后一定及时给您答复 💌💌💌

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/weixin_43151418/article/details/151932574

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--