纯原创!!!!
项目背景
古诗词是中华文化的瑰宝,如何通过游戏让学习变得有趣?我设计了这款游戏,目标是让玩家在娱乐中熟悉古诗词。项目使用 Python 实现,结合 Pygame 的图形能力和 Tkinter 的界面灵活性,适合初学者学习 GUI 开发。
- 技术栈 :
- Pygame:主菜单和经典模式。
- Tkinter:贪吃蛇模式、弹窗界面。
- MySQL:存储玩家成绩。
- 开发环境 :
- Python 3.11
- Pygame 2.5.2
- Tkinter(内置)
- MySQL Connector 8.0
游戏功能概述
游戏包含以下核心功能:
- 主菜单:提供"经典模式"、"贪吃蛇模式"、"难度选择"、"历史成绩"和"退出"选项。
- 难度选择:支持"简单 (60秒)"、"普通 (30秒)"、"困难 (15秒)"三种难度,影响游戏时间。
- 经典模式:玩家拖动随机散布的文字方块,拼接成完整诗词。
- 贪吃蛇模式:控制蛇吃字符,按顺序完成诗词。
- 历史成绩:记录并展示两种模式的最高分。
- 动态适配:支持长诗词显示,主窗口最大化,弹窗固定大小。
一、游戏界面制作
在开发古诗拼接游戏的过程中,界面设计是核心部分,直接影响玩家的体验。我们使用了 Pygame 和 Tkinter 两种 GUI 框架,分别负责不同模块的界面制作。本节将详细介绍主菜单、经典模式、贪吃蛇模式以及弹窗界面的设计与实现。
1. 主菜单界面
主菜单是玩家的第一印象,需要直观、美观且易操作。我们使用 Pygame 实现,结合背景图片和按钮布局。
-
设计思路 :
- 窗口大小接近全屏(屏幕分辨率减 100 像素),提供沉浸感。
- 按钮分为两组:大按钮(经典模式、贪吃蛇模式、退出)居中,小按钮(难度选择、历史成绩)右下角垂直排列。
- 添加背景图片和鼠标悬停效果,提升视觉体验。
-
实现方式 :
- 使用 pygame.display.set_mode 设置窗口大小。
- 定义按钮列表,包含位置、颜色和字体属性。
- 在 draw 方法中绘制背景和按钮,handle_event 处理点击事件。
-
代码示例 (menu.py):
class Menu: def __init__(self): screen_width, screen_height = pygame.display.Info().current_w - 100, pygame.display.Info().current_h - 100 self.background = pygame.transform.scale(pygame.image.load("assets/images/bg1.png"), (screen_width, screen_height)) self.font_large = pygame.font.Font("assets/fonts/simsunb", 36) self.font_small = pygame.font.Font("assets/fonts/simsunb", 18) self.buttons = [ {"text": "经典模式", "rect": pygame.Rect((screen_width - 300) // 2, screen_height // 4, 300, 80), "font": self.font_large}, {"text": "难度选择", "rect": pygame.Rect(screen_width - 120, screen_height - 75, 100, 25), "font": self.font_small} ] def draw(self, screen): screen.blit(self.background, (0, 0)) for button in self.buttons: pygame.draw.rect(screen, button["current_color"], button["rect"]) text_surf = button["font"].render(button["text"], True, (255, 0, 0)) screen.blit(text_surf, text_surf.get_rect(center=button["rect"].center))
2.经典游戏制作 -
功能概述
- 目标:将打散的古诗词文字方块拖动到正确位置,拼接成完整诗句。
- 规则 :
- 每个方块包含一个字符,初始位置随机,角度随机(0°、90°、180°、270°)。
- 玩家拖动方块到目标槽,双击旋转角度。
- 在限定时间内完成拼接,成功后进入下一首诗。
- 计分:每完成一首诗得 1 分,游戏结束时记录总分。
- 难度:根据难度选择(简单 60秒、普通 30秒、困难 15秒)设置时间限制。
-
界面设计
- 设计思路 :
- 背景:使用古风图片,增强氛围。
- 目标槽:动态排列,支持多行显示长诗词。
- 方块:蓝色矩形,红色文字,可拖动和旋转。
- 信息显示:右上角显示时间和分数,左上角显示目标诗词提示。
- 布局 :
- 窗口最大化(屏幕分辨率减 100 像素)。
- 目标槽垂直居中,水平排列,若超出屏幕宽度则换行。
- 方块随机分布在窗口内。
- 设计思路 :
-
部分代码示例(classic.py)
import pygame
import random
import os
import mysql.connector
from datetime import datetime
import tkinter as tk
from tkinter import ttk
class Classic:
def __init__(self, screen, difficulty="normal"):
self.screen = screen # Pygame 窗口
self.score = 0 # 玩家分数
self.start_time = None # 游戏开始时间
self.time_limit = None # 根据难度设置时间限制
# 加载背景图片
# 初始化字体
# 从 poems.txt 读取诗词
self.poem = None # 当前诗词
self.words = None # 打散的字符列表
self.word_blocks = [] # 文字方块列表(位置、角度等)
self.target_slots = None # 目标槽位
self.last_click_time = 0 # 上次点击时间,用于双击检测
self.game_over = False # 游戏结束标志
def get_next_poem(self):
# 从未使用的诗词中随机选择一首
pass
def calculate_target_slots(self, screen_width, screen_height):
# 动态计算目标槽位,支持长诗词多行显示
# 根据屏幕宽度确定每行槽数
# 计算所需行数并居中排列
pass
def draw(self, screen):
# 绘制背景
# 计算剩余时间并显示
# 显示分数
# 绘制目标槽(灰色框)
# 绘制每行目标线
# 绘制文字方块(蓝色矩形,红色文字,支持旋转)
# 显示目标诗词提示
pass
def handle_event(self, event, mouse_pos):
# 处理鼠标按下:选中方块,双击旋转
# 处理鼠标松开:取消选中
# 处理鼠标移动:拖动方块
# 检查时间是否耗尽,弹出分数窗口
# 检查拼接是否完成,刷新下一首诗
pass
def check_completion(self):
# 检查所有方块是否在正确位置且角度为 0
pass
def show_score_popup(self):
# 创建 Tkinter 弹窗
# 显示分数,输入姓名
# 保存成绩后关闭
pass
def save_score(self, name):
# 连接 MySQL 数据库
# 插入玩家姓名、分数和时间
pass
if __name__ == "__main__":
# 初始化 Pygame
# 设置测试窗口
# 创建 Classic 实例并运行测试循环
pass
3.贪吃蛇游戏制作
-
贪吃蛇模式是古诗拼接游戏的第二种玩法,玩家通过控制一条蛇吃掉屏幕上的字符,按顺序拼接成完整的古诗词。这一模式结合了经典贪吃蛇游戏的动态性与古诗词学习的教育价值。本节将介绍其功能、界面设计、实现方式和关键代码。
-
功能概述
- 目标:控制蛇吃掉诗词中的字符,按顺序完成整首诗。
- 规则 :
- 蛇初始包含诗词的第一个字符,玩家通过方向键控制移动。
- 屏幕上生成食物(下一个所需字符),蛇吃到后增长并更新目标。
- 完成一首诗后刷新新诗词。
- 计分:每完成一首诗得 1 分,游戏结束时记录总分。
- 难度:根据难度选择(简单 60秒、普通 30秒、困难 15秒)设置时间限制。
-
界面设计
- 设计思路 :
- 窗口:最大化(屏幕分辨率减 100 像素),提供足够活动空间。
- 蛇:蓝色矩形,白色文字,表示当前收集的字符。
- 食物:红色矩形,白色文字,表示下一个目标字符。
- 信息:右上角显示时间和分数,左上角显示目标诗词提示。
- 布局 :
- 使用 Tkinter 的 Canvas 绘制动态元素。
- 元素大小固定(60x60),位置根据屏幕动态计算。
- 设计思路 :
-
部分代码示例(snake.py)
import tkinter as tk
from tkinter import ttk
import random
class Snake:
def __init__(self, difficulty="normal"):
self.root = tk.Tk()
self.root.title("贪吃蛇模式")
# 设置窗口大小
self.canvas = tk.Canvas(self.root, bg="black")
self.score = 0
self.time_limit = None # 根据难度设置
# 加载诗词
self.poem = None
self.snake = [] # 初始蛇
self.direction = "Right"
self.remaining_chars = None
self.food = None
# 创建时间和分数标签
# 绑定方向键
self.game_over = False
# 开始移动
def get_next_poem(self):
# 随机选择新诗词
pass
def spawn_food(self):
# 生成下一个字符的食物
pass
def draw(self):
# 绘制蛇和食物
# 更新信息显示
pass
def change_direction(self, direction):
# 更新移动方向
pass
def move_snake(self):
# 移动蛇
# 检查吃食物
# 检查游戏结束
# 递归调用
pass
def check_collision(self):
# 检查是否撞墙
pass
def show_score_popup(self):
# 显示分数弹窗
pass
def save_score(self, name):
# 保存成绩到数据库
pass
if __name__ == "__main__":
# 创建实例并运行
pass

*
4.难度选择和历史记录展示的制作
-
难度选择
- 目标:让玩家选择游戏难度,影响时间限制。
- 规则 :
- 提供"简单 (60秒)"、"普通 (30秒)"、"困难 (15秒)"三个选项。
- 默认选择"普通",点击确认后返回难度值。
- 用途:难度值传递给经典模式和贪吃蛇模式,调整游戏体验。
-
历史记录展示
- 目标:展示经典模式和贪吃蛇模式的玩家成绩。
- 规则 :
- 显示前 10 名成绩,包括姓名、分数和时间。
- 支持切换模式查看(经典或贪吃蛇)。
- 数据来源:从 MySQL 数据库读取。
-
界面设计
难度选择界面
- 设计思路 :
- 固定窗口(300x200),简洁明了。
- 使用单选按钮(Radiobutton)列出选项。
- 添加标题和确认按钮。
- 布局 :
- 标题居中,选项垂直排列,按钮底部居中。
- 设计思路 :
-
历史记录界面
- 设计思路 :
- 固定窗口(600x400),容纳表格。
- 使用 Treeview 表格展示成绩,单选按钮切换模式。
- 添加返回按钮。
- 布局 :
- 标题顶部,模式选择左上,表格占主要空间,按钮底部。
- 设计思路 :
-
代码框架(difficulty.py)
import tkinter as tk
from tkinter import ttk
class Difficulty:
def __init__(self):
self.root = tk.Tk()
self.root.title("难度选择")
self.root.geometry("300x200")
self.root.resizable(False, False)
self.frame = ttk.Frame(self.root, padding="10")
self.frame.pack(fill="both", expand=True)
# 添加标题
self.difficulty_var = tk.StringVar(value="normal")
# 添加难度选项
# 添加确认按钮
self.root.mainloop()
def get_difficulty(self):
# 返回选择的难度
pass
if __name__ == "__main__":
# 测试运行
pass
代码框架(history.py)
*
import tkinter as tk
from tkinter import ttk
import mysql.connector
class History:
def __init__(self):
self.root = tk.Tk()
self.root.title("历史成绩")
self.root.geometry("600x400")
self.root.resizable(False, False)
self.frame = ttk.Frame(self.root, padding="10")
self.frame.pack(fill="both", expand=True)
# 添加标题
self.mode_var = tk.StringVar(value="classic")
# 添加模式选择按钮
self.tree_frame = ttk.Frame(self.frame)
self.tree_frame.pack(fill="both", expand=True)
self.tree = ttk.Treeview(self.tree_frame, columns=("name", "score", "time"), show="headings", height=10)
# 设置表格列
# 添加滚动条
# 添加返回按钮
self.update_scores()
self.root.mainloop()
def update_scores(self):
# 清空表格
# 连接数据库
# 查询并显示成绩
pass
if __name__ == "__main__":
# 测试运行
pass

5.主函数的制作
-
功能概述
- 目标:启动游戏,管理模式切换,提供统一的运行循环。
- 职责 :
- 初始化 Pygame 环境,设置主窗口。
- 跟踪当前难度和游戏状态(菜单、经典模式、贪吃蛇模式)。
- 调用其他模块(menu.py, classic.py, snake.py, difficulty.py, history.py)。
- 处理窗口重置,确保 Pygame 和 Tkinter 无冲突。
-
代码(main.py)
import pygame
import random
import os
import mysql.connector
from datetime import datetime
import tkinter as tk
from tkinter import ttk
class Classic:
def __init__(self, screen, difficulty="normal"):
self.screen = screen
self.score = 0
self.start_time = pygame.time.get_ticks()
self.time_limit = {"easy": 60000, "normal": 30000, "hard": 15000}.get(difficulty, 30000)
screen_width, screen_height = screen.get_width(), screen.get_height()
try:
self.background = pygame.image.load("assets/images/bg1.png")
self.background = pygame.transform.scale(self.background, (screen_width, screen_height))
except FileNotFoundError:
self.background = None
font_path = "assets/fonts/simsunb"
if os.path.exists(font_path):
self.font = pygame.font.Font(font_path, 48)
else:
self.font = pygame.font.SysFont("microsoftyahei", 48) or pygame.font.SysFont("simsun", 48)
try:
with open("data/poems.txt", "r", encoding="utf-8") as f:
self.all_poems = [line.strip() for line in f.readlines() if line.strip()]
self.used_poems = []
self.poem = self.get_next_poem()
except FileNotFoundError:
self.all_poems = ["床前明月光"]
self.used_poems = []
self.poem = "床前明月光"
self.words = list(self.poem)
random.shuffle(self.words)
self.word_blocks = []
for i, char in enumerate(self.words):
x = random.randint(50, screen_width - 50)
y = random.randint(50, screen_height - 50)
angle = random.choice([0, 90, 180, 270])
self.word_blocks.append(
{"text": char, "rect": pygame.Rect(x, y, 60, 60), "selected": False, "angle": angle})
# 动态计算目标槽位置(支持换行)
self.target_slots = self.calculate_target_slots(screen_width, screen_height)
self.last_click_time = 0
self.double_click_threshold = 300
self.end_time = None
self.game_over = False
def get_next_poem(self):
available_poems = [p for p in self.all_poems if p not in self.used_poems]
if not available_poems:
self.used_poems = []
available_poems = self.all_poems[:]
poem = random.choice(available_poems)
self.used_poems.append(poem)
return poem
def calculate_target_slots(self, screen_width, screen_height):
slot_width = 80
max_slots_per_row = (screen_width - 200) // slot_width # 左右各留 100 像素
rows_needed = (len(self.words) + max_slots_per_row - 1) // max_slots_per_row
start_y = screen_height // 2 - (rows_needed * 60) // 2 # 垂直居中
slots = []
for i, char in enumerate(self.words):
row = i // max_slots_per_row
col = i % max_slots_per_row
x = 100 + col * slot_width # 左边留 100 像素
y = start_y + row * 60 # 每行间隔 60 像素
slots.append(pygame.Rect(x, y - 30, 60, 60))
return slots
def draw(self, screen):
if self.background:
screen.blit(self.background, (0, 0))
else:
screen.fill((0, 0, 0))
elapsed_time = pygame.time.get_ticks() - self.start_time
remaining_time = max(0, (self.time_limit - elapsed_time) // 1000)
time_text = self.font.render(f"时间: {remaining_time}s", True, (255, 0, 0))
screen.blit(time_text, (screen.get_width() - 200, 20))
score_text = self.font.render(f"分数: {self.score}", True, (255, 0, 0))
screen.blit(score_text, (screen.get_width() - 200, 80))
# 绘制目标槽和线
for slot in self.target_slots:
pygame.draw.rect(screen, (150, 150, 150), slot, 1)
for row in range(
(len(self.words) + (screen.get_width() - 200) // 80 - 1) // ((screen.get_width() - 200) // 80)):
y = self.target_slots[row * ((screen.get_width() - 200) // 80)].centery
pygame.draw.line(screen, (255, 255, 255), (100, y), (screen.get_width() - 100, y), 2)
# 绘制方块
for block in self.word_blocks:
pygame.draw.rect(screen, (100, 150, 200), block["rect"])
text_surf = self.font.render(block["text"], True, (255, 0, 0))
rotated_surf = pygame.transform.rotate(text_surf, block["angle"])
rotated_rect = rotated_surf.get_rect(center=block["rect"].center)
screen.blit(rotated_surf, rotated_rect)
# 绘制目标诗词(提示)
hint = self.font.render(f"目标: {self.poem}", True, (255, 0, 0))
screen.blit(hint, (50, 50))
def handle_event(self, event, mouse_pos):
current_time = pygame.time.get_ticks()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
for block in self.word_blocks:
if block["rect"].collidepoint(mouse_pos):
block["selected"] = True
if current_time - self.last_click_time <= self.double_click_threshold:
block["angle"] = (block["angle"] + 90) % 360
self.last_click_time = current_time
elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
for block in self.word_blocks:
block["selected"] = False
elif event.type == pygame.MOUSEMOTION:
for block in self.word_blocks:
if block["selected"]:
block["rect"].move_ip(event.rel)
block["rect"].clamp_ip(self.screen.get_rect())
elapsed_time = current_time - self.start_time
if elapsed_time >= self.time_limit and not self.game_over:
self.end_time = datetime.now()
self.game_over = True
self.show_score_popup()
return "menu"
if self.check_completion():
self.score += 1
self.poem = self.get_next_poem()
self.words = list(self.poem)
random.shuffle(self.words)
self.word_blocks = []
screen_width = self.screen.get_width()
screen_height = self.screen.get_height()
for i, char in enumerate(self.words):
x = random.randint(50, screen_width - 50)
y = random.randint(50, screen_height - 50)
angle = random.choice([0, 90, 180, 270])
self.word_blocks.append(
{"text": char, "rect": pygame.Rect(x, y, 60, 60), "selected": False, "angle": angle})
self.target_slots = self.calculate_target_slots(screen_width, screen_height)
return None
def check_completion(self):
aligned = [None] * len(self.words)
for block in self.word_blocks:
for i, slot in enumerate(self.target_slots):
if slot.collidepoint(block["rect"].center) and block["angle"] == 0:
aligned[i] = block["text"]
break
return aligned == list(self.poem)
def show_score_popup(self):
popup = tk.Tk()
popup.title("游戏结束")
popup.geometry("300x150")
popup.resizable(False, False)
label = ttk.Label(popup, text=f"您获得了 {self.score} 分,请输入你的名称:")
label.pack(pady=10)
entry = ttk.Entry(popup)
entry.pack(pady=10)
entry.focus_set()
def on_confirm():
name = entry.get()
self.save_score(name)
popup.destroy()
button = ttk.Button(popup, text="确定", command=on_confirm)
button.pack(pady=10)
popup.mainloop()
def save_score(self, name):
conn = mysql.connector.connect(
host="localhost",
user="root",
password="root",
database="chinese"
)
cursor = conn.cursor()
query = "INSERT INTO score (name, score, time) VALUES (%s, %s, %s)"
values = (name or "Anonymous", self.score, self.end_time)
cursor.execute(query, values)
conn.commit()
cursor.close()
conn.close()
if __name__ == "__main__":
pygame.init()
screen_info = pygame.display.Info()
screen = pygame.display.set_mode((screen_info.current_w - 100, screen_info.current_h - 100))
pygame.display.set_caption("古诗拼接游戏 - 经典模式测试")
clock = pygame.time.Clock()
game = Classic(screen)
running = True
while running:
mouse_pos = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
result = game.handle_event(event, mouse_pos)
if result == "menu":
running = False
game.draw(screen)
pygame.display.flip()
clock.tick(60)
pygame.quit()
三、总结
经过一系列的设计与开发,古诗拼接游戏从概念变为一个功能完整的程序。通过主菜单、经典模式、贪吃蛇模式、难度选择和历史记录的整合,我们实现了一个兼具娱乐性和教育意义的小游戏。本节将回顾开发成果,分享经验教训,并展望未来改进方向。
1. 开发成果
- 功能完善 :
- 主菜单:Pygame 实现的动态界面,提供清晰的功能入口。
- 经典模式:拖动文字拼接诗词,支持长诗词多行显示。
- 贪吃蛇模式:Tkinter 实现的动态玩法,吃字符完成诗词。
- 难度选择:三档难度调整游戏时间,增加灵活性。
- 历史记录:展示前 10 名成绩,记录玩家成就。
- 技术实现 :
- 结合 Pygame 和 Tkinter,解决了混合 GUI 的冲突。
- 使用 MySQL 存储成绩,实现数据持久化。
- 主函数通过状态机管理模块切换,保证流程顺畅。
- 用户体验 :
- 窗口最大化适配大屏幕,弹窗固定大小保持一致性。
- 界面简洁,交互直观,适合学习古诗词的玩家。
2. 经验教训
-
- GUI 框架选择 :
- Pygame 适合动态渲染(如经典模式),但弹窗功能较弱;Tkinter 擅长静态交互(如难度选择),但动画实现复杂。混合使用需谨慎管理生命周期。
- 线程管理 :
- 初期未正确关闭 Pygame 或 Tkinter 窗口,导致卡顿。通过 pygame.display.quit() 和 root.destroy() 重置状态解决了问题。
- 界面适配 :
- 长诗词显示和按钮布局需动态调整,静态设计易溢出。开发中增加了 calculate_target_slots 和按钮分组逻辑。
- 代码结构 :
- 模块化设计提高了可维护性,但初期未规划好接口(如难度传递),后期调整增加了工作量。
- GUI 框架选择 :
3. 未来改进方向
-
- 功能扩展 :
- 添加音效(如吃食物音效、完成诗词提示音),提升沉浸感。
- 引入更多诗词类型(如唐诗、宋词分类),增加教育深度。
- 支持多人模式,通过网络排行榜竞争。
- 界面优化 :
- 长诗词提示支持换行或滚动显示,避免溢出。
- 按钮和方块支持自定义皮肤,增强个性化。
- 性能提升 :
- 优化贪吃蛇模式的长蛇移动逻辑,减少计算开销。
- 预加载背景图片和字体,缩短启动时间。
- 跨平台支持 :
- 测试并适配 macOS 和 Linux,确保兼容性。
- 打包为可执行文件(如 PyInstaller),方便分发。
- 功能扩展 :