使用Python开发经典俄罗斯方块游戏
在这篇教程中,我们将学习如何使用Python和Pygame库开发一个经典的俄罗斯方块游戏。这个项目将帮助你理解游戏开发的基本概念,包括图形界面、用户输入处理、碰撞检测等重要内容。
项目概述
我们将实现以下功能:
- 创建游戏主窗口和网格系统
- 实现不同形状的方块(Tetromino)
- 添加方块旋转和移动功能
- 实现行消除机制
- 添加分数系统
- 实现游戏结束判定
所需知识
- Python基础编程
- Pygame库的基本使用
- 面向对象编程概念
- 基本的游戏开发原理
完整代码实现
python
import pygame
import random
# 初始化Pygame
pygame.init()
# 颜色定义
COLORS = [
(0, 0, 0), # 黑色(背景)
(120, 37, 179), # 紫色
(100, 179, 179), # 青色
(80, 34, 22), # 褐色
(80, 134, 22), # 绿色
(180, 34, 22), # 红色
(180, 34, 122), # 粉色
]
# 方块形状定义
SHAPES = [
[[1, 5, 9, 13], [4, 5, 6, 7]], # I
[[1, 2, 5, 9], [0, 4, 5, 6], [1, 5, 9, 8], [4, 5, 6, 10]], # J
[[1, 2, 6, 10], [5, 6, 7, 9], [2, 6, 10, 11], [3, 5, 6, 7]], # L
[[1, 2, 5, 6]], # O
[[5, 6, 8, 9], [1, 5, 6, 10]], # S
[[1, 4, 5, 6], [1, 4, 5, 9], [4, 5, 6, 9], [1, 5, 6, 9]], # T
[[4, 5, 9, 10], [2, 6, 5, 9]] # Z
]
class Tetris:
def __init__(self, height, width):
self.height = height
self.width = width
self.field = []
self.score = 0
self.state = "start"
self.figure = None
self.x = 0
self.y = 0
self.init_field()
def init_field(self):
self.field = []
for i in range(self.height):
new_line = []
for j in range(self.width):
new_line.append(0)
self.field.append(new_line)
def new_figure(self):
self.figure = Figure(3, 0)
def intersects(self):
intersection = False
for i in range(4):
for j in range(4):
if i * 4 + j in self.figure.image():
if (i + self.figure.y > self.height - 1 or
j + self.figure.x > self.width - 1 or
j + self.figure.x < 0 or
self.field[i + self.figure.y][j + self.figure.x] > 0):
intersection = True
return intersection
def freeze(self):
for i in range(4):
for j in range(4):
if i * 4 + j in self.figure.image():
self.field[i + self.figure.y][j + self.figure.x] = self.figure.color
self.break_lines()
self.new_figure()
if self.intersects():
self.state = "gameover"
def break_lines(self):
lines = 0
for i in range(1, self.height):
zeros = 0
for j in range(self.width):
if self.field[i][j] == 0:
zeros += 1
if zeros == 0:
lines += 1
for i1 in range(i, 1, -1):
for j in range(self.width):
self.field[i1][j] = self.field[i1-1][j]
self.score += lines ** 2
def go_space(self):
while not self.intersects():
self.figure.y += 1
self.figure.y -= 1
self.freeze()
def go_down(self):
self.figure.y += 1
if self.intersects():
self.figure.y -= 1
self.freeze()
def go_side(self, dx):
old_x = self.figure.x
self.figure.x += dx
if self.intersects():
self.figure.x = old_x
def rotate(self):
old_rotation = self.figure.rotation
self.figure.rotate()
if self.intersects():
self.figure.rotation = old_rotation
class Figure:
def __init__(self, x, y):
self.x = x
self.y = y
self.type = random.randint(0, len(SHAPES) - 1)
self.color = random.randint(1, len(COLORS) - 1)
self.rotation = 0
def image(self):
return SHAPES[self.type][self.rotation]
def rotate(self):
self.rotation = (self.rotation + 1) % len(SHAPES[self.type])
# 游戏参数设置
GAME_HEIGHT = 20
GAME_WIDTH = 10
TILE_SIZE = 30
GAME_RES = GAME_WIDTH * TILE_SIZE, GAME_HEIGHT * TILE_SIZE
FPS = 60
# 初始化游戏窗口
pygame.init()
screen = pygame.display.set_mode(GAME_RES)
pygame.display.set_caption("俄罗斯方块")
clock = pygame.time.Clock()
# 创建游戏对象
game = Tetris(GAME_HEIGHT, GAME_WIDTH)
counter = 0
pressing_down = False
while True:
if game.figure is None:
game.new_figure()
counter += 1
if counter > 100000:
counter = 0
if counter % (FPS // (game.score + 1) // 2 + 1) == 0 or pressing_down:
if game.state == "start":
game.go_down()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
game.rotate()
if event.key == pygame.K_DOWN:
pressing_down = True
if event.key == pygame.K_LEFT:
game.go_side(-1)
if event.key == pygame.K_RIGHT:
game.go_side(1)
if event.key == pygame.K_SPACE:
game.go_space()
if event.key == pygame.K_ESCAPE:
pygame.quit()
exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
pressing_down = False
screen.fill((0, 0, 0))
for i in range(game.height):
for j in range(game.width):
if game.field[i][j] > 0:
pygame.draw.rect(screen, COLORS[game.field[i][j]],
[j * TILE_SIZE, i * TILE_SIZE, TILE_SIZE - 1, TILE_SIZE - 1])
if game.figure is not None:
for i in range(4):
for j in range(4):
if i * 4 + j in game.figure.image():
pygame.draw.rect(screen, COLORS[game.figure.color],
[(j + game.figure.x) * TILE_SIZE,
(i + game.figure.y) * TILE_SIZE,
TILE_SIZE - 1, TILE_SIZE - 1])
pygame.display.flip()
clock.tick(FPS)
代码详解
1. 基础设置和常量定义
python
import pygame
import random
# 颜色定义
COLORS = [
(0, 0, 0), # 黑色(背景)
(120, 37, 179), # 紫色
# ... 其他颜色
]
# 方块形状定义
SHAPES = [
[[1, 5, 9, 13], [4, 5, 6, 7]], # I形
# ... 其他形状
]
这部分代码定义了:
- 游戏使用的颜色列表
- 七种不同的俄罗斯方块形状
- 每种形状的旋转状态
2. Tetris类
Tetris类是游戏的核心,包含了以下主要功能:
- 游戏场地初始化
- 方块生成和移动
- 碰撞检测
- 消行处理
- 游戏状态管理
3. Figure类
Figure类负责管理方块对象,包括:
- 方块的位置
- 方块的类型和颜色
- 方块的旋转状态
4. 游戏主循环
主循环处理:
- 用户输入
- 游戏状态更新
- 画面渲染
游戏功能
-
基本操作
- 左右方向键:移动方块
- 上方向键:旋转方块
- 下方向键:加速下落
- 空格键:直接落到底部
-
计分系统
- 同时消除的行数越多,得分越高
- 分数影响方块下落速度
-
游戏结束条件
- 新方块无法放置时游戏结束
运行效果
运行代码后,你将看到:
- 一个黑色背景的游戏窗口
- 不同颜色的方块随机出现
- 方块可以移动和旋转
- 完整的行会被消除
- 游戏分数实时更新
扩展优化建议
你可以通过以下方式改进这个游戏:
-
界面优化
- 添加开始菜单
- 显示下一个方块预览
- 添加分数显示界面
- 添加游戏结束画面
-
功能增强
- 添加音效
- 实现方块阴影提示
- 添加暂停功能
- 实现存档功能
-
游戏性提升
- 添加难度级别
- 实现连击奖励机制
- 添加特殊方块效果
注意事项
-
运行前确保已安装Python和Pygame库
-
可以通过pip安装Pygame:
bashpip install pygame
-
游戏参数(如窗口大小、速度等)可以根据需要调整
-
建议在开发时多添加注释,便于后续维护