毕业设计----用python制作的古诗词拼接接龙游戏

纯原创!!!!

项目背景

古诗词是中华文化的瑰宝,如何通过游戏让学习变得有趣?我设计了这款游戏,目标是让玩家在娱乐中熟悉古诗词。项目使用 Python 实现,结合 Pygame 的图形能力和 Tkinter 的界面灵活性,适合初学者学习 GUI 开发。

  • 技术栈
    • Pygame:主菜单和经典模式。
    • Tkinter:贪吃蛇模式、弹窗界面。
    • MySQL:存储玩家成绩。
  • 开发环境
    • Python 3.11
    • Pygame 2.5.2
    • Tkinter(内置)
    • MySQL Connector 8.0

游戏功能概述

游戏包含以下核心功能:

  1. 主菜单:提供"经典模式"、"贪吃蛇模式"、"难度选择"、"历史成绩"和"退出"选项。
  2. 难度选择:支持"简单 (60秒)"、"普通 (30秒)"、"困难 (15秒)"三种难度,影响游戏时间。
  3. 经典模式:玩家拖动随机散布的文字方块,拼接成完整诗词。
  4. 贪吃蛇模式:控制蛇吃字符,按顺序完成诗词。
  5. 历史成绩:记录并展示两种模式的最高分。
  6. 动态适配:支持长诗词显示,主窗口最大化,弹窗固定大小。

一、游戏界面制作

在开发古诗拼接游戏的过程中,界面设计是核心部分,直接影响玩家的体验。我们使用了 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 和按钮分组逻辑。
    • 代码结构
      • 模块化设计提高了可维护性,但初期未规划好接口(如难度传递),后期调整增加了工作量。

3. 未来改进方向

    • 功能扩展
      • 添加音效(如吃食物音效、完成诗词提示音),提升沉浸感。
      • 引入更多诗词类型(如唐诗、宋词分类),增加教育深度。
      • 支持多人模式,通过网络排行榜竞争。
    • 界面优化
      • 长诗词提示支持换行或滚动显示,避免溢出。
      • 按钮和方块支持自定义皮肤,增强个性化。
    • 性能提升
      • 优化贪吃蛇模式的长蛇移动逻辑,减少计算开销。
      • 预加载背景图片和字体,缩短启动时间。
    • 跨平台支持
      • 测试并适配 macOS 和 Linux,确保兼容性。
      • 打包为可执行文件(如 PyInstaller),方便分发。
相关推荐
Full Stack Developme1 分钟前
Spring Security 与 Apache Shiro 两大安全框架比较
spring boot·python·安全
tobias.b4 分钟前
408真题解析-2009-10-数据结构-排序
数据结构·算法·排序算法·408考研·408真题·真题解析
杰瑞哥哥5 分钟前
快速搭建Web前端(streamlit使用指南)
python·信息可视化·web·模型部署
小途软件7 分钟前
基于计算机视觉的课堂行为编码研究
人工智能·python·深度学习·计算机视觉·语言模型·自然语言处理·django
Zachary_zlc7 分钟前
有向无环图检测算法和关键路径算法
算法
智航GIS7 分钟前
9.2 多进程入门
数据库·python
小途软件8 分钟前
基于计算机视觉的桥梁索力测试方法
人工智能·python·语言模型·自然语言处理·django
你撅嘴真丑9 分钟前
素数回文数的个数 与 求分数序列和
算法
好奇龙猫11 分钟前
【大学院-筆記試験練習:线性代数和数据结构(2)】
数据结构·线性代数·决策树
yousuotu15 分钟前
基于Python实现水果新鲜度分类
开发语言·python·分类