目录
1984 年,苏联工程师阿列克谢・帕基特诺夫在电脑上敲下一串代码,无意间创造出了风靡全球的游戏 —— 俄罗斯方块。这个由 “tetra”(希腊语,意为 “四”)与 “Tennis”(帕基特诺夫喜爱的网球)组合而成的名字,带着数学与运动的奇妙融合,开启了一场跨越时代的方块冒险。
作为童年的回忆,每个游戏少年都希望有一款自己的俄罗斯方块游戏,接下来我们就开始“tetra”的创作之旅。
成品展示
模块划分
- 初始化模块:负责 Pygame 库的初始化、游戏窗口的创建和颜色、常量的定义。
- 方块管理模块:包含方块的生成、绘制、碰撞检测和合并等功能。
- 游戏逻辑模块:处理游戏的主循环、事件监听、方块下落和消除行的逻辑。
- 界面绘制模块:负责绘制游戏面板、方块、提示窗口、按钮和游戏结束界面。
初始化模块
Pygame 初始化
pygame.init()
调用 pygame.init()
函数初始化 Pygame 库的所有模块。
常量定义
- 颜色常量:定义了游戏中使用的各种颜色,如
BLACK
、WHITE
等。 - 窗口尺寸常量:
WIDTH
和HEIGHT
定义游戏区域的宽度和高度,PREVIEW_WIDTH
定义提示窗口的宽度。 - 方块大小常量:
BLOCK_SIZE
定义每个方块的大小。
窗口创建
screen = pygame.display.set_mode((WIDTH + PREVIEW_WIDTH, HEIGHT))
pygame.display.set_caption("俄罗斯方块")
方块管理模块
方块形状定义
SHAPES = [
[[1, 1, 1, 1]],
[[1, 1], [1, 1]],
[[1, 1, 0], [0, 1, 1]],
[[0, 1, 1], [1, 1, 0]],
[[1, 1, 1], [0, 1, 0]],
[[1, 1, 1], [1, 0, 0]],
[[1, 1, 1], [0, 0, 1]]
]
定义了 7 种不同形状的方块。
方块生成
def new_piece():
shape = random.choice(SHAPES)
color = random.choice(COLORS)
return {
'x': WIDTH // 2 // BLOCK_SIZE - len(shape[0]) // 2,
'y': 0,
'shape': shape,
'color': color
}
随机选择一个方块形状和颜色,生成一个新的方块。
方块绘制
def draw_piece(piece, offset_x=0, offset_y=0):
for y, row in enumerate(piece['shape']):
for x, val in enumerate(row):
if val:
pygame.draw.rect(screen, piece['color'], [
offset_x + (piece['x'] + x) * BLOCK_SIZE,
offset_y + (piece['y'] + y) * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
])
pygame.draw.rect(screen, GRAY, [
offset_x + (piece['x'] + x) * BLOCK_SIZE,
offset_y + (piece['y'] + y) * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
], 1)
根据方块的位置、形状和颜色,在游戏窗口中绘制方块。
碰撞检测
def is_collision(board, piece):
for y, row in enumerate(piece['shape']):
for x, val in enumerate(row):
if val:
new_x = piece['x'] + x
new_y = piece['y'] + y
if new_x < 0 or new_x >= WIDTH // BLOCK_SIZE or new_y >= HEIGHT // BLOCK_SIZE:
return True
if new_y >= 0 and board[new_y][new_x]:
return True
return False
检查方块是否越界或与游戏面板上已有的方块发生碰撞。
方块合并
def merge(board, piece):
for y, row in enumerate(piece['shape']):
for x, val in enumerate(row):
if val:
board[piece['y'] + y][piece['x'] + x] = piece['color']
return board
将方块合并到游戏面板中。
游戏逻辑模块
主循环
while running:
# 事件处理
# 方块下落逻辑
# 界面绘制
pygame.display.flip()
事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and not game_over:
# 处理键盘按键事件
处理游戏中的各种事件,如关闭窗口、键盘按键等。
方块下落逻辑
if not game_over and fall_time / 1000 >= fall_speed:
fall_time = 0
new_piece_data = {
'x': current_piece['x'],
'y': current_piece['y'] + 1,
'shape': current_piece['shape'],
'color': current_piece['color']
}
if not is_collision(board, new_piece_data):
current_piece = new_piece_data
else:
board = merge(board, current_piece)
board, cleared_lines = clear_lines(board)
# 更新得分
current_piece = next_piece
next_piece = new_piece()
if is_collision(board, current_piece):
game_over = True
控制方块自动下落,当方块落地后,合并方块、消除满行并更新得分。
消除满行
def clear_lines(board):
full_lines = []
for y, row in enumerate(board):
if all(row):
full_lines.append(y)
for line in full_lines:
del board[line]
board = [[0] * (WIDTH // BLOCK_SIZE)] + board
return board, len(full_lines)
检查游戏面板中是否有满行,若有则消除并返回消除的行数。
得分规则
if cleared_lines == 1:
score += 1
elif cleared_lines == 2:
score += 4
elif cleared_lines == 3:
score += 9
elif cleared_lines == 4:
score += 16
根据消除的行数更新得分,消除 1 行得 1 分,消除 2 行得 4 分,消除 3 行得 9 分,消除 4 行得 16 分。
界面绘制模块
游戏面板绘制
for y, row in enumerate(board):
for x, val in enumerate(row):
if val:
pygame.draw.rect(screen, val, [
x * BLOCK_SIZE,
y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
])
pygame.draw.rect(screen, GRAY, [
x * BLOCK_SIZE,
y * BLOCK_SIZE,
BLOCK_SIZE, BLOCK_SIZE
], 1)
绘制游戏面板上已有的方块。
提示窗口绘制
- 得分显示:在提示窗口中显示当前得分。
- 下一个方块预览:显示下一个即将出现的方块。
- 操作提示:显示游戏的操作提示信息。
游戏结束界面绘制
game_over_text = font.render("Game Over!", True, RED)
screen.blit(game_over_text, (WIDTH // 2 - game_over_text.get_width() // 2, HEIGHT // 2 - 100))
draw_button("Play Again", ...)
draw_button("Quit", ...)
当游戏结束时,显示游戏结束信息和重新开始、退出游戏的按钮。