• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

qingmu177

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

软件工程第二次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2024
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13253
这个作业的目标 增强python语言的编程能力,学会运用AIGC工具辅助写代码;初步掌握开发步骤
学号 102201317

一、项目展示

源代码已上传至github仓库:
https://github.com/qingmu177/my_homework/tree/software-engineering_second-homework

二、项目介绍

一 所使用的技术和特殊的算法

运用了Pygame库。主要用来进行图像加载与缩放,窗口渲染,对事件处理

主算法展示:

# 主菜单函数
def main_menu():
   """显示主菜单"""
   pygame.init()  # 初始化pygame
   screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))  # 创建窗口
   pygame.display.set_caption('石了个石 - 主菜单')  # 设置窗口标题
   font = pygame.font.Font(pygame.font.match_font('simhei'), 50)  # 创建主标题字体
   small_font = pygame.font.Font(pygame.font.match_font('simhei'), 30)  # 创建菜单选项字体
   menu_options = ["简单模式", "普通模式", "困难模式", "排行榜", "退出"]  # 菜单选项
   selected_option = 0  # 当前选中的选项索引

   while True:
       background = load_background_image(MAIN_BG)  # 使用主菜单背景
       screen.blit(background, (0, 0))  # 绘制背景

       title_text = font.render("石了个石_陈石石石", True, BLACK)  # 渲染标题文本
       screen.blit(title_text, (WINDOW_WIDTH // 2 - title_text.get_width() // 2, 100))  # 显示标题文本

       # 显示菜单选项
       for index, option in enumerate(menu_options):
           color = RED if index == selected_option else WHITE  # 选中的选项为红色,其他为白色
           menu_text = small_font.render(option, True, color)  # 渲染菜单文本
           screen.blit(menu_text, (WINDOW_WIDTH // 2 - menu_text.get_width() // 2, 300 + index * 50))  # 显示菜单选项

       for event in pygame.event.get():  # 处理事件
           if event.type == QUIT:  # 如果退出事件
               pygame.quit()  # 退出pygame
               sys.exit()  # 退出程序
           elif event.type == KEYDOWN:  # 如果按下键盘
               if event.key == K_UP:  # 向上箭头
                   selected_option = (selected_option - 1) % len(menu_options)  # 选择上一个选项
               elif event.key == K_DOWN:  # 向下箭头
                   selected_option = (selected_option + 1) % len(menu_options)  # 选择下一个选项
               elif event.key == K_RETURN:  # 回车键
                   if selected_option == 0:  # 简单模式
                       game_loop(difficulty="easy")  # 启动简单模式游戏
                   elif selected_option == 1:  # 普通模式
                       game_loop(difficulty="normal")  # 启动普通模式游戏
                   elif selected_option == 2:  # 困难模式
                       game_loop(difficulty="hard")  # 启动困难模式游戏
                   elif selected_option == 3:  # 排行榜
                       show_leaderboard(screen)  # 显示排行榜
                   elif selected_option == 4:  # 退出
                       pygame.quit()  # 退出pygame
                       sys.exit()  # 退出程序

       pygame.display.flip()  # 更新显示

# 游戏循环函数,包含难度级别
def game_loop(difficulty):
   """游戏主循环"""
   pygame.init()  # 初始化pygame
   play_surface = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))  # 创建游戏窗口
   pygame.display.set_caption(f'石了个石 - {difficulty.capitalize()} 模式')  # 设置窗口标题

   # 根据难度设置图像数量和时间限制
   if difficulty == "easy":
       used_image_count = 7
       time_limit = 180
   elif difficulty == "normal":
       used_image_count = 10
       time_limit = 180
   elif difficulty == "hard":
       used_image_count = 15
       time_limit = 90

   images = load_sheep_images(used_image_count)  # 加载图像

   font = pygame.font.Font(pygame.font.match_font('simhei'), 25)  # 创建游戏字体
   fps_clock = pygame.time.Clock()  # 创建时钟对象

   grid_cols = 8  # 网格列数
   grid_rows = 5  # 网格行数
   offset_x = (WINDOW_WIDTH - (grid_cols * (ICON_SIZE + 10))) // 2  # 水平偏移量
   offset_y = (WINDOW_HEIGHT - (grid_rows * (ICON_SIZE + 10))) // 2  # 垂直偏移量
   max_item_count = 7  # 最大物品数量
   item_count = 3  # 当前物品数量
   store = [0] * max_item_count  # 存储区初始化
   score = 0  # 当前得分
   total_score = 0  # 总得分
   seconds = time_limit  # 剩余时间

   start_ticks = pygame.time.get_ticks()  # 记录游戏开始时间

   # 生成游戏网格
   layers = generate_solvable_grid(used_image_count, grid_cols, grid_rows)

   selected_icons = []  # 选中的图标列表
   move_history = []  # 移动历史记录

   while True:
       background = load_background_image(GAME_BG)  # 使用游戏背景
       play_surface.blit(background, (0, 0))  # 绘制背景

       seconds = time_limit - (pygame.time.get_ticks() - start_ticks) // 1000  # 计算剩余时间

       # 绘制图标网格
       for r in range(grid_rows):  # 遍历行
           for c in range(grid_cols):  # 遍历列
               x = offset_x + c * (ICON_SIZE + 10)  # 计算图标的x坐标
               base_y = offset_y + r * (ICON_SIZE + 10)  # 计算图标的基准y坐标
               if layers[r][c]:  # 如果该格子有物品
                   stack_height = len(layers[r][c])  # 堆叠高度
                   for level in range(stack_height):  # 遍历堆叠的每一层
                       icon_index = layers[r][c][level]  # 获取当前层的图标索引
                       y = base_y - level * int(ICON_SIZE * OVERLAP_PERCENTAGE)  # 计算图标的y坐标
                       play_surface.blit(images[icon_index], (x, y))  # 绘制图标

       # 绘制存储区
       storage_x = WINDOW_WIDTH // 2 - (max_item_count * ICON_SIZE) // 2  # 存储区x坐标
       storage_y = WINDOW_HEIGHT - 100  # 存储区y坐标
       for i in range(max_item_count):  # 遍历存储区
           pygame.draw.rect(play_surface, STORAGE_BOX_COLOR,  # 绘制存储框
                            (storage_x + i * ICON_SIZE, storage_y, ICON_SIZE, ICON_SIZE))
           if store[i]:  # 如果存储区有物品
               play_surface.blit(images[store[i] - 1], (storage_x + i * ICON_SIZE, storage_y))  # 绘制物品

       # 显示分数和计时器
       mission_text = f"总分: {total_score}"  # 总分文本
       score_text = f"当前分数: {score}"  # 当前分数文本
       countdown_text = f"时间: {seconds}"  # 剩余时间文本

       play_surface.blit(font.render(mission_text, True, RED), (10, 10))  # 显示总分
       play_surface.blit(font.render(score_text, True, GREEN), (10, 40))  # 显示当前分数
       play_surface.blit(font.render(countdown_text, True, GREEN), (WINDOW_WIDTH / 2 - 50, 10))  # 显示剩余时间

       for event in pygame.event.get():  # 处理事件
           if event.type == QUIT:  # 如果退出事件
               pygame.quit()  # 退出pygame
               sys.exit()  # 退出程序
           if event.type == MOUSEBUTTONUP:  # 鼠标点击事件
               (mouse_x, mouse_y) = event.pos  # 获取鼠标点击位置
               for r in range(grid_rows):  # 遍历行
                   for c in range(grid_cols):  # 遍历列
                       x = offset_x + c * (ICON_SIZE + 10)  # 计算图标的x坐标
                       base_y = offset_y + r * (ICON_SIZE + 10)  # 计算图标的基准y坐标
                       if layers[r][c]:  # 如果该格子有物品
                           top_image_y = base_y - (len(layers[r][c]) - 1) * int(ICON_SIZE * OVERLAP_PERCENTAGE)  # 顶层图标y坐标
                           # 检查鼠标点击位置是否在图标上
                           if x < mouse_x < x + ICON_SIZE and top_image_y < mouse_y < top_image_y + ICON_SIZE:
                               clicked_icon = layers[r][c].pop()  # 获取被点击的图标
                               move_history.append((r, c, clicked_icon + 1))  # 记录移动历史
                               for i in range(7):  # 将图标放入存储区
                                   if store[i] == 0:  # 找到空位
                                       store[i] = clicked_icon + 1  # 放入图标
                                       break

                               # 检查是否消除
                               if store.count(clicked_icon + 1) == 3:
                                   store = [0 if icon == clicked_icon + 1 else icon for icon in store]  # 清空对应的图标
                                   score += 10  # 每次消除得分
                                   total_score += 10  # 更新总分

                                   if score > 20:  # 每20分增加一个存储位
                                       item_count = min(item_count + 1, max_item_count)  # 增加物品数量
                                       score = 0  # 重置当前得分

           if event.type == KEYDOWN:  # 按键事件
               if event.key == K_BACKSPACE:  # 用户按下退格键来悔棋
                   undo_last_move(layers, store, move_history)  # 进行悔棋操作

       if seconds <= 0:  # 如果时间结束
           show_defeat_screen(play_surface)  # 显示失败界面
       if all(store) and not any(store.count(icon) == 3 for icon in store if icon != 0):  # 存储区已满且没有消除
           show_defeat_screen(play_surface)  # 显示失败界面

       if not any(layers[r][c] for r in range(grid_rows) for c in range(grid_cols)):  # 如果网格没有物品
           show_victory_screen(play_surface, total_score)  # 显示胜利界面

       pygame.display.flip()  # 刷新窗口
       fps_clock.tick(30)  # 控制帧率

二 前端设计与特色功能

界面设计以简洁、易用为原则,通过合理的图像布局和色彩搭配增强用户的游戏体验。

主菜单界面:包含5个菜单,简单模式、普通模式、困难模式、排行榜、退出。
  通过红色高亮提示用户所选中的菜单,用户按下【enter】键进入菜单。
游戏界面:
  游戏背景通过GAME_BG加载,所有游戏元素)都采用居中的布局方式
如图:
胜利与失败界面:
  胜利和失败界面分别使用了不同的背景图像,通过绿色和红色字体分别展示胜利或失败的状态。界面颜色搭配明确,强化视觉冲击力。


难度设置:
  分为简单、普通、困难三种难度,不同难度下图标种类不同,限定时间也不同(困难模式时间为90s图标为15种,其他模式180s,图标最多10种);
如图


增添了道具,撤销功能,用户点击【backspace】键即可“悔棋”
如图:

三、测试

一 图标过多问题:

图标过多且过于重复降低了用户兴趣。

评价:测试用例满足程序测试了需求;
解决:重新编写图标生成逻辑,使图表数量合理。

二 增添背景后图标大小异常问题


评价:测试用例满足程序测试了需求;
解决:重新编写背景添加逻辑,达到图标大小正常的目标

四、AIGC表格/心得体会

项目内容 学习到的内容和心得体会
Pygame 初始化和窗口创建 学习了如何使用 pygame 库初始化游戏环境和创建窗口。如何设置窗口标题和大小。
图像绘制和界面更新 学会了如何加载图像和调整图像大小。
图像加载与处理 学习了如何计算图像的绘制位置并处理重叠问题。
游戏逻辑和计时 掌握了如何实现游戏计时和逻辑处理。通过 pygame.time.get_ticks() 记录时间,计算剩余时间,并在游戏中添加计时功能。了解了如何处理游戏胜利和失败的条件,并相应地调用不同的界面显示函数
排行榜和分数管理 学习了使用文件读写操作(open, readlines, write)来保存和加载分数。
可解的网格生成 学会了如何生成可解的游戏网格。了解了如何计算每种图像的数量,并使用 shuffle 打乱图像列表以生成随机网格。掌握了如何创建游戏网格并确保网格是可解的。

心得体会:

一个项目的开发是很复杂的,我掌握了 pygame 的基本使用,增强了我在游戏开发中的综合能力。通过实际的编码和调试,我学会了如何将不同的功能集成到一个完整的游戏中,并初步学会了处理实际开发中的各种问题。

五、PSP表格

任务 工作内容 时间
需求分析 确定游戏功能需求、界面设计、游戏逻辑等。 1h
界面设计 设计游戏主菜单、游戏界面、胜利和失败界面等。 2h
主菜单实现、游戏逻辑实现、胜利,失败界面实现、存储区和悔棋功能实现 逐步调试代码,确保游戏逻辑按照预期运行。 4h
测试修改代码 编写测试用例,进行详细测试,并记录问题。 3h

总结评价:

需求分析用的时间过长。
测试代码所耗费时间过多,还需改进。

posted on 2024-09-18 23:56  qingmu177  阅读(46)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3