Python开发俄罗斯方块_俄罗斯方块的编程
文章标签:
如何自己编程一些小游戏
import pygame
import random
import time
import os
# 初始化pygame
pygame.init()
# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 30
GRID_WIDTH = 10
GRID_HEIGHT = 20
SIDEBAR_WIDTH = 200
# 颜色定义
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 120, 255)
YELLOW = (255, 255, 0)
PURPLE = (180, 0, 255)
CYAN = (0, 255, 255)
ORANGE = (255, 165, 0)
GRAY = (128, 128, 128)
DARK_GRAY = (50, 50, 50)
COLORS = [CYAN, BLUE, ORANGE, YELLOW, GREEN, PURPLE, RED]
# 方块形状
SHAPES = [
[[1, 1, 1, 1]], # I
[[1, 1, 1], [0, 1, 0]], # T
[[1, 1, 1], [1, 0, 0]], # L
[[1, 1, 1], [0, 0, 1]], # J
[[1, 1], [1, 1]], # O
[[0, 1, 1], [1, 1, 0]], # S
[[1, 1, 0], [0, 1, 1]] # Z
]
# 设置屏幕
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("俄罗斯方块")
# 游戏区域
game_area_left = (SCREEN_WIDTH - SIDEBAR_WIDTH - GRID_WIDTH * GRID_SIZE) // 2
game_area_top = (SCREEN_HEIGHT - GRID_HEIGHT * GRID_SIZE) // 2
# 加载字体
def get_font(size):
# 尝试加载系统中文字体
font_names = ['SimHei', 'Microsoft YaHei', 'SimSun', 'KaiTi', 'Arial Unicode MS']
for font_name in font_names:
try:
return pygame.font.SysFont(font_name, size)
except:
continue
# 如果系统中文字体都不可用,使用默认字体
return pygame.font.Font(None, size)
class Tetromino:
def __init__(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
def rotate(self):
# 转置矩阵实现旋转
rotated = [[self.shape[y][x] for y in range(len(self.shape)-1, -1, -1)]
for x in range(len(self.shape[0]))]
return rotated
def draw(self, surface):
for y, row in enumerate(self.shape):
for x, cell in enumerate(row):
if cell:
rect = pygame.Rect(
game_area_left + (self.x + x) * GRID_SIZE,
game_area_top + (self.y + y) * GRID_SIZE,
GRID_SIZE, GRID_SIZE
)
pygame.draw.rect(surface, self.color, rect)
pygame.draw.rect(surface, WHITE, rect, 1)
# 添加内部高光效果
highlight = pygame.Rect(
game_area_left + (self.x + x) * GRID_SIZE + 2,
game_area_top + (self.y + y) * GRID_SIZE + 2,
GRID_SIZE - 4, GRID_SIZE - 4
)
pygame.draw.rect(surface, self.color, highlight)
pygame.draw.rect(surface, WHITE, highlight, 1)
class Game:
def __init__(self):
self.board = [[0 for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
self.current_piece = Tetromino()
self.next_piece = Tetromino()
self.game_over = False
self.score = 0
self.level = 1
self.lines_cleared = 0
self.fall_speed = 0.5 # 初始下落速度(秒)
self.last_fall_time = time.time()
def draw_board(self, surface):
# 绘制游戏区域背景
pygame.draw.rect(surface, DARK_GRAY, (
game_area_left,
game_area_top,
GRID_WIDTH * GRID_SIZE,
GRID_HEIGHT * GRID_SIZE
))
# 绘制网格
for x in range(GRID_WIDTH + 1):
pygame.draw.line(
surface, GRAY,
(game_area_left + x * GRID_SIZE, game_area_top),
(game_area_left + x * GRID_SIZE, game_area_top + GRID_HEIGHT * GRID_SIZE)
)
for y in range(GRID_HEIGHT + 1):
pygame.draw.line(
surface, GRAY,
(game_area_left, game_area_top + y * GRID_SIZE),
(game_area_left + GRID_WIDTH * GRID_SIZE, game_area_top + y * GRID_SIZE)
)
# 绘制已落下的方块
for y, row in enumerate(self.board):
for x, cell in enumerate(row):
if cell:
color_idx = cell - 1
rect = pygame.Rect(
game_area_left + x * GRID_SIZE,
game_area_top + y * GRID_SIZE,
GRID_SIZE, GRID_SIZE
)
pygame.draw.rect(surface, COLORS[color_idx], rect)
pygame.draw.rect(surface, WHITE, rect, 1)
# 添加内部高光效果
highlight = pygame.Rect(
game_area_left + x * GRID_SIZE + 2,
game_area_top + y * GRID_SIZE + 2,
GRID_SIZE - 4, GRID_SIZE - 4
)
pygame.draw.rect(surface, COLORS[color_idx], highlight)
pygame.draw.rect(surface, WHITE, highlight, 1)
def draw_sidebar(self, surface):
sidebar_left = game_area_left + GRID_WIDTH * GRID_SIZE + 20
# 绘制侧边栏背景
pygame.draw.rect(surface, DARK_GRAY, (
sidebar_left - 10,
game_area_top - 10,
SIDEBAR_WIDTH,
GRID_HEIGHT * GRID_SIZE + 20
))
# 绘制下一个方块预览标题
font = get_font(28)
next_text = font.render("下一个方块:", True, YELLOW)
surface.blit(next_text, (sidebar_left, game_area_top))
# 绘制下一个方块预览区域背景
preview_bg = pygame.Rect(
sidebar_left - 5,
game_area_top + 40,
120,
120
)
pygame.draw.rect(surface, BLACK, preview_bg)
pygame.draw.rect(surface, WHITE, preview_bg, 2)
# 绘制下一个方块
next_left = sidebar_left + 30
next_top = game_area_top + 70
for y, row in enumerate(self.next_piece.shape):
for x, cell in enumerate(row):
if cell:
rect = pygame.Rect(
next_left + x * GRID_SIZE,
next_top + y * GRID_SIZE,
GRID_SIZE, GRID_SIZE
)
pygame.draw.rect(surface, self.next_piece.color, rect)
pygame.draw.rect(surface, WHITE, rect, 1)
# 绘制分数和等级
score_text = font.render(f"分数: {self.score}", True, WHITE)
level_text = font.render(f"等级: {self.level}", True, WHITE)
lines_text = font.render(f"消除行数: {self.lines_cleared}", True, WHITE)
surface.blit(score_text, (sidebar_left, next_top + 150))
surface.blit(level_text, (sidebar_left, next_top + 190))
surface.blit(lines_text, (sidebar_left, next_top + 230))
# 绘制游戏说明
controls_font = get_font(20)
controls = [
"游戏控制:",
"← → : 左右移动",
"↑ : 旋转方块",
"↓ : 加速下落",
"空格 : 直接落下",
"P : 暂停游戏",
"R : 重新开始"
]
for i, text in enumerate(controls):
color = YELLOW if i == 0 else WHITE
control_text = controls_font.render(text, True, color)
surface.blit(control_text, (sidebar_left, next_top + 300 + i * 30))
def draw_game_over(self, surface):
# 半透明覆盖层
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180))
surface.blit(overlay, (0, 0))
font_large = get_font(72)
font_small = get_font(36)
game_over_text = font_large.render("游戏结束!", True, RED)
text_rect = game_over_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 50))
surface.blit(game_over_text, text_rect)
score_text = font_small.render(f"最终分数: {self.score}", True, YELLOW)
score_rect = score_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 20))
surface.blit(score_text, score_rect)
restart_text = font_small.render("按 R 键重新开始", True, WHITE)
restart_rect = restart_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 80))
surface.blit(restart_text, restart_rect)
def check_collision(self, shape, x, y):
for row_idx, row in enumerate(shape):
for col_idx, cell in enumerate(row):
if cell:
# 检查是否超出边界
if (x + col_idx < 0 or x + col_idx >= GRID_WIDTH or
y + row_idx >= GRID_HEIGHT):
return True
# 检查是否与已有方块重叠
if y + row_idx >= 0 and self.board[y + row_idx][x + col_idx]:
return True
return False
def merge_piece(self):
for y, row in enumerate(self.current_piece.shape):
for x, cell in enumerate(row):
if cell and self.current_piece.y + y >= 0:
self.board[self.current_piece.y + y][self.current_piece.x + x] = self.current_piece.shape_idx + 1
def clear_lines(self):
lines_to_clear = []
for y, row in enumerate(self.board):
if all(row):
lines_to_clear.append(y)
for line in lines_to_clear:
del self.board[line]
self.board.insert(0, [0 for _ in range(GRID_WIDTH)])
# 更新分数
if lines_to_clear:
self.lines_cleared += len(lines_to_clear)
self.score += (1, 2, 5, 10)[min(len(lines_to_clear)-1, 3)] * 100 * self.level
self.level = self.lines_cleared // 10 + 1
self.fall_speed = max(0.05, 0.5 - (self.level - 1) * 0.05)
def move(self, dx, dy):
if not self.check_collision(self.current_piece.shape,
self.current_piece.x + dx,
self.current_piece.y + dy):
self.current_piece.x += dx
self.current_piece.y += dy
return True
return False
def rotate_piece(self):
rotated = self.current_piece.rotate()
if not self.check_collision(rotated, self.current_piece.x, self.current_piece.y):
self.current_piece.shape = rotated
return True
return False
def drop_piece(self):
while self.move(0, 1):
pass
self.merge_piece()
self.clear_lines()
self.current_piece = self.next_piece
self.next_piece = Tetromino()
# 检查游戏是否结束
if self.check_collision(self.current_piece.shape, self.current_piece.x, self.current_piece.y):
self.game_over = True
def update(self):
current_time = time.time()
if current_time - self.last_fall_time > self.fall_speed:
if not self.move(0, 1):
self.merge_piece()
self.clear_lines()
self.current_piece = self.next_piece
self.next_piece = Tetromino()
# 检查游戏是否结束
if self.check_collision(self.current_piece.shape, self.current_piece.x, self.current_piece.y):
self.game_over = True
self.last_fall_time = current_time
def reset(self):
self.__init__()
def main():
game = Game()
clock = pygame.time.Clock()
paused = False
# 游戏背景
background = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
background.fill((40, 40, 60))
# 添加一些装饰性网格
for x in range(0, SCREEN_WIDTH, 40):
pygame.draw.line(background, (50, 50, 80), (x, 0), (x, SCREEN_HEIGHT), 1)
for y in range(0, SCREEN_HEIGHT, 40):
pygame.draw.line(background, (50, 50, 80), (0, y), (SCREEN_WIDTH, y), 1)
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
game.reset()
paused = False
if game.game_over:
continue
if event.key == pygame.K_p:
paused = not paused
if not paused:
if event.key == pygame.K_LEFT:
game.move(-1, 0)
elif event.key == pygame.K_RIGHT:
game.move(1, 0)
elif event.key == pygame.K_DOWN:
game.move(0, 1)
elif event.key == pygame.K_UP:
game.rotate_piece()
elif event.key == pygame.K_SPACE:
game.drop_piece()
# 绘制背景
screen.blit(background, (0, 0))
if not paused and not game.game_over:
game.update()
# 绘制游戏元素
game.draw_board(screen)
game.current_piece.draw(screen)
game.draw_sidebar(screen)
if game.game_over:
game.draw_game_over(screen)
if paused and not game.game_over:
# 半透明覆盖层
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 150))
screen.blit(overlay, (0, 0))
font = get_font(72)
pause_text = font.render("游戏暂停", True, YELLOW)
text_rect = pause_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
screen.blit(pause_text, text_rect)
font_small = get_font(28)
continue_text = font_small.render("按 P 键继续游戏", True, WHITE)
continue_rect = continue_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 + 80))
screen.blit(continue_text, continue_rect)
pygame.display.flip()
clock.tick(60)
pygame.quit()
if __name__ == "__main__":
main()