news 2026/7/11 21:36:26

【游戏开发入门】用python实现俄罗斯方块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【游戏开发入门】用python实现俄罗斯方块

俄罗斯方块 Python (Pygame)

首先,给代码:

import pygame import random # 基础配置 BLOCK_SIZE = 30 GRID_WIDTH = 10 GRID_HEIGHT = 20 SCREEN_W = BLOCK_SIZE * (GRID_WIDTH + 6) SCREEN_H = BLOCK_SIZE * GRID_HEIGHT # 方块形状定义 SHAPES = [ [[1,1,1,1]], [[1,1],[1,1]], [[0,1,0],[1,1,1]], [[1,0,0],[1,1,1]], [[0,0,1],[1,1,1]], [[1,1,0],[0,1,1]], [[0,1,1],[1,1,0]] ] COLORS = [(0,255,255),(255,255,0),(128,0,255),(0,0,255),(255,165,0),(0,255,0),(255,0,0)] class Tetris: def __init__(self): pygame.init() self.screen = pygame.display.set_mode((SCREEN_W, SCREEN_H)) pygame.display.set_caption("俄罗斯方块") self.clock = pygame.time.Clock() self.font = pygame.font.SysFont(None, 36) self.grid = [[(0,0,0) for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)] self.game_over = False self.score = 0 self.spawn_new() def spawn_new(self): self.shape_idx = random.randint(0, len(SHAPES)-1) self.shape = SHAPES[self.shape_idx] self.color = COLORS[self.shape_idx] self.x = GRID_WIDTH // 2 - len(self.shape[0])//2 self.y = 0 if self.check_collision(): self.game_over = True def check_collision(self, dx=0, dy=0, rot=None): mat = self.shape if rot is None else rot for yi, row in enumerate(mat): for xi, val in enumerate(row): if val: nx = self.x + xi + dx ny = self.y + yi + dy if nx <0 or nx >= GRID_WIDTH or ny >= GRID_HEIGHT: return True if ny >=0 and self.grid[ny][nx] != (0,0,0): return True return False def lock_block(self): for yi, row in enumerate(self.shape): for xi, val in enumerate(row): if val: self.grid[self.y+yi][self.x+xi] = self.color self.clear_lines() self.spawn_new() def clear_lines(self): lines = 0 for y in range(GRID_HEIGHT-1, -1, -1): if all(c != (0,0,0) for c in self.grid[y]): lines +=1 for yy in range(y,0,-1): self.grid[yy] = self.grid[yy-1].copy() self.grid[0] = [(0,0,0)]*GRID_WIDTH self.score += lines * 100 def rotate(self): # 矩阵旋转 r = list(zip(*self.shape[::-1])) r = [list(row) for row in r] if not self.check_collision(rot=r): self.shape = r def draw(self): self.screen.fill((20,20,20)) # 网格 for y in range(GRID_HEIGHT): for x in range(GRID_WIDTH): c = self.grid[y][x] rect = pygame.Rect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1) pygame.draw.rect(self.screen, c, rect) # 当前方块 for yi, row in enumerate(self.shape): for xi, val in enumerate(row): if val: px = (self.x + xi)*BLOCK_SIZE py = (self.y + yi)*BLOCK_SIZE r = pygame.Rect(px, py, BLOCK_SIZE-1, BLOCK_SIZE-1) pygame.draw.rect(self.screen, self.color, r) # 分数 text = self.font.render(f"Score: {self.score}", True, (255,255,255)) self.screen.blit(text, (GRID_WIDTH*BLOCK_SIZE + 10, 50)) if self.game_over: over = self.font.render("Game Over", True, (255,0,0)) self.screen.blit(over, (GRID_WIDTH*BLOCK_SIZE + 10, 100)) pygame.display.update() def run(self): fall_timer = 0 fall_speed = 500 while True: dt = self.clock.tick(60) fall_timer += dt for e in pygame.event.get(): if e.type == pygame.QUIT: return if e.type == pygame.KEYDOWN and not self.game_over: if e.key == pygame.K_LEFT and not self.check_collision(dx=-1): self.x -=1 if e.key == pygame.K_RIGHT and not self.check_collision(dx=1): self.x +=1 if e.key == pygame.K_DOWN and not self.check_collision(dy=1): self.y +=1 if e.key == pygame.K_UP: self.rotate() # 自动下落 if fall_timer >= fall_speed and not self.game_over: if self.check_collision(dy=1): self.lock_block() else: self.y +=1 fall_timer = 0 self.draw() if __name__ == "__main__": game = Tetris() game.run()

操作说明

  • 左右方向键:左右移动方块
  • 下方向键:快速下移
  • 上方向键:旋转方块
  • 关闭窗口退出游戏

功能包含

  1. 7 种标准俄罗斯方块、不同颜色
  2. 自动下落、行消除、计分系统
  3. 碰撞检测、方块落地锁定
  4. 填满顶部游戏结束判定
  5. 简单 UI 分数展示

俄罗斯方块 Python (Pygame) 代码逐段完整讲解

一、前置依赖与全局常量

import pygame import random # 基础配置 BLOCK_SIZE = 30 # 每个方块像素大小 GRID_WIDTH = 10 # 游戏区域横向格子数(标准10列) GRID_HEIGHT = 20 # 游戏区域纵向格子数(标准20行) SCREEN_W = BLOCK_SIZE * (GRID_WIDTH + 6) # 窗口总宽,右侧留出分数显示区域 SCREEN_H = BLOCK_SIZE * GRID_HEIGHT # 窗口总高

作用:定义画布、格子尺寸,后续所有绘制、坐标计算都复用这几个常量,方便统一修改。

# 7种方块形状矩阵,1代表有方块,0代表空 SHAPES = [ [[1,1,1,1]], # I长条 [[1,1],[1,1]], # O正方形 [[0,1,0],[1,1,1]], # T型 [[1,0,0],[1,1,1]], # L型 [[0,0,1],[1,1,1]], # 反L [[1,1,0],[0,1,1]], # Z [[0,1,1],[1,1,0]] # 反Z ] # 对应7种方块的RGB颜色 COLORS = [(0,255,255),(255,255,0),(128,0,255),(0,0,255),(255,165,0),(0,255,0),(255,0,0)]

核心设计:用二维矩阵描述方块轮廓,一一对应颜色,随机生成时直接配对。

二、游戏主类Tetris

所有游戏状态、逻辑、绘制全部封装在类内,结构清晰。

1. 构造函数__init__初始化游戏

def __init__(self): pygame.init() # 初始化pygame底层 self.screen = pygame.display.set_mode((SCREEN_W, SCREEN_H)) # 创建窗口 pygame.display.set_caption("俄罗斯方块") self.clock = pygame.time.Clock() # 控制帧率 self.font = pygame.font.SysFont(None, 36) # 文字字体 # 游戏网格:二维列表,存储每个格子颜色,初始全黑(0,0,0) self.grid = [[(0,0,0) for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)] self.game_over = False # 游戏结束标记 self.score = 0 # 得分 self.spawn_new() # 生成第一个方块
  • self.grid:游戏场地本体,落地的方块永久存在这里;
  • spawn_new():调用生成新方块方法,开局生成第一块。

2.spawn_new()生成新方块

def spawn_new(self): self.shape_idx = random.randint(0, len(SHAPES)-1) # 随机选一种方块 self.shape = SHAPES[self.shape_idx] # 取出形状矩阵 self.color = COLORS[self.shape_idx] # 匹配颜色 self.x = GRID_WIDTH // 2 - len(self.shape[0])//2 # X坐标:水平居中生成 self.y = 0 # Y坐标:顶部生成 # 生成时直接碰撞 = 方块顶满屏幕,游戏结束 if self.check_collision(): self.game_over = True

3.check_collision()碰撞检测(核心函数)

def check_collision(self, dx=0, dy=0, rot=None): mat = self.shape if rot is None else rot # rot传旋转后矩阵,用于旋转检测 for yi, row in enumerate(mat): for xi, val in enumerate(row): if val: # 当前位置有方块才检测 nx = self.x + xi + dx # 偏移后的X ny = self.y + yi + dy # 偏移后的Y # 1.撞左右墙壁 if nx <0 or nx >= GRID_WIDTH: return True # 2.撞底部边界 if ny >= GRID_HEIGHT: return True # 3.撞场上已落地的方块(ny>=0排除顶部出界) if ny >=0 and self.grid[ny][nx] != (0,0,0): return True return False # 无碰撞返回False

参数说明:

  • dx/dy:移动偏移量(左右 / 下移时传入 ±1)
  • rot:旋转后的方块矩阵,旋转前先检测会不会撞墙 / 方块

返回True= 发生碰撞,不能移动 / 旋转。

4.lock_block()方块落地锁定

方块无法继续下落时,把方块永久写入网格self.grid,然后消行、生成新方块:

def lock_block(self): for yi, row in enumerate(self.shape): for xi, val in enumerate(row): if val: self.grid[self.y+yi][self.x+xi] = self.color self.clear_lines() # 消除满行 self.spawn_new() # 出新方块

5.clear_lines()满行消除 + 计分

def clear_lines(self): lines = 0 # 从最底部往上遍历 for y in range(GRID_HEIGHT-1, -1, -1): # 判断一整行全部不为黑色 = 填满 if all(c != (0,0,0) for c in self.grid[y]): lines +=1 # 当前行上方所有行整体下落一格 for yy in range(y,0,-1): self.grid[yy] = self.grid[yy-1].copy() self.grid[0] = [(0,0,0)]*GRID_WIDTH # 最顶行清空 self.score += lines * 100 # 每消除1行+100分

6.rotate()方块旋转

def rotate(self): # 矩阵旋转算法:反转行 + 按列打包 r = list(zip(*self.shape[::-1])) r = [list(row) for row in r] # 旋转后不碰撞才更新方块 if not self.check_collision(rot=r): self.shape = r

矩阵旋转逻辑举例:

plaintext

[[0,1,0], [1,1,1]] 旋转后 [[1,0], [1,1], [1,0]]

7.draw()渲染画面

负责每一帧绘制背景、网格、当前方块、分数、游戏结束文字:

def draw(self): self.screen.fill((20,20,20)) # 填充深灰色背景 # 1.绘制场上已落地方块 for y in range(GRID_HEIGHT): for x in range(GRID_WIDTH): c = self.grid[y][x] rect = pygame.Rect(x*BLOCK_SIZE, y*BLOCK_SIZE, BLOCK_SIZE-1, BLOCK_SIZE-1) pygame.draw.rect(self.screen, c, rect) # 2.绘制正在下落的活动方块 for yi, row in enumerate(self.shape): for xi, val in enumerate(row): if val: px = (self.x + xi)*BLOCK_SIZE py = (self.y + yi)*BLOCK_SIZE r = pygame.Rect(px, py, BLOCK_SIZE-1, BLOCK_SIZE-1) pygame.draw.rect(self.screen, self.color, r) # 3.绘制分数文字 text = self.font.render(f"Score: {self.score}", True, (255,255,255)) self.screen.blit(text, (GRID_WIDTH*BLOCK_SIZE + 10, 50)) # 4.游戏结束红字提示 if self.game_over: over = self.font.render("Game Over", True, (255,0,0)) self.screen.blit(over, (GRID_WIDTH*BLOCK_SIZE + 10, 100)) pygame.display.update() # 刷新画布

BLOCK_SIZE-1:方块之间留 1 像素黑线分隔,视觉更清晰。

8.run()游戏主循环(游戏心脏)

所有事件、自动下落、画面刷新都在这里循环执行:

def run(self): fall_timer = 0 fall_speed = 500 # 自动下落间隔毫秒 while True: dt = self.clock.tick(60) # 锁60帧,dt=当前帧耗时ms fall_timer += dt # 事件监听:关闭窗口、按键 for e in pygame.event.get(): if e.type == pygame.QUIT: return if e.type == pygame.KEYDOWN and not self.game_over: if e.key == pygame.K_LEFT and not self.check_collision(dx=-1): self.x -=1 if e.key == pygame.K_RIGHT and not self.check_collision(dx=1): self.x +=1 if e.key == pygame.K_DOWN and not self.check_collision(dy=1): self.y +=1 if e.key == pygame.K_UP: self.rotate() # 自动下落计时逻辑 if fall_timer >= fall_speed and not self.game_over: if self.check_collision(dy=1): self.lock_block() # 下方碰撞,锁定方块 else: self.y +=1 fall_timer = 0 # 计时器清零 self.draw() # 每帧渲染画面
  • fall_timer计时器实现定时自动下落,不用依赖帧率;
  • 按键按下时先检测碰撞,无碰撞才移动坐标。

三、程序入口

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

Python 标准入口,创建游戏对象并启动主循环。

整体逻辑流程总结

  1. 初始化窗口、空白网格、生成第一个方块;
  2. 主循环持续监听键盘、计时自动下落;
  3. 左右 / 下移先碰撞检测,合法则修改坐标;上键执行旋转;
  4. 计时到自动下落一格,下方碰撞则锁定方块;
  5. 锁定后扫描所有行,消除满行并加分;
  6. 顶部生成新方块,生成时直接碰撞 → Game Over;
  7. 每一帧绘制网格、活动方块、分数文字。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/11 21:36:06

PIC18微控制器与PAM8904驱动的声光报警系统设计

1. 项目概述与核心组件选型在工业控制、安防监控和智能家居等领域&#xff0c;可靠的事件通知系统至关重要。本项目基于PIC18F97J94微控制器和PAM8904音频驱动芯片构建了一套通用型警报通知方案&#xff0c;能够根据各类传感器输入触发不同模式的声光报警。这套系统的核心优势在…

作者头像 李华
网站建设 2026/7/11 21:35:37

STM32F437ZG与AD7490高精度数据采集系统设计

1. AD7490与STM32F437ZG的硬件协同设计AD7490是一款16位、1MSPS逐次逼近型(SAR)ADC芯片&#xff0c;而STM32F437ZG则是STMicroelectronics推出的高性能ARM Cortex-M4微控制器。这对组合在工业测量、医疗设备等需要高精度信号采集的场景中具有独特优势。1.1 AD7490关键特性解析这…

作者头像 李华
网站建设 2026/7/11 21:35:01

SenseNova-U1-8B多模态模型:从信息图生成到一体化AI工作流

你有没有遇到过这样的场景&#xff1a;想快速生成一张信息图来辅助汇报&#xff0c;却发现现有工具要么文字渲染模糊不清&#xff0c;要么排版混乱需要反复调整&#xff1f;或者当你需要图文并茂的内容时&#xff0c;不得不在文字编辑器和图像生成工具之间来回切换&#xff0c;…

作者头像 李华
网站建设 2026/7/11 21:33:21

2026机加工行业QMS质量管理系统数字化选型

一、行业现状&#xff1a;机加工质量管理数字化核心痛点 机加工属于典型离散制造场景&#xff0c;涵盖CNC数控加工、车、铣、磨、钣金、精密零部件加工及外协热处理、表面处理等全工序&#xff0c;具备多品种、小批量、公差精度严苛、外协工序占比高、质检节点繁杂的行业特性。…

作者头像 李华
网站建设 2026/7/11 21:30:42

云计算全栈架构详解

云计算本质是将计算、存储、网络、软件等各类 IT 资源&#xff0c;通过网络以按需分配、弹性伸缩、按量付费的方式对外提供服务。整个体系遵循自底向上的分层架构&#xff0c;每一层都有明确的定位、核心技术与商业价值&#xff0c;下面从最基础的硬件资源开始&#xff0c;逐层…

作者头像 李华