使用Pygame制作“俄罗斯方块”游戏

1. 前言

俄罗斯方块(Tetris) 是一款由方块下落、行消除等核心规则构成的经典益智游戏:

  • 每次从屏幕顶部出现一个随机的方块(由若干小方格组成),玩家可以左右移动或旋转该方块,让它合适地堆叠在底部或其他方块之上。
  • 当某一行被填满时,该行会被消除,并给玩家增加分数。
  • 若方块叠加到顶部无法容纳新的方块,就表示游戏结束。

在本篇中,我们将使用 PythonPygame 来实现一个简化版的俄罗斯方块,主要演示核心流程,帮助你掌握更多 2D 游戏编程的常见技巧。


2. 开发环境

  1. Python 3.x
  2. Pygame:如果尚未安装,请执行
    pip install pygame
    
  3. 支持图形界面的桌面操作系统(Windows、macOS 或大部分 Linux)。

3. 游戏思路与要点

俄罗斯方块主要有以下几个关键逻辑点:

  1. 网格与方块

    • 整个游戏区域可被拆分为若干行列(比如 10 列 × 20 行)。
    • 下落的“方块”通常由四个小方格(称为 Tetromino)组成,常见形状有 I、O、T、S、Z、J、L 七种。
  2. 方块的移动和旋转

    • 在每帧或固定时间间隔,让方块自动向下移动一次。
    • 监听玩家按键:左右移动、加速下落、旋转方块等。
    • 在方块运动前要检测是否与已有方块发生碰撞或超出边界;若无法移动,则保持在原处。
  3. 行检测与消除

    • 每次放置完一个方块后,需要检查游戏网格中是否有某一行被填满(全部不是空)。
    • 若有满行,则消除该行,并将上方的所有行整体下移相应的行数,为玩家增加分数。
  4. 游戏结束检测

    • 当新的方块在顶部生成时,若该区域已被占满而无法容纳,即表示游戏结束。
  5. 随机性与关卡速度

    • 生成方块形状时,通常随机从七种基本形状中选择。
    • 随着分数的提升,可以让方块下落的速度越来越快,增强挑战性。

4. 完整示例代码

以下代码示例仅实现一个简易版本的俄罗斯方块,展示最核心的逻辑。你可以将其保存为 tetris_game.py 并运行,进一步研究与改进。

import pygame
import sys
import random# 初始化 pygame
pygame.init()# --------------------------
# 配置参数
# --------------------------
CELL_SIZE = 30       # 每个网格的像素大小
COLS = 10            # 游戏区域的列数
ROWS = 20            # 游戏区域的行数WINDOW_WIDTH = CELL_SIZE * COLS
WINDOW_HEIGHT = CELL_SIZE * ROWS
FPS = 30             # 帧率# 颜色
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY  = (128, 128, 128)
RED   = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE  = (0, 0, 255)
CYAN  = (0, 255, 255)
YELLOW = (255, 255, 0)
MAGENTA = (255, 0, 255)
ORANGE  = (255, 165, 0)# 为了区分不同形状,定义一个全局形状/颜色映射
SHAPES_COLORS = [([[1, 1, 1, 1]], CYAN),       # I 形 (1行4列)([[1, 1],[1, 1]], YELLOW),          # O 形 (2行2列)([[0, 1, 0],[1, 1, 1]], MAGENTA),      # T 形([[1, 1, 0],[0, 1, 1]], GREEN),        # S 形([[0, 1, 1],[1, 1, 0]], RED),          # Z 形([[1, 0, 0],[1, 1, 1]], BLUE),         # J 形([[0, 0, 1],[1, 1, 1]], ORANGE)        # L 形
]# 创建窗口
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("俄罗斯方块 - Pygame")
clock = pygame.time.Clock()# 字体
font = pygame.font.SysFont("arial", 24)# --------------------------
# 游戏网格
# --------------------------
# 用一个 2D 列表保存网格信息:0 表示空,其他表示对应的颜色
grid = [[0] * COLS for _ in range(ROWS)]def draw_text(surface, text, color, x, y):"""在指定位置绘制文字"""label = font.render(text, True, color)surface.blit(label, (x, y))def draw_grid(surface):"""绘制当前网格状态"""for r in range(ROWS):for c in range(COLS):val = grid[r][c]rect = pygame.Rect(c * CELL_SIZE, r * CELL_SIZE, CELL_SIZE, CELL_SIZE)if val == 0:pygame.draw.rect(surface, BLACK, rect, 0)  # 空 -> 绘制黑色背景pygame.draw.rect(surface, GRAY, rect, 1)   # 网格线else:# 如果 val 非 0,则 val 存储的是颜色pygame.draw.rect(surface, val, rect, 0)pygame.draw.rect(surface, GRAY, rect, 1)def check_lines():"""检测并消除已填满的行,返回消除行数"""full_lines = 0for r in range(ROWS):if 0 not in grid[r]:  # 如果这一行没有空格full_lines += 1# 将该行之上的所有行往下移动for rr in range(r, 0, -1):grid[rr] = grid[rr - 1][:]# 最上面那行设为空grid[0] = [0] * COLSreturn full_linesclass Tetromino:"""表示当前下落的方块包含:shape  -> 形状(一个2D list)color  -> 颜色row, col -> 在grid中的坐标(左上角)"""def __init__(self, shape, color):self.shape = shapeself.color = colorself.row = 0self.col = COLS // 2 - len(shape[0]) // 2def width(self):return len(self.shape[0])def height(self):return len(self.shape)def can_move(self, dr, dc):"""判断方块是否能移动dr, dc"""new_row = self.row + drnew_col = self.col + dcfor r in range(self.height()):for c in range(self.width()):if self.shape[r][c] != 0:rr = new_row + rcc = new_col + c# 判断是否越界if rr < 0 or rr >= ROWS or cc < 0 or cc >= COLS:return False# 判断是否和已有方块重叠if grid[rr][cc] != 0:return Falsereturn Truedef move(self, dr, dc):"""执行移动"""if self.can_move(dr, dc):self.row += drself.col += dcreturn Truereturn Falsedef rotate(self):"""顺时针旋转90度先生成新形状,然后判断是否能放置"""rotated = list(zip(*self.shape[::-1]))  # 转置 + 逆序 可实现顺时针旋转new_shape = [list(row) for row in rotated]# 临时保存原 shapeold_shape = self.shapeself.shape = new_shape# 如果旋转后出界或冲突,则恢复原 shapeif not self.can_move(0, 0):self.shape = old_shapedef lock(self):"""当方块无法继续移动后,锁定到网格"""for r in range(self.height()):for c in range(self.width()):if self.shape[r][c] != 0:grid[self.row + r][self.col + c] = self.colordef new_tetromino():"""随机生成一个新的方块对象"""shape, color = random.choice(SHAPES_COLORS)return Tetromino(shape, color)def is_game_over():"""判断顶端是否已堆满"""for c in range(COLS):if grid[0][c] != 0:return Truereturn Falsedef main():current_piece = new_tetromino()next_piece = new_tetromino()fall_time = 0fall_speed = 0.5  # 每0.5秒下落一格score = 0running = Truewhile running:dt = clock.tick(FPS) / 1000  # 以秒为单位的帧间隔fall_time += dt# 1) 事件处理for event in pygame.event.get():if event.type == pygame.QUIT:running = Falseelif event.type == pygame.KEYDOWN:if event.key == pygame.K_LEFT:current_piece.move(0, -1)elif event.key == pygame.K_RIGHT:current_piece.move(0, 1)elif event.key == pygame.K_DOWN:# 快速下落current_piece.move(1, 0)elif event.key == pygame.K_UP:# 旋转current_piece.rotate()# 2) 自动下落if fall_time >= fall_speed:if not current_piece.move(1, 0):# 不能再下落 -> 锁定到 gridcurrent_piece.lock()# 检查是否有行被消除lines_cleared = check_lines()score += lines_cleared * 10# 判断游戏是否结束if is_game_over():running = Falseelse:# 生成新的方块current_piece = next_piecenext_piece = new_tetromino()fall_time = 0# 3) 绘制screen.fill(BLACK)draw_grid(screen)# 预先“绘制”当前方块(仅在可见区域内)for r in range(current_piece.height()):for c in range(current_piece.width()):if current_piece.shape[r][c] != 0:rr = current_piece.row + rcc = current_piece.col + cif rr >= 0:rect = pygame.Rect(cc * CELL_SIZE, rr * CELL_SIZE, CELL_SIZE, CELL_SIZE)pygame.draw.rect(screen, current_piece.color, rect, 0)pygame.draw.rect(screen, GRAY, rect, 1)draw_text(screen, f"Score: {score}", WHITE, 10, 10)pygame.display.flip()game_over(screen, score)def game_over(surface, score):"""游戏结束画面"""surface.fill(GRAY)draw_text(surface, "Game Over!", WHITE, WINDOW_WIDTH // 2 - 60, WINDOW_HEIGHT // 2 - 30)draw_text(surface, f"Your Score: {score}", WHITE, WINDOW_WIDTH // 2 - 70, WINDOW_HEIGHT // 2 + 10)pygame.display.flip()pygame.time.wait(3000)pygame.quit()sys.exit()if __name__ == "__main__":main()

核心逻辑解析

  1. grid 用于存储当前游戏区域的状态

    • grid[r][c] == 0 表示空格。
    • 其他值表示已经堆积在那儿的方块颜色(例如 (255,0,0) 对应红色等)。
  2. 方块(Tetromino) 类

    • 通过 shape(2D List)和 color 来描述该方块是什么形状、什么颜色。
    • row, col 表示方块左上角在网格坐标系的位置。
    • move(dr, dc) 会先检测移动后是否出界或与其他方块冲突;若可行再更新位置。
    • rotate() 通过矩阵转置 + 逆序实现顺时针旋转;若旋转后冲突,则恢复原状。
    • lock() 在方块无法下落后,将形状“锁定”到 grid 上。
  3. 行消除

    • check_lines() 判断每一行是否已被填满;若是,则把上方的行依次向下移动,并清空最上面的一行。
  4. 自动下落与输入控制

    • 用一个计时器 fall_time 不断累加帧间隔,达到 fall_speed 时让方块往下移动一次。
    • 监听左右键和上下键,实现左右移动、加速下落与旋转。
  5. 生成和切换方块

    • 每次锁定当前方块后,都从预先生成的 next_piece 切换过来,并随机生成下一个 next_piece
    • 这样可以在界面显示“下一块”预览(若想添加此功能,只需在界面上额外绘制 next_piece 的形状)。

5. 运行效果

image.png


6. 总结

通过这篇文章,我们用 Python + Pygame 实现了一个简化版的俄罗斯方块。这个项目涵盖了网格管理、方块碰撞与旋转、行检测与消除等常见的游戏逻辑。在此基础上,你完全可以自行改造并添加各种细节与高级功能,让游戏更贴近于真正的 Tetris。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/11119.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序设计和开发:什么是竞品分析,如何进行竞品分析

一、竞品分析的定义 竞品分析是指对竞争对手的产品进行深入研究和比较&#xff0c;以了解市场动态、发现自身产品的优势和不足&#xff0c;并为产品的设计、开发和营销策略提供参考依据。在小程序设计和开发中&#xff0c;竞品分析可以帮助开发者了解同类型小程序的功能、用户体…

Vue简介

目录 Vue是什么&#xff1f;为什么要使用Vue&#xff1f;Vue的三种加载方式拓展&#xff1a;什么是渐进式框架&#xff1f; Vue是什么&#xff1f; Vue是一套用于构建用户界面的渐进式 JavaScript (主张最少)框架 &#xff0c;开发者只需关注视图层。另一方面&#xff0c;当与…

Linux多路转接poll

Linux多路转接poll 1. poll() poll() 结构包含了要监视的 event 和发生的 event &#xff0c;接口使用比 select() 更方便。且 poll 并没有最大数量限制&#xff08;但是数量过大后性能也是会下降&#xff09;。 2. poll() 的工作原理 poll() 不再需要像 select() 那样自行…

C++【深入底层,手撕vector】

vector是向量的意思&#xff0c;看了vector的底层实现之后&#xff0c;能够很明确的认识到它其实就是我们经常使用的顺序表。在我们的认知中&#xff0c;顺序表会有一个数组、数据的size以及容量的大小。vector作为一个向量容器&#xff0c;它可以存放任意类型的数据。所以在实…

基于FPGA的BT656编解码

概述 BT656全称为“ITU-R BT.656-4”或简称“BT656”,是一种用于数字视频传输的接口标准。它规定了数字视频信号的编码方式、传输格式以及接口电气特性。在物理层面上,BT656接口通常包含10根线(在某些应用中可能略有不同,但标准配置为10根)。这些线分别用于传输视频数据、…

关于系统重构实践的一些思考与总结

文章目录 一、前言二、系统重构的范式1.明确目标和背景2.兼容屏蔽对上层的影响3.设计灰度迁移方案3.1 灰度策略3.2 灰度过程设计3.2.1 case1 业务逻辑变更3.2.2 case2 底层数据变更&#xff08;数据平滑迁移&#xff09;3.2.3 case3 在途新旧流程兼容3.2.4 case4 接口变更3.2.5…

Microsoft Power BI:融合 AI 的文本分析

Microsoft Power BI 是微软推出的一款功能强大的商业智能工具&#xff0c;旨在帮助用户从各种数据源中提取、分析和可视化数据&#xff0c;以支持业务决策和洞察。以下是关于 Power BI 的深度介绍&#xff1a; 1. 核心功能与特点 Power BI 提供了全面的数据分析和可视化功能&…

【机器学习】自定义数据集 ,使用朴素贝叶斯对其进行分类

一、贝叶斯原理 贝叶斯算法是基于贝叶斯公式的&#xff0c;其公式为&#xff1a; 其中叫做先验概率&#xff0c;叫做条件概率&#xff0c;叫做观察概率&#xff0c;叫做后验概率&#xff0c;也是我们求解的结果&#xff0c;通过比较后验概率的大小&#xff0c;将后验概率最大的…

AMS仿真方法

1. 准备好verilog文件。并且准备一份.vc文件&#xff0c;将所有的verilog file的路径全部写在里面。 2. 将verilog顶层导入到virtuoso中&#xff1a; 注意.v只要引入顶层即可。不需要全部引入。实际上顶层里面只要包含端口即可&#xff0c;即便是空的也没事。 引入时会报warni…

OpenAI o3-mini全面解析:最新免费推理模型重磅发布

引言 2025年1月31日&#xff0c;OpenAI重磅发布全新推理模型o3-mini。这款模型作为OpenAI推理系列的最新突破&#xff0c;不仅在性能和性价比方面实现跨越式提升&#xff0c;更是首次全面开放免费使用。这一重大举措彰显了OpenAI在人工智能技术普及和成本优化领域的创新决心。…

文件读写操作

写入文本文件 #include <iostream> #include <fstream>//ofstream类需要包含的头文件 using namespace std;void test01() {//1、包含头文件 fstream//2、创建流对象ofstream fout;/*3、指定打开方式&#xff1a;1.ios::out、ios::trunc 清除文件内容后打开2.ios:…

TensorFlow 示例摄氏度到华氏度的转换(一)

TensorFlow 实现神经网络模型来进行摄氏度到华氏度的转换&#xff0c;可以将其作为一个回归问题来处理。我们可以通过神经网络来拟合这个简单的转换公式。 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与预测 7. 保存与加载模型 …

99.24 金融难点通俗解释:MLF(中期借贷便利)vs LPR(贷款市场报价利率)

目录 0. 承前1. 什么是MLF&#xff1f;1.1 专业解释1.2 通俗解释1.3 MLF的三个关键点&#xff1a; 2. 什么是LPR&#xff1f;2.1 专业解释2.2 通俗解释2.3 LPR的三个关键点&#xff1a; 3. MLF和LPR的关系4. 传导机制4.1 第一步&#xff1a;央行调整MLF4.2 第二步&#xff1a;银…

此虚拟机的处理器所支持的功能不同于保存虚拟机状态的虚拟机的处理器所支持的功能

1.问题&#xff1a;今天记录下自己曾经遇到的一个问题&#xff0c;就是复制别人虚拟机时弹出来的一个报错&#xff1a; 如图&#xff0c;根本原因就在于虚拟机版本的问题&#xff0c;无法对应的上&#xff0c;所以必须升级虚拟机。 2.问题解决&#xff1a; 1.直接点击放弃,此时…

Linux命令入门

Linux命令入门 ls命令 ls命令的作用是列出目录下的内容&#xff0c;语法细节如下: 1s[-a -l -h] [Linux路径] -a -l -h是可选的选项 Linux路径是此命令可选的参数 当不使用选项和参数,直接使用ls命令本体,表示:以平铺形式,列出当前工作目录下的内容 ls命令的选项 -a -a选项&a…

10 Flink CDC

10 Flink CDC 1. CDC是什么2. CDC 的种类3. 传统CDC与Flink CDC对比4. Flink-CDC 案例5. Flink SQL 方式的案例 1. CDC是什么 CDC 是 Change Data Capture&#xff08;变更数据获取&#xff09;的简称。核心思想是&#xff0c;监测并捕获数据库的变动&#xff08;包括数据或数…

【Redis】set 和 zset 类型的介绍和常用命令

1. set 1.1 介绍 set 类型和 list 不同的是&#xff0c;存储的元素是无序的&#xff0c;并且元素不允许重复&#xff0c;Redis 除了支持集合内的增删查改操作&#xff0c;还支持多个集合取交集&#xff0c;并集&#xff0c;差集 1.2 常用命令 命令 介绍 时间复杂度 sadd …

happytime

happytime 一、查壳 无壳&#xff0c;64位 二、IDA分析 1.main 2.cry函数 总体&#xff1a;是魔改的XXTEA加密 在main中可以看到被加密且分段的flag在最后的循环中与V6进行比较&#xff0c;刚好和上面v6数组相同。 所以毫无疑问密文是v6. 而与flag一起进入加密函数的v5就…

【etcd】二进制安装etcd

由于生产服务器不能使用yum 安装 etcd ,或者 安装的etcd 版本比较老&#xff0c;这里介绍一个使用二进制安装的方式。 根据安装文档编写一个下载脚本即可 &#xff1a; 指定 etcd 的版本 提供了两个下载地址 一个 Google 一个 Github&#xff0c; 不过都需要外网 注释掉删除保…

MediaPipe与YOLO已训练模型实现可视化人脸和手势关键点检测

项目首页 - ZiTai_YOLOV11:基于前沿的 MediaPipe 技术与先进的 YOLOv11 预测试模型&#xff0c;精心打造一款强大的实时检测应用。该应用无缝连接摄像头&#xff0c;精准捕捉画面&#xff0c;能即时实现人脸检测、手势识别以及骨骼关键点检测&#xff0c;将检测结果实时、直观地…