python 小游戏:扫雷
目录
1. 前言
2. 准备工作
3. 生成雷区
4. 鼠标点击扫雷
5. 胜利 or 失败
6. 游戏效果展示
7. 完整代码
1. 前言
本文使用 Pygame 实现的简化版扫雷游戏。
如上图所示,游戏包括基本的扫雷功能:生成雷区、左键点击扫雷、右键标记地雷、显示数字提示等。
2. 准备工作
首先,当然要下载pygame 库文件,可以通过下面命令下载
pip install pygame
在这之前,我们需要提前规划好前期工作,例如游戏窗口多大,生成图形显示的颜色等等。
这里为了方便,我们采用大多数默认的版本,这里生成的格子数量就是 (400 / 40)*(400/40),也就是100个窗格
import pygame
import random
# 初始化 Pygame
pygame.init()
# 屏幕设置
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 400
CELL_SIZE = 40
GRID_WIDTH = SCREEN_WIDTH // CELL_SIZE
GRID_HEIGHT = SCREEN_HEIGHT // CELL_SIZE
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
# 字体设置
font = pygame.font.SysFont("Arial", 20)
如下:
3. 生成雷区
有了窗口格子区域,接下来就可以生成雷区,这里采用random函数随机生成,保证每次打开游戏雷区的位置不一样
# 生成雷区
def create_grid(width, height, num_mines):
grid = [[0 for _ in range(width)] for _ in range(height)]
mines = set()
while len(mines) < num_mines:
x = random.randint(0, width - 1)
y = random.randint(0, height - 1)
mines.add((x, y))
grid[y][x] = -1 # -1 表示地雷
# 计算每个格子周围的地雷数量
for y in range(height):
for x in range(width):
if grid[y][x] == -1:
continue
count = 0
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
if 0 <= x + dx < width and 0 <= y + dy < height:
if grid[y + dy][x + dx] == -1:
count += 1
grid[y][x] = count
return grid, mines
-
使用
create_grid
函数生成雷区,随机放置地雷,并计算每个格子周围的地雷数量。
4. 鼠标点击扫雷
生成雷区后,下面就是扫雷环节,之前写C语言扫雷,还需要在控制台键入区域。这里可以直接调用鼠标
# 绘制格子
def draw_grid():
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
if revealed[y][x]:
if grid[y][x] == -1:
pygame.draw.rect(screen, RED, rect) # 地雷
else:
pygame.draw.rect(screen, GRAY, rect)
if grid[y][x] > 0:
text = font.render(str(grid[y][x]), True, BLACK)
screen.blit(text, (x * CELL_SIZE + 10, y * CELL_SIZE + 10))
else:
pygame.draw.rect(screen, WHITE, rect)
if flagged[y][x]:
pygame.draw.circle(screen, GREEN, rect.center, 10) # 标记地雷
pygame.draw.rect(screen, BLACK, rect, 1) # 格子边框
# 翻开格子
def reveal_cell(x, y):
if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT and not revealed[y][x]:
revealed[y][x] = True
if grid[y][x] == 0:
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
reveal_cell(x + dx, y + dy) # 递归翻开空白区域
5. 胜利 or 失败
胜利条件:所有非地雷格子都被翻开时,玩家胜利。
-
游戏结束显示:
-
如果踩到地雷,显示 "Game Over!"。
-
如果胜利,显示 "You Win!"。
-
# 检查是否胜利
def check_win():
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
if grid[y][x] != -1 and not revealed[y][x]:
return False
return True
6. 游戏效果展示
失败:
胜利:
7. 完整代码
直接复制到py脚本运行即可:
import pygame
import random
# 初始化 Pygame
pygame.init()
# 屏幕设置
SCREEN_WIDTH = 400
SCREEN_HEIGHT = 400
CELL_SIZE = 40
GRID_WIDTH = SCREEN_WIDTH // CELL_SIZE
GRID_HEIGHT = SCREEN_HEIGHT // CELL_SIZE
# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
# 字体设置
font = pygame.font.SysFont("Arial", 20)
# 初始化屏幕
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("Minesweeper")
# 游戏状态
game_over = False
win = False
# 生成雷区
def create_grid(width, height, num_mines):
grid = [[0 for _ in range(width)] for _ in range(height)]
mines = set()
while len(mines) < num_mines:
x = random.randint(0, width - 1)
y = random.randint(0, height - 1)
mines.add((x, y))
grid[y][x] = -1 # -1 表示地雷
# 计算每个格子周围的地雷数量
for y in range(height):
for x in range(width):
if grid[y][x] == -1:
continue
count = 0
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
if 0 <= x + dx < width and 0 <= y + dy < height:
if grid[y + dy][x + dx] == -1:
count += 1
grid[y][x] = count
return grid, mines
# 初始化雷区
grid, mines = create_grid(GRID_WIDTH, GRID_HEIGHT, 10)
# 记录翻开的格子和标记的地雷
revealed = [[False for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
flagged = [[False for _ in range(GRID_WIDTH)] for _ in range(GRID_HEIGHT)]
# 绘制格子
def draw_grid():
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
rect = pygame.Rect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE)
if revealed[y][x]:
if grid[y][x] == -1:
pygame.draw.rect(screen, RED, rect) # 地雷
else:
pygame.draw.rect(screen, GRAY, rect)
if grid[y][x] > 0:
text = font.render(str(grid[y][x]), True, BLACK)
screen.blit(text, (x * CELL_SIZE + 10, y * CELL_SIZE + 10))
else:
pygame.draw.rect(screen, WHITE, rect)
if flagged[y][x]:
pygame.draw.circle(screen, GREEN, rect.center, 10) # 标记地雷
pygame.draw.rect(screen, BLACK, rect, 1) # 格子边框
# 翻开格子
def reveal_cell(x, y):
if 0 <= x < GRID_WIDTH and 0 <= y < GRID_HEIGHT and not revealed[y][x]:
revealed[y][x] = True
if grid[y][x] == 0:
for dy in [-1, 0, 1]:
for dx in [-1, 0, 1]:
reveal_cell(x + dx, y + dy) # 递归翻开空白区域
# 检查是否胜利
def check_win():
for y in range(GRID_HEIGHT):
for x in range(GRID_WIDTH):
if grid[y][x] != -1 and not revealed[y][x]:
return False
return True
# 游戏主循环
clock = pygame.time.Clock()
running = True
while running:
screen.fill(WHITE)
# 事件处理
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if not game_over and not win:
if event.type == pygame.MOUSEBUTTONDOWN:
x, y = event.pos
grid_x = x // CELL_SIZE
grid_y = y // CELL_SIZE
if event.button == 1: # 左键翻开格子
if grid[grid_y][grid_x] == -1:
game_over = True # 踩到地雷
else:
reveal_cell(grid_x, grid_y)
if check_win():
win = True
elif event.button == 3: # 右键标记地雷
if not revealed[grid_y][grid_x]:
flagged[grid_y][grid_x] = not flagged[grid_y][grid_x]
# 绘制雷区
draw_grid()
# 游戏结束显示
if game_over:
text = font.render("Game Over!", True, RED)
screen.blit(text, (SCREEN_WIDTH // 2 - 60, SCREEN_HEIGHT // 2 - 10))
if win:
text = font.render("You Win!", True, GREEN)
screen.blit(text, (SCREEN_WIDTH // 2 - 50, SCREEN_HEIGHT // 2 - 10))
# 更新屏幕
pygame.display.flip()
clock.tick(30)
# 退出游戏
pygame.quit()