第二次软件工程作业
2026 秋软件工程个人作业(第二次)——《一箭又一箭》开发报告
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601 软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102402132 |
| GitHub 仓库 | fnisao/arrow-after-arrow |
本文记录《一箭又一箭》小游戏的设计、实现、AIGC 协作与测试。游戏使用 Python 标准库 Tkinter 开发,包含三个可通关关卡。文中的界面图由项目的 Tkinter 画布导出;游戏界面与运行效果以程序实际启动后的显示为准。
一、项目展示
1. 开始界面
开始页保留游戏名“一箭又一箭”,用折角纸卡、彩色箭头贴纸和三步玩法说明呈现轻松的解谜氛围。玩家可以从主按钮进入第一关。

图 1:开始界面。标题、玩法说明和开始按钮位于同一张纸卡中。
2. 游戏界面
棋盘左侧显示箭头,右侧的“关卡小票”显示关卡名、剩余箭头、进度、剩余失误和重开按钮。方向用不同颜色区分,鼠标悬停时还会出现虚线方向引导。下图是第一关发生一次碰撞、成功消除一支箭头后的状态。

图 2:第一关游戏界面。右侧关卡小票显示剩余箭头和失误机会。
3. 通关与失败界面
最后一支箭头飞出后,程序显示通关页;点击“进入下一关”继续。失误次数耗尽时显示失败页,点击“重新挑战本关”可恢复初始布局。

图 3:通关界面。完成本关后可进入下一关。

图 4:失败界面。点击按钮可重开当前关。
4. 运行方式
开发环境为 Windows、Python 3.14.7。游戏只使用 Python 标准库 Tkinter,无需额外安装游戏依赖。在项目目录中运行:
python game.py
使用鼠标点击箭头或按钮;游戏中按 R 可以重开当前关。自动化测试命令:
python -m unittest -v test_game.py test_ui.py
capture_screens.py 是可选的报告配图导出工具,使用 PyMuPDF;运行游戏不需要这个依赖。
二、项目介绍
1. 游戏规则
棋盘由网格构成,每个箭头只占一格,方向为上、下、左、右。点击箭头后,程序沿箭头方向逐格检查到棋盘边界:途中没有其他箭头,它就飞出并消失;途中遇到箭头,它会变红、晃动,阻挡它的箭头被红圈标出,同时失误次数减一。清空本关所有箭头后进入下一关;失误机会用完后可以重试。
2. 设计与功能
本作采用折纸与贴纸的视觉主题:暖色纸张背景、折角卡片和带阴影的彩色箭头,突出小游戏的轻松感。棋盘保留行列坐标,方便观察方向;青色进度条表示已清除比例。开始、游戏和结果页保持统一的纸卡样式;状态信息集中在棋盘右侧,避免压住可点击区域。所有图形由 Tkinter Canvas 绘制,没有借用原商业游戏素材。
项目包含 3 个固定关卡,规模分别为 5×5、6×6、7×7,共 8、12、16 支箭头。箭头顺利飞出和碰撞都带有短动画;动画期间暂时锁定棋盘点击,避免连续点击造成状态错乱。
三、实现思路
1. 数据结构与模块划分
game_logic.py 保存纯规则:Arrow 记录行、列、方向;Level 记录关卡名称、棋盘边长、可用失误次数和初始箭头;GameState 管理当前箭头、失误次数与游戏状态。当前箭头放在以 (row, col) 为键的字典中,便于定位点击格子。game.py 负责界面绘制、鼠标输入和动画,两部分分开后,规则可以不打开窗口直接测试。
方向到坐标增量的映射为:
DIRECTIONS = {
"up": (-1, 0), "down": (1, 0),
"left": (0, -1), "right": (0, 1),
}
这里的元组依次是“行变化、列变化”。行号向下增加,因此 up 的行变化为 -1。
2. 路径检测
核心函数 blocker() 从箭头的下一格开始,沿方向增量逐格扫描;若找到箭头,返回第一个阻挡物;若到达边界,返回 None。下面是项目中的关键实现:
def blocker(arrow, arrows, size):
dr, dc = DIRECTIONS[arrow.direction]
occupied = {other.position: other for other in arrows
if other.position != arrow.position}
row, col = arrow.row + dr, arrow.col + dc
while 0 <= row < size and 0 <= col < size:
if (row, col) in occupied:
return occupied[row, col]
row += dr
col += dc
return None
occupied 用坐标映射箭头对象;扫描时只检查所选箭头正前方的同一行或同一列。边界条件在读取格子前判断,因此朝外的边缘箭头会直接得到 None,不发生越界访问。对单次点击而言,构造 occupied 的时间复杂度为 O(A),路径扫描最多 O(N) 步,其中 A 是当前箭头数、N 是棋盘边长。点击处理根据返回值决定扣失误或移除箭头。失败与通关状态由 GameState.click() 更新,界面等待动画结束后再展示结果页。
3. 关卡可解性
最初设计关卡时,固定布局中出现过互相阻挡的闭环。例如第一关的 (1, 4) 箭头原本向下,整组箭头构成环,程序无法找到下一支可飞出的箭头。后来调整该箭头方向,并对另外两关中的闭环做同类修正。solution() 每轮寻找一支当前无遮挡的箭头,移除后继续搜索;三关均能生成完整消除顺序。这证明存在通关路径,但还需本人实际操作,检查解谜体验是否合理。
四、AIGC 使用过程
以下四项来自本项目实际开发对话和测试。本次使用的 AIGC 工具是 ChatGPT / Codex,表格分别记录需求、生成内容、验证结果及后续人工核验,未把尚未发生的人工修改写成既成事实。
| 子任务 | 提出的要求或发现的问题 | AIGC 提供的内容 | 实际效果 | 人工核验与调整 |
|---|---|---|---|---|
| 基础玩法与结构 | “现在先只用 Python 完成要求的设计游戏” | 编写 game_logic.py、Tkinter 界面、三关固定数据和规则测试 |
窗口可以启动,基础交互、动画、重开及结算流程可运行 | 通过自动化测试检查规则与流程;关卡手工体验仍需本人确认 |
| 关卡检查与修正 | 首版布局的求解结果为 None,说明关卡存在互相阻挡的闭环 |
分析阻挡关系并调整部分箭头方向,加入 solution() 检查完整消除顺序 |
三关均能求出通关顺序,规则测试通过 | 对照求解顺序检查关卡数据,未把“存在解”误写成“已经手工试玩” |
| 首轮界面优化 | “保持游戏名字不变,优化 UI,并参考班级已完成作业写报告” | 提供深色控制台风格的初版界面,并整理报告结构 | 功能正常,但实际运行截图显示界面偏工具式 | 查看截图后提出“让小游戏前端更有特色”的修改意见 |
| 二次视觉调整 | 提供运行截图,要求前端 UI 更有特色 | 将界面改为折纸贴纸主题,加入关卡小票、彩色箭头与悬停方向引导 | 四张界面图已更新,九项自动化测试通过 | 后续在本机试玩时检查字号、色彩和动画手感 |
五、测试结果
使用 unittest 执行规则与界面流程测试,共 9 项,运行结果为 OK。其中 T01–T06 对应作业要求;另外三项检查了从点击到结算的界面状态变化及悬停交互。
Ran 9 tests in 0.796s
OK
| 编号 | 测试内容 | 预期结果 | 实际自动化结果 |
|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头消失 | 返回 cleared,剩余箭头数为 0,通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头保留,失误减 1 | 返回 blocked 和阻挡物坐标;箭头保留,失误减 1,通过 |
| T03 | 四个方向的边缘箭头朝外 | 不越界,路径无遮挡 | 四向 blocker() 均返回 None,通过 |
| T04 | 按合法顺序清空三关 | 三关均可通关并切换界面 | 三关 solution() 均非空;规则状态和界面切换通过 |
| T05 | 失误次数耗尽 | 失败并可重开 | 状态进入 failed,界面显示结果页;重开恢复,通过 |
| T06 | 游戏进行中重开 | 布局和失误次数恢复 | 初始箭头坐标集与失误次数全部恢复,通过 |
| T07 | 连续点击走完三关 | 每关通关页与下一关正常 | 模拟点击和动画完成后,三关依次进入结果页,通过 |
| T08 | 多次碰撞后重开 | 失败页和重开正常 | 模拟点击达到失误上限,随后重开第一关,通过 |
| T09 | 悬停箭头显示方向引导 | 不改变游戏状态 | 方向引导显示后箭头集合不变,移开鼠标后悬停状态清除,通过 |
自动化测试说明代码在上述场景下符合预期;其中界面测试通过程序生成鼠标点击事件,覆盖了从开始到通关、失败与重开的流程。实际运行截图使第一关的布局与字体得到人工检查,并促成了本次 UI 改版。第二、三关尚无本人逐关手工通关记录,因此这里没有把自动化测试写成手工试玩。
六、PSP 估时与实际耗时
开发过程中未逐项计时,下面的实际耗时根据开发过程进行回顾估算。预估耗时表示开始任务前对各阶段工作量的判断,差异按“实际耗时-预估耗时”计算。实际开发共约 7.9 小时,其中界面实现耗时最多,主要用于两轮视觉方案调整和交互细节修改。
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 0.4 | -0.6 |
| Python 与图形库学习 | 1.5 | 0.5 | -1.0 |
| 游戏界面实现 | 3.0 | 2.0 | -1.0 |
| 路径与碰撞逻辑实现 | 2.0 | 1.25 | -0.75 |
| 关卡设计 | 1.0 | 0.75 | -0.25 |
| AIGC 辅助开发 | 1.5 | 0.75 | -0.75 |
| 测试与修改 | 1.5 | 1.0 | -0.5 |
| README 与博客撰写 | 2.0 | 1.25 | -0.75 |
| 合计 | 13.5 | 7.9 | -5.6 |
从结果看,实际耗时低于预估。AIGC 帮助完成了代码框架、界面方案和报告结构,减少了重复查阅与编写时间;但关卡可解性、碰撞逻辑和界面效果仍需要本人通过测试与运行截图进行检查。
七、心得体会
本次开发说明,AIGC 可以较快地搭出可运行的界面和规则模块,但生成的关卡数据仍可能有逻辑问题。初版布局就出现过互相阻挡的闭环;只有把“是否存在完整消除顺序”写成检查程序,才发现并修正了这个问题。对我而言,理解扫描方向、边界条件和状态变化,比单纯得到一份代码更重要。
把规则与 Tkinter 界面分开后,路径检测可以直接做自动化测试,开始、通关和失败界面也能用点击流程测试核验。实际运行截图让我发现首轮界面虽功能完整,却更像工具面板,因此又提出了折纸贴纸风格的修改要求。自动化测试能证明某些行为正确,但无法评价关卡的趣味性;这是我在继续开发时需要重视的部分。
八、素材来源与参考
棋盘、箭头、纸卡和结果页图形均由 Tkinter Canvas 代码绘制。项目没有使用原商业游戏的代码、美术素材或音效。报告格式参考了同班报告示例一和同班报告示例二的作业信息表、分界面展示和测试记录方式;文中的项目实现、截图与测试结果均对应本项目。
浙公网安备 33010602011771号