软件工程第二次作业

软件工程第二次个人作业:一箭又一箭小游戏

项目 内容
这个作业属于哪个课程 202601 软件工程班级博客
这个作业要求在哪里 第二次个人作业要求
这个作业的目标 使用 Python 和 AIGC 完成 "一箭又一箭" 小游戏
学号 102401405
GitHub 仓库 https://github.com/wiyiti/one-arrow-game

一、项目展示

1.1 开始界面

游戏启动后显示标题 "一箭又一箭",包含 "开始游戏" 和 "选择关卡" 两个按钮。

1.2 选关界面

以网格展示 7 个关卡,通关后自动解锁下一关,已通关的关卡显示金色星星。

1.3 游戏界面

顶部 HUD 显示当前关卡、剩余箭头数、失误次数、实时星级和倒计时。中部为游戏棋盘,四种方向的箭头分别用不同颜色表示(上 = 绿、下 = 蓝、左 = 橙、右 = 紫)。底部有撤销、提示、自动求解三个功能按钮。

1.4 碰撞 / 失误反馈

点击被挡住的箭头后,箭头沿方向飞出一段距离再弹回,同时变红,失误次数减 1,失去一颗星。

1.5 提示功能

点击 "提示" 按钮,程序会找到一个当前可以消除的箭头,用金色闪烁框高亮显示 2.5 秒。

1.6 失败界面

失误次数用完或时间耗尽时,显示失败原因,点击任意处重新开始。

1.7 第一关演示 GIF

1.8 可解性测试

运行 python ``test_game.py 可自动验证 T01-T06 用例,并输出每关的棋盘尺寸、箭头数和通关步数:


二、项目介绍

2.1 游戏规则

棋盘中分布着上、下、左、右四个方向的箭头。玩家点击箭头后:

  1. 如果箭头到棋盘边界之间没有其他箭头阻挡,箭头飞出棋盘并被消除;

  2. 如果路径上存在其他箭头,箭头不能飞出,会沿方向弹出一段再弹回并变红,同时消耗 1 次失误;

  3. 每关限失误 3 次、限时 75 秒,任一耗尽则本关失败;

  4. 清空棋盘全部箭头即通关,按剩余失误评 1-3 颗星;

  5. 共 7 个关卡,按顺序解锁,进度自动保存。

2.2 界面设计

游戏采用暖色调简约风格,背景为米白色(RGB 245,240,230),棋盘为浅棕色圆角矩形,整体视觉柔和不刺眼。HUD 区域分为三行排列:

  • 第一行:返回按钮、当前关卡、重开本关按钮
  • 第二行:剩余箭头数、失误次数、实时星级、倒计时
  • 第三行:撤销、提示、自动求解三个功能按钮

四种方向的箭头各有专属配色:上=绿色、下=蓝色、左=橙色、右=紫色,配合带箭杆的实心箭头造型,玩家一眼就能分辨方向。箭头使用 2 倍超采样离屏渲染后平滑缩放,边缘无锯齿。

2.3 主要功能

基础功能:

  • 完整三界面:开始界面、游戏界面、通关 / 失败界面

  • 四方向箭头,鼠标点击操作

  • 同行 / 同列路径检测,正确判断阻挡

  • 箭头飞出动画、碰撞弹回动画

  • 失误计数、重新开始、关卡切换

附加功能:

  • 75 秒倒计时,最后 10 秒变红警告

  • 三星评价,实时显示在 HUD 上

  • 选关界面,按进度解锁

  • 提示功能(金色闪烁高亮可消除箭头)

  • 撤销上一步(恢复上一个被消除的箭头)

  • AI 自动求解(回溯算法自动演示通关)

  • 本地存档(progress.json 记录解锁进度和星级)

  • 抗锯齿箭头渲染(2 倍超采样)

2.4 游戏特色

  1. 碰撞反馈生动:被挡住的箭头不是简单晃动,而是沿方向弹出一段距离再弹回原位,同时变红,直观展示"撞到东西了"
  2. 实时星级评价:HUD 上始终显示当前星级,每失误一次金色星星变灰一颗,不用等到通关才知道评价
  3. 智能提示:卡住时点"提示",金色闪烁框标出一个当前可以消除的箭头,帮助玩家理清思路
  4. 撤销反悔:点错了不用重开,撤销按钮恢复上一个被消除的箭头
  5. AI 自动求解:回溯算法自动寻找通关路径并逐步演示,既能看完整解法,也能验证关卡可解性
  6. 难度递进:7 个关卡按箭头数量从 5 个逐步增加到 14 个,棋盘从 3×3 扩展到 5×5,难度平缓上升
  7. 本地存档:通关进度和星级自动保存到 progress.json,下次打开继续玩

三、实现思路

3.1 箭头、方向与关卡的表示

方向用字典映射为方向向量:

DIRS = {'U': (-1, 0), 'D': (1, 0), 'L': (0, -1), 'R': (0, 1)}

棋盘用二维列表表示,单元格为 None(空格)或 'U'/'D'/'L'/'R':

grid = [
    ['R', None, 'D'],
    [None, 'U', None],
    ['U', None, 'R'],
]

每个关卡就是一个这样的二维数组,7 个关卡按箭头数量从少到多排列(5→6→8→10→11→12→14)。

3.2 路径检测

这是游戏的核心逻辑。点击一个箭头后,从箭头相邻格子开始,沿方向向量逐格遍历:

def is_blocked(self, row, col):
    d = self.grid[row][col]
    dr, dc = DIRS[d]
    r, c = row + dr, col + dc
    while 0 <= r < self.rows and 0 <= c < self.cols:
        if self.grid[r][c] is not None:
            return True    # 遇到其他箭头,被挡住
        r += dr
        c += dc
    return False           # 走到边界都没遇到箭头,可以飞出

边界条件 0 <= r < self.rows and 0 <= c < self.cols 同时判断上下左右四个方向,避免数组越界。

3.3 动画系统

飞出动画和碰撞动画都用 time.time() 计算进度:

  • 飞出动画:0.4 秒内箭头沿方向移动 200px,然后消失

  • 碰撞动画:前 60% 时间沿方向弹出 30px,后 40% 弹回原位,期间变红

3.4 撤销功能

用一个栈记录每步被消除的箭头坐标和方向:

self.history.append((row, col, d))  # 消除时入栈

r, c, d = self.history.pop()         # 撤销时出栈

self.grid[r][c] = d                  # 恢复箭头

3.5 自动求解

用回溯搜索找到一条通关顺序:

def _solve(self, grid, rows, cols, path):
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] is not None and not blocked(r, c):
                grid[r][c] = None
                path.append((r, c))
                if self._solve(grid, rows, cols, path):
                    return True
                path.pop()
                grid[r][c] = d
                return False
    return all(grid[r][c] is None for r in range(rows) for c in range(cols)) # 棋盘空了即成功

找到路径后,每隔 0.6 秒自动 "点击" 一个箭头,播放飞出动画。

3.6 存档

游戏使用 JSON 文件 progress.json 来保存玩家的通关进度。每次通关后,程序会将当前已解锁到第几关、以及每关获得的最高星数写入这个文件。下次启动游戏时,先读取该文件恢复进度,未通关的关卡保持锁定状态。这样玩家关闭游戏后再打开,可以从上次的进度继续玩,而不需要从头开始。


四、AIGC 使用过程记录

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
路径检测逻辑 DeepSeek 生成四个方向的遍历检测代码,从箭头沿方向走到边界判断是否有阻挡 基础逻辑正确,但最初向上 / 向左检测时只写了 r >= 0 没加上界判断,边缘箭头会数组越界 修改 while 条件为 0 <= r < rows and 0 <= c < cols,统一四个方向的边界判断
碰撞动画 Codex 生成箭头被挡住后左右晃动再恢复的动画代码 晃动方向不对(应该沿箭头方向弹出再弹回,而不是左右晃),且动画速度太快 改为沿方向向量做三角形位移:前 60% 时间弹出 30px,后 40% 弹回,调整动画时长从 0.3s 到 0.5s
关卡可解性验证 Codex 生成回溯搜索代码,自动验证每个关卡是否存在通关路径 能正确检测死锁布局,但最初的算法在找到第一个可消箭头后直接 return False,逻辑有误 修改回溯逻辑:消除箭头后递归,成功才返回 True,失败则恢复箭头继续尝试其他位置
箭头绘制优化 DeepSeek 生成带箭杆和箭头的绘制代码,并建议用 2 倍超采样抗锯齿 基本可用,但直接画在屏幕上仍有锯齿 按建议实现离屏渲染:在 2 倍大小的透明 surface 上画箭头,再用 smoothscale 缩小回原尺寸,边缘明显平滑

总结:AIGC 能快速生成代码框架,但边界条件、动画细节和算法逻辑都需要人工调试和修改。尤其是路径检测的越界问题和回溯算法的正确性,AI 给出的初版都有 bug,必须自己运行测试才能发现。


五、测试结果

自动化测试运行 python test_game.py,覆盖以下用例:

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 箭头飞出,格子变为 None 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 箭头弹回,grid 不变,misses_left -1 通过
T03 点击位于边缘且朝向棋盘外的箭头 箭头正常消失,不发生越界错误 正常消除,无 IndexError 通过
T04 消除本关全部箭头 显示通关并进入下一关 通关后 level_idx +1,load_level 通过
T05 失误次数耗尽 显示失败并允许重新开始 state 变为 LOSE,可重开 通过
T06 游戏进行中重新开始 箭头布局和失误次数恢复 load_level 重置 grid 和 misses_left 通过

附加关卡可解性验证:

关卡 棋盘 箭头数 通关步数 结果
第 1 关 3×3 5 5 可通关
第 2 关 4×4 6 6 可通关
第 3 关 4×4 8 8 可通关
第 4 关 5×4 10 10 可通关
第 5 关 5×5 11 11 可通关
第 6 关 5×5 12 12 可通关
第 7 关 5×5 14 14 可通关

六、PSP 表格

任务 预估耗时(小时) 实际耗时(小时) 差异(小时)
需求分析与游戏设计 1 1 0
Python 与图形库学习 1.5 1 -0.5
游戏界面实现 2 2.5 +0.5
路径与碰撞逻辑实现 1.5 1.5 0
关卡设计 1 1 0
AIGC 辅助开发 1 1.5 +0.5
测试与修改 1 1.5 +0.5
README 与博客撰写 1.5 1.5 0
合计 10.5 11.5 +1

七、心得体会

AI 带来的帮助

这次作业从始至终都借助了 AIGC 工具(DeepSeek、Codex等)来辅助开发,AI 在以下几个方面帮了很大忙:

  • 快速搭建代码框架:Pygame 的初始化、事件循环、界面绘制这些模板代码,AI 几秒钟就能生成,省去了查文档的时间
  • 核心算法实现:路径检测和回溯求解的逻辑,AI 给出了初版代码,我只需要在其基础上调整边界条件和参数
  • 动画和 UI:飞出动画、碰撞弹回、按钮样式等,AI 生成的代码基本可用,微调后效果不错
  • Bug 定位:遇到数组越界、界面重叠等问题时,把报错信息贴给 AI,能快速定位原因

出现的问题

但 AI 生成的代码也不是拿来就能用,实际开发中遇到了不少问题:

  • 边界条件遗漏:路径检测最初只判断了 r >= 0,没有加上界,导致边缘箭头点击时数组越界崩溃
  • 动画效果不对:AI 生成的碰撞动画是左右晃动,但实际应该沿箭头方向弹出再弹回,效果不好
  • 回溯算法逻辑错误:最初的求解器在找到第一个可消箭头后直接 return False,导致所有关卡都被判为无解
  • 界面元素重叠:加了倒计时、撤销、提示、自动求解等按钮后,HUD 上的元素互相遮挡,需要重新排版
  • 字体不支持 emoji:直接在代码里写 ⏱ 和 🔒,中文系统上显示成方框,只能换成文字

这些问题如果不自己运行测试,光看代码是发现不了的。AI 给的代码"看起来对"和"实际能跑"是两回事。

自己的收获

  • 理解了游戏开发的基本流程:从需求分析、数据结构设计、核心逻辑实现、界面绘制到测试调试,走完了一个完整的小型软件开发流程
  • 掌握了路径检测的思路:从一个格子沿方向向量逐格扫描,遇到箭头就返回被挡,走到边界就返回可飞,这个思路不仅适用于这个游戏,也是很多网格类问题的基础
  • 学会了状态管理:游戏有开始、选关、游戏中、通关、失败等多个状态,用一个 self.state 变量切换,每个状态对应不同的绘制和事件处理,代码结构清晰了很多
  • 体会到了版本控制的重要性:每完成一个小功能就 commit 一次,出了问题可以回退,也能清楚看到开发进度,这和课堂上学的 Git 工作流是一致的
  • 明白了 AIGC 是辅助工具而不是替代品:AI 能快速生成代码框架,但边界情况、业务逻辑、调试修改都需要自己来。提交的每一行代码,自己都要能解释清楚
posted @ 2026-09-21 15:09  yitt  阅读(17)  评论(0)    收藏  举报