软件工程第二次个人作业:利用 AIGC 完成“一箭又一箭”小游戏
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102402129 |
| 姓名 | 梁洪睿 |
| GitHub 仓库 | vic155/-2 |
本项目使用 Codex 辅助开发,本文由 AI 根据实际开发记录协助整理。本人参与需求提出、体验反馈和代码学习。
一、项目介绍
“一箭又一箭”是一款用 Python 和 Pygame 实现的点击解谜小游戏。玩家点击箭头,如果它前方直到棋盘边界都没有其他箭头,就能飞出并消失;如果被阻挡,则产生碰撞反馈,并扣除一次失误机会。每关有 3 次机会,清空棋盘后通关,机会耗尽后失败,可以重新开始。
第一版实现了基础玩法,第二版增加了随机出题和点击音效,并简化了主页。当前提供三个难度:5×5 棋盘、12 支箭头;6×6 棋盘、22 支箭头;7×7 棋盘、33 支箭头。每次开始生成可解题目,重开保留原题,换题生成同难度的新布局。
界面采用浅色背景和青绿色按钮,包含开始页、游戏页和结果页。除了鼠标点击,还支持 R 重开、N 换题、H 提示、M 音效开关和 Esc 返回主页。主页的小箭头可以点击飞出,进入棋盘时有入场动画。
二、项目展示
开始界面

游戏过程:显示当前关卡、剩余箭头、失误机会和操作按钮。

通关界面

游戏演示 GIF(动图不包含音频)

以上截图和演示来自第二版程序的实际渲染。
三、实现思路
1. 各文件如何配合
| 文件 | 主要作用 |
|---|---|
main.py |
程序入口,创建游戏界面并启动主循环 |
arrow_game/app.py |
绘制界面、处理鼠标键盘输入、播放动画 |
arrow_game/model.py |
定义方向、检测阻挡、管理棋盘和胜负状态 |
arrow_game/levels.py |
定义三个难度,生成随机可解题目 |
arrow_game/audio.py |
加载音效,处理播放和静音 |
简单来说,main.py 启动 app.py,界面把点击位置交给 model.py,再根据返回结果绘制飞出或碰撞动画。
2. 箭头与路径检测
棋盘用字典保存,键是 (行, 列),值是箭头方向;没有箭头的格子不存入字典。四个方向对应增量:上 (-1, 0)、下 (1, 0)、左 (0, -1)、右 (0, 1)。
路径检测的核心是从箭头前方一格开始,沿朝向逐格扫描,遇到第一个被占用的格子就返回它的位置,否则返回 None。下面是核心扫描部分:
dr, dc = direction.delta # 取得方向增量。
row, col = position
row, col = row + dr, col + dc # 跳过箭头自身。
while 0 <= row < height and 0 <= col < width:
if (row, col) in board:
return row, col # 返回最近的阻挡者。
row, col = row + dr, col + dc
return None # 到达边界仍无阻挡。
例如 → · · ↑ ·,左边的箭头会被右侧的向上箭头挡住。阻挡只看位置,与对方的朝向无关。边缘朝外的箭头第一步就越界,因此不会进入循环,也不会出现越界访问。
find_blocker() 只检查指定箭头是否受阻;solve() 才会反复寻找当前可消除的箭头,得到完整解答顺序。删除箭头只会减少阻挡,因此可以采用贪心方式求解。
3. 随机题目与状态管理
随机出题时先随机选择格子,再依次为当前能朝外离开的格子指定方向,记录一个合法的移除顺序。最终保留所有箭头,按照构造时的顺序即可通关,避免独立随机方向造成死局。
游戏状态由 Game 类管理:点击受阻时扣机会,成功时删除箭头,棋盘为空时标记通关。重开会从本题初始数据恢复棋盘和 3 次机会;换题则先重新生成布局,再重置状态。
四、AIGC 使用过程
使用工具为 Codex。下面记录的是本次开发中实际提出过的要求。本人主要提出需求、反馈效果并追问代码含义,具体代码修改由 AI 执行。
| 子任务 | 我提出的要求 | AI 完成了什么 | 效果与本人参与 |
|---|---|---|---|
| 基础玩法与代码学习 | 完成基础游戏,并解释各 Python 文件之间的关系,补充行尾注释 | 实现界面、四向路径检测、失误机制和关卡流程,添加中文注释 | 基础功能通过自动测试;我继续追问了 class、__init__、类型标注及求解函数 |
| 第二版随机出题 | 将固定题目改成随机出题,并加入点击音效 | 实现可解随机生成器、换题按钮、五种音效及开关 | 300 道随机题均通过求解和点击回放;本人提出功能需求 |
| 调整音效 | 原音效感觉偏笨重,希望更清脆 | 缩短音效,调整音调与衰减,重新生成声音资源 | 音频检查通过;本人根据听感提出修改方向,具体修改由 AI 完成 |
| 精简主页 | 减少主页文字,让打开和游玩更有创意 | 精简标题与按钮,加入可点飞的装饰箭头、入场动画和飞行尾迹 | 更新后共 56 项测试通过;本人提出界面取舍,AI 完成实现 |
开发中也遇到过问题:音频设备关闭后,继续调用旧的声音对象可能导致进程退出。AI 在播放前增加音频初始化状态检查,再通过回归测试确认修复。详细过程保存在项目的 docs/aigc-log.md 中。
五、测试结果
测试环境为 Windows、Python 3.12.7、pygame-ce 2.5.7。2026 年 9 月 20 日保存的测试记录显示,56 项自动测试全部通过,用时 2.380 秒,包括逻辑、界面和音频检查;其中覆盖三个难度各 100 道随机题,共 300 道题的完整求解回放。
测试命令:
python -m unittest discover -s tests -v
| 编号 | 测试内容 | 预期结果 | 实际自动验证结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 飞出并消失 | 箭头删除,数量减少,失误机会不变;界面触发飞出动画 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头保留,失误减 1 | 布局不变,机会从 3 变成 2,并显示碰撞反馈 | 通过 |
| T03 | 点击边缘朝外的箭头 | 正常消除,无越界 | 上下左右四个方向均正常消除 | 通过 |
| T04 | 清空当前关卡 | 显示通关,可进入下一关 | 完整回放成功,前两关可以切关,末关显示完成结果 | 通过 |
| T05 | 失误机会耗尽 | 显示失败,可重开 | 3 次碰撞后进入失败状态,重试正常 | 通过 |
| T06 | 游戏中重新开始 | 恢复布局和失误机会 | 消除、碰撞后重开均恢复原题和 3 次机会 | 通过 |
原始输出保存在 docs/test-results.txt。以上为自动测试与界面事件回放结果。本人逐关试玩记录:待补充三个难度的实际通关情况。
六、PSP 表格
单位为小时,差异为“实际耗时-预估耗时”。下表待按本人真实投入补充;没有事先估算的阶段应写“未预估”。
| 任务 | 预估耗时 | 实际耗时 | 差异 |
|---|---|---|---|
| 需求分析与游戏设计 | 待补充 | 待补充 | 待补充 |
| Python 与图形库学习 | 待补充 | 待补充 | 待补充 |
| 游戏界面实现 | 待补充 | 待补充 | 待补充 |
| 路径与碰撞逻辑实现 | 待补充 | 待补充 | 待补充 |
| 关卡设计 | 待补充 | 待补充 | 待补充 |
| AIGC 辅助开发 | 待补充 | 待补充 | 待补充 |
| 测试与修改 | 待补充 | 待补充 | 待补充 |
| README 与博客撰写 | 待补充 | 待补充 | 待补充 |
| 合计 | 待补充 | 待补充 | 待补充 |
七、心得体会
这次作业中,AI 帮助我较快搭建了一个可以运行的游戏,但生成代码之后,还需要继续理解代码为什么这样写。我围绕类、初始化方法、类型标注、路径检测和求解顺序进行了追问,也要求把注释放在代码行尾,方便对照阅读。
两次版本迭代让我看到,功能正确与体验合适是两件事。加入音效之后,我仍然觉得声音偏笨重,于是继续提出“更清脆”的要求;主页功能齐全之后,我又要求减少文字、增加开场互动。AI 能帮助执行修改,而具体想要怎样的效果,需要自己表达清楚,并继续运行检查。
对于关键算法,我的理解是:一次路径检测只回答一个箭头能否出去;完整求解需要连续检测并删除箭头。边界条件、碰撞扣次数和重开恢复状态都需要单独验证,不能只凭游戏能够启动就判断完成。
八、运行方法与素材说明
仓库中的 arrow-again 保存第一版,arrow-again2 保存第二版。下载代码后,进入第二版目录运行:
python -m pip install -r requirements.txt
python main.py
箭头和界面由 Pygame 绘制,音效由项目脚本合成,没有使用原商业游戏的素材。中文字体使用 Noto Sans SC,许可证随项目放在 assets/OFL.txt 中。更详细的运行说明、截图和开发记录可在第二版目录的 README 与 docs 中查看。

浙公网安备 33010602011771号