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

📅 2026/7/11 21:36:30
【游戏开发入门】用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, dx0, dy0, rotNone): 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.yyi][self.xxi] 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(rotr): 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(fScore: {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(dx1): self.x 1 if e.key pygame.K_DOWN and not self.check_collision(dy1): 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(dy1): self.lock_block() else: self.y 1 fall_timer 0 self.draw() if __name__ __main__: game Tetris() game.run()操作说明左右方向键左右移动方块下方向键快速下移上方向键旋转方块关闭窗口退出游戏功能包含7 种标准俄罗斯方块、不同颜色自动下落、行消除、计分系统碰撞检测、方块落地锁定填满顶部游戏结束判定简单 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 True3.check_collision()碰撞检测核心函数def check_collision(self, dx0, dy0, rotNone): 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.撞场上已落地的方块ny0排除顶部出界 if ny 0 and self.grid[ny][nx] ! (0,0,0): return True return False # 无碰撞返回False参数说明dx/dy移动偏移量左右 / 下移时传入 ±1rot旋转后的方块矩阵旋转前先检测会不会撞墙 / 方块返回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.yyi][self.xxi] 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(rotr): 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(fScore: {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(dx1): self.x 1 if e.key pygame.K_DOWN and not self.check_collision(dy1): 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(dy1): self.lock_block() # 下方碰撞锁定方块 else: self.y 1 fall_timer 0 # 计时器清零 self.draw() # 每帧渲染画面fall_timer计时器实现定时自动下落不用依赖帧率按键按下时先检测碰撞无碰撞才移动坐标。三、程序入口if __name__ __main__: game Tetris() game.run()Python 标准入口创建游戏对象并启动主循环。整体逻辑流程总结初始化窗口、空白网格、生成第一个方块主循环持续监听键盘、计时自动下落左右 / 下移先碰撞检测合法则修改坐标上键执行旋转计时到自动下落一格下方碰撞则锁定方块锁定后扫描所有行消除满行并加分顶部生成新方块生成时直接碰撞 → Game Over每一帧绘制网格、活动方块、分数文字。