《Python Pygame 入门:开发一个简易拼图游戏(支持自定义图片)》
·
Python Pygame 入门:开发简易拼图游戏
下面我将创建一个支持自定义图片的简易拼图游戏,使用Python的Pygame库实现。游戏包含完整功能:图片加载、网格分割、碎片随机打乱、拖拽交互和胜利判定。
完整代码实现
import pygame
import sys
import random
import os
from pygame.locals import *
# 初始化pygame
pygame.init()
# 游戏常量
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
GRID_SIZE = 3 # 3x3网格
TILE_SIZE = 150 # 每个拼图块大小
MARGIN = 10 # 拼图块间距
# 颜色定义
BACKGROUND = (40, 44, 52)
GRID_COLOR = (86, 98, 112)
TEXT_COLOR = (220, 220, 220)
HIGHLIGHT = (97, 175, 239)
# 创建游戏窗口
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("简易拼图游戏")
# 字体设置
font = pygame.font.SysFont(None, 36)
class PuzzleGame:
def __init__(self):
self.tiles = []
self.empty_pos = (GRID_SIZE-1, GRID_SIZE-1) # 空白位置在右下角
self.selected_tile = None
self.game_complete = False
self.image_path = ""
def load_image(self, image_path):
"""加载并分割自定义图片"""
try:
# 加载图片并调整大小
original_image = pygame.image.load(image_path)
img_width = GRID_SIZE * TILE_SIZE
img_height = GRID_SIZE * TILE_SIZE
scaled_image = pygame.transform.scale(original_image, (img_width, img_height))
# 清空现有拼图块
self.tiles = []
# 分割图片为网格块
for row in range(GRID_SIZE):
for col in range(GRID_SIZE):
# 创建拼图块表面
tile_surface = pygame.Surface((TILE_SIZE, TILE_SIZE), pygame.SRCALPHA)
# 计算源矩形区域(最后一块留空)
if row == GRID_SIZE-1 and col == GRID_SIZE-1:
# 空白块(透明)
tile_surface.fill((0, 0, 0, 0))
else:
# 从缩放后的图片中截取相应区域
src_rect = pygame.Rect(col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE, TILE_SIZE)
tile_surface.blit(scaled_image, (0, 0), src_rect)
# 添加边框
pygame.draw.rect(tile_surface, GRID_COLOR, (0, 0, TILE_SIZE, TILE_SIZE), 2)
# 存储拼图块信息
self.tiles.append({
'surface': tile_surface,
'correct_pos': (row, col), # 正确位置
'current_pos': (row, col) # 当前位置
})
# 记录图片路径
self.image_path = image_path
# 打乱拼图
self.shuffle_tiles()
self.game_complete = False
return True
except Exception as e:
print(f"加载图片失败: {e}")
return False
def shuffle_tiles(self):
"""随机打乱拼图块(确保可解)"""
# 进行100次随机移动
for _ in range(100):
# 获取空白位置周围的可行移动方向
row, col = self.empty_pos
possible_moves = []
# 检查四个方向
if row > 0: possible_moves.append((row-1, col)) # 上
if row < GRID_SIZE-1: possible_moves.append((row+1, col)) # 下
if col > 0: possible_moves.append((row, col-1)) # 左
if col < GRID_SIZE-1: possible_moves.append((row, col+1)) # 右
# 随机选择一个方向移动
if possible_moves:
move_pos = random.choice(possible_moves)
self.move_tile(move_pos)
def move_tile(self, tile_pos):
"""移动拼图块"""
# 检查是否与空白位置相邻
row, col = tile_pos
empty_row, empty_col = self.empty_pos
# 检查是否在相邻位置(上、下、左、右)
if ((abs(row - empty_row) == 1 and col == empty_col) or
(abs(col - empty_col) == 1 and row == empty_row)):
# 找到要移动的拼图块
for tile in self.tiles:
if tile['current_pos'] == tile_pos:
# 更新拼图块位置
tile['current_pos'] = self.empty_pos
# 更新空白位置
self.empty_pos = tile_pos
break
# 检查游戏是否完成
self.check_completion()
def check_completion(self):
"""检查拼图是否完成"""
self.game_complete = True
for tile in self.tiles:
if tile['current_pos'] != tile['correct_pos']:
self.game_complete = False
break
def draw(self, screen):
"""绘制游戏界面"""
# 绘制背景
screen.fill(BACKGROUND)
# 计算拼图区域位置(居中)
total_width = GRID_SIZE * (TILE_SIZE + MARGIN) - MARGIN
total_height = GRID_SIZE * (TILE_SIZE + MARGIN) - MARGIN
start_x = (SCREEN_WIDTH - total_width) // 2
start_y = (SCREEN_HEIGHT - total_height) // 2
# 绘制所有拼图块
for tile in self.tiles:
row, col = tile['current_pos']
# 跳过空白块
if row == self.empty_pos[0] and col == self.empty_pos[1]:
continue
# 计算绘制位置
x = start_x + col * (TILE_SIZE + MARGIN)
y = start_y + row * (TILE_SIZE + MARGIN)
# 绘制拼图块
screen.blit(tile['surface'], (x, y))
# 高亮选中的拼图块
if self.selected_tile == (row, col):
highlight_rect = pygame.Rect(x-5, y-5, TILE_SIZE+10, TILE_SIZE+10)
pygame.draw.rect(screen, HIGHLIGHT, highlight_rect, 3)
# 绘制游戏标题
title_text = font.render("简易拼图游戏", True, TEXT_COLOR)
screen.blit(title_text, (SCREEN_WIDTH//2 - title_text.get_width()//2, 20))
# 绘制操作说明
controls = [
"操作说明:",
"鼠标点击 - 选择拼图块",
"方向键 - 移动选中的拼图块",
"R键 - 重新打乱",
"L键 - 加载新图片"
]
for i, text in enumerate(controls):
ctrl_text = font.render(text, True, TEXT_COLOR)
screen.blit(ctrl_text, (50, 70 + i*40))
# 显示当前图片路径
if self.image_path:
path_text = font.render(f"图片: {os.path.basename(self.image_path)}", True, TEXT_COLOR)
screen.blit(path_text, (50, SCREEN_HEIGHT - 50))
# 如果游戏完成,显示胜利信息
if self.game_complete:
# 半透明覆盖层
overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 180))
screen.blit(overlay, (0, 0))
# 胜利文本
win_text = font.render("恭喜! 拼图完成!", True, (76, 209, 55))
restart_text = font.render("按R键重新开始", True, TEXT_COLOR)
screen.blit(win_text, (SCREEN_WIDTH//2 - win_text.get_width()//2,
SCREEN_HEIGHT//2 - 50))
screen.blit(restart_text, (SCREEN_WIDTH//2 - restart_text.get_width()//2,
SCREEN_HEIGHT//2 + 10))
def handle_event(self, event):
"""处理游戏事件"""
if event.type == QUIT:
return False
if self.game_complete and event.type == KEYDOWN and event.key == K_r:
self.shuffle_tiles()
self.game_complete = False
return True
if event.type == KEYDOWN:
if event.key == K_r: # 重新打乱
self.shuffle_tiles()
self.game_complete = False
elif event.key == K_l: # 加载新图片
self.load_new_image()
elif self.selected_tile: # 方向键移动选中的拼图块
row, col = self.selected_tile
if event.key == K_UP:
self.move_tile((row-1, col))
elif event.key == K_DOWN:
self.move_tile((row+1, col))
elif event.key == K_LEFT:
self.move_tile((row, col-1))
elif event.key == K_RIGHT:
self.move_tile((row, col+1))
if event.type == MOUSEBUTTONDOWN:
# 计算点击位置
total_width = GRID_SIZE * (TILE_SIZE + MARGIN) - MARGIN
total_height = GRID_SIZE * (TILE_SIZE + MARGIN) - MARGIN
start_x = (SCREEN_WIDTH - total_width) // 2
start_y = (SCREEN_HEIGHT - total_height) // 2
# 获取鼠标位置
mouse_x, mouse_y = pygame.mouse.get_pos()
# 检查是否在拼图区域内
if (start_x <= mouse_x < start_x + total_width and
start_y <= mouse_y < start_y + total_height):
# 计算点击的网格位置
grid_col = (mouse_x - start_x) // (TILE_SIZE + MARGIN)
grid_row = (mouse_y - start_y) // (TILE_SIZE + MARGIN)
# 检查是否点击了有效的拼图块(不是空白块)
if (grid_row, grid_col) != self.empty_pos:
self.selected_tile = (grid_row, grid_col)
return True
def load_new_image(self):
"""加载新图片(示例中为内置图片,实际使用可替换)"""
# 在实际应用中,这里可以改为打开文件对话框
# 示例使用内置图片路径
images = [
"image1.jpg", # 替换为实际图片路径
"image2.png",
"image3.bmp"
]
new_image = random.choice(images)
self.load_image(new_image)
# 创建游戏实例
game = PuzzleGame()
# 加载初始图片(替换为你的图片路径)
game.load_image("default_puzzle.jpg") # 替换为你的图片路径
# 游戏主循环
clock = pygame.time.Clock()
running = True
while running:
# 处理事件
for event in pygame.event.get():
running = game.handle_event(event)
# 绘制游戏
game.draw(screen)
# 更新显示
pygame.display.flip()
# 控制帧率
clock.tick(60)
# 退出游戏
pygame.quit()
sys.exit()
游戏功能说明
-
核心功能:
- 支持自定义图片加载
- 3x3网格拼图
- 随机打乱拼图块
- 鼠标选择拼图块
- 键盘方向键移动拼图
- 自动检测拼图完成状态
-
操作方式:
- 鼠标点击选择拼图块
- 方向键移动选中的拼图块
- R键:重新打乱拼图
- L键:加载新图片(示例中为随机选择)
-
界面元素:
- 居中显示拼图网格
- 高亮显示选中的拼图块
- 显示操作说明
- 显示当前图片名称
- 拼图完成时显示胜利画面
如何自定义图片
- 准备一张图片(JPG、PNG或BMP格式)
- 修改代码中的图片路径:
# 初始加载图片 game.load_image("your_image.jpg") # 替换为你的图片路径 - 在
load_new_image()方法中添加你的图片列表
扩展建议
-
增加难度:
# 修改网格大小 GRID_SIZE = 4 # 4x4网格 -
添加动画效果:
- 实现拼图块移动动画
- 添加胜利动画
-
添加计时功能:
- 记录玩家完成拼图的时间
- 保存最佳成绩
-
添加音效:
- 移动拼图时的音效
- 完成拼图时的胜利音效
这个拼图游戏项目展示了Pygame的基本应用,包括图像处理、事件处理、用户交互和游戏状态管理。通过修改代码中的常量和添加新功能,你可以进一步扩展和完善这个游戏。
更多推荐
所有评论(0)