软件工程第二次个人作业
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 2026 秋季软件工程 |
| 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成"一箭又一箭"小游戏 |
| 学号 | 102401604 |
| GitHub 仓库 | https://github.com/cccccheyu/arrow-game |
一、项目展示
完整演示 GIF
下面这段 GIF 录制了真实的一局游戏:主菜单 → 选关 → 进入第 2 关 → 点击被阻挡的箭头(碰撞反馈:抖动 + 红线 + 扣分) → 撤销恢复 → 按正确顺序消除全部箭头(飞出 + 粒子 + 连击加分)→ 三星通关结算。

各界面截图
| 开始界面 | 关卡选择 |
|---|---|
![]() |
![]() |
| 游戏进行中 | 碰撞反馈 |
|---|---|
![]() |
![]() |
| 提示功能 | AI 自动求解 |
|---|---|
![]() |
![]() |
| 通关结算(三星) | 失败界面 |
|---|---|
![]() |
![]() |
| 无尽模式 | 全通关结局 |
|---|---|
![]() |
![]() |
二、项目介绍
2.1 游戏规则
- 棋盘上分布若干带方向的箭头(上
^、下v、左<、右>)。 - 点击一个箭头后,程序检查它前进方向上到棋盘边界之间是否还有其他箭头:
- 无阻挡:箭头沿方向飞出棋盘并被消除,得分 +100(连击有额外加成);
- 有阻挡:箭头不消失,播放抖动 + 变红 + 红色阻挡线反馈,消耗 1 次失误,得分 −50;
- 清空本关全部箭头即通关,进入结算(按失误数评 1~3 星)并可进入下一关;
- 失误次数耗尽则本关失败,可重新开始。
2.2 界面设计
采用 960×640 窗口、柔和深色渐变主题,四个方向用不同颜色区分(上=青、下=橙、左=绿、右=粉),一眼可辨。界面包含:
- 开始界面:标题 + 开始游戏 / 无尽模式 / 音效开关 / 退出;
- 关卡选择:6 个内置关卡卡片(显示最佳星级),未通关的关卡锁定;
- 游戏界面:顶部 HUD(当前关卡、剩余箭头、剩余失误、得分、计时、连击),中部棋盘,底部功能按钮(重新开始 / 提示 / 撤销 / 自动求解 / 返回)与快捷键提示;
- 结算界面:星星逐个点亮 + 得分 / 用时 / 失误统计 + 下一关 / 重玩 / 返回。
2.3 主要功能与特色
基础功能(作业要求,全部实现):图形界面、四方向箭头、鼠标点击、路径判断、飞出消除、碰撞反馈、失误次数显示、6 个可通关关卡、通关/失败界面、重新开始。
附加功能(附加分,全部实现):
| 附加项 | 实现 |
|---|---|
| 更多关卡 + 关卡选择 | 6 个内置关卡 + 选关界面 + 解锁进度 |
| 得分 / 计时 / 星级 | 连击加分、时间奖励、按失误评 1~3 星 |
| 提示 | 高亮"解锁最多后续"的安全箭头 |
| 撤销上一步 | 快照栈回退棋盘 / 失误 / 得分 |
| 保存进度 | JSON 存档(解锁、最佳分、星级),重启恢复 |
| 随机生成可通关关卡 | 生成 → DFS 求解器验证 → 重试;无尽模式 5 档难度 |
| AI 自动求解 | DFS + 状态去重,一键演示通关 |
| 流畅动画 + 音效 | 缓动飞出 / 衰减抖动 / 粒子系统;程序化合成 7 种音效(无版权风险) |
| 打包为可执行文件 | PyInstaller 配置(build.spec / build.bat) |
三、实现思路
3.1 方向与箭头的表示
方向用字符串枚举表示,delta 属性返回 (行增量, 列增量),把四个方向的差异收敛到一个元组,避免 if-else 散落:
class Direction(str, Enum):
UP, DOWN, LEFT, RIGHT = "^", "v", "<", ">"
@property
def delta(self): # (dr, dc)
return _DELTAS[self] # UP=(-1,0) DOWN=(1,0) LEFT=(0,-1) RIGHT=(0,1)
箭头 Arrow 持有 row / col / direction / state(IDLE / FLYING / SHAKING / GONE)与像素偏移量,供动画层读写。
3.2 关卡的表示
关卡用字符串布局描述,直观且便于手工设计与单元测试:
Level(id=2, name="四门大开", layout=(
">..^.",
".....",
"^...v",
".....",
".v..<",
), miss_limit=3, solution=((0,3),(0,0),(2,0),(4,1),(4,4),(2,4)))
'.' 为空格,其余字符即箭头方向。build_board() 把布局解析成二维网格;solution 是一组已验证的通关顺序,供自动化测试校验关卡可解性。
3.3 路径检测(重点)
核心只有一个函数:从箭头的下一格出发,沿方向步进,只要还在棋盘内就检查是否有箭头;走出边界仍未遇到箭头即"通畅"。
def is_path_clear(board, row, col, direction) -> bool:
dr, dc = direction.delta
r, c = row + dr, col + dc # 从下一格开始,不含自身
while 0 <= r < board.rows and 0 <= c < board.cols:
if board.grid[r][c] is not None: # 遇到箭头 → 被阻挡
return False
r += dr
c += dc
return True # 走到边界外 → 通畅
关键点:
- 循环条件同时约束上下界(
0 <= r < rows)。初版漏掉r >= 0,导致第 0 行朝上的箭头进入负索引(Python 负索引不报错但会错误地读到最后一行),这是本次开发印象最深的一个 bug(详见 AIGC 记录 1)。 - 从下一格开始,避免把箭头自身当作阻挡物。
- 用
direction.delta统一四方向,同一份代码处理上下左右,天然保证四方向行为一致。
同文件还提供 first_blocker()(返回第一个阻挡物,用于画碰撞红线)、free_arrows()(当前可消除的箭头,用于提示)、path_cells()(路径格子,用于轨迹特效)。
3.4 飞出与碰撞
- 飞出:
is_path_clear为真 → 从棋盘逻辑移除,交给FlyAnimation(ease-out-cubic 缓动)沿方向位移出界,同时ParticleSystem爆散 + 尾迹; - 碰撞:为假 →
ShakeAnimation(衰减正弦波)沿垂直方向抖动并变红,first_blocker画出红色阻挡线,失误 −1;失误归零触发失败。
3.5 整体架构
采用场景系统:SceneManager 管理 Menu / LevelSelect / Game / Result / Ending 五个场景的切换,每个场景实现 handle_event / update / draw。模型层(board / path_check / solver)与渲染层(renderer)分离,模型不依赖 pygame,便于单元测试。
四、AIGC 使用过程
全程以 Qoder(Coding Agent) 为主,辅以 ChatGPT(算法讨论)与 DeepSeek(关卡交叉验证)。汇总表(作业参考格式):
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 路径检测 | Qoder | 生成四方向检测代码(delta 元组统一方向) | 向上判断时负索引越界 | 补 0 <= r 边界条件 + 5 个边界测试 |
| 关卡设计 | Qoder + DeepSeek | 生成 6 关布局与通关顺序 | 关卡 2 顺序错、关卡 6 死锁 | 调整顺序 / 改箭头方向 + 写求解器自动验证 |
| 碰撞动画 | Qoder | 生成抖动 / 飞出 / 粒子三个动画类 | 抖动幅度过大、粒子消失突兀 | amplitude 20→8、加 alpha 衰减 |
| 自动求解 | ChatGPT + Qoder | DFS + 状态去重思路与实现 | 初版无去重,12 箭较慢 | 加 visited 集合 + max_states 上限 |
| 程序化音效 | Qoder | 波形 + 包络合成 7 种音效 | 初版无包络、numpy 缺失会崩 | 加 attack/decay 包络 + 降级逻辑 |
下面展开 3 次最具代表性的记录(完整 6 次见 docs/AIGC_USAGE.md)。
记录 1:路径检测与边界越界
- 我的要求:"实现
is_path_clear(board, row, col, direction),判断箭头前方到边界是否还有箭头;边缘箭头(如第 0 行朝上)不能越界。" - AI 完成:生成基于
while循环 +direction.delta的四方向检测代码。 - 效果:基本可用,但
while条件写成r < rows漏掉r >= 0,朝上/朝左的边缘箭头进入负索引(不报错但逻辑错误)。 - 人工修改:改为
0 <= r < rows and 0 <= c < cols,并补 5 个边界单元测试(T03 系列)验证。
记录 2:关卡设计与死锁修复
- 我的要求:"设计 6 个 5x5~7x7 关卡,难度递增,每关都必须存在通关顺序,不能死锁。"
- AI 完成:生成 6 关布局与声明的通关顺序;我另用 DeepSeek 独立交叉验证。
- 效果:关卡 2 声明顺序有误(先点了被挡的
(2,4));关卡 6 出现(2,6)v与(4,6)^互挡死锁。 - 人工修改:调整关卡 2 顺序、把关卡 6 的
(4,6)^改为v;并编写 DFS 求解器 +test_levels.py,对每关自动验证"声明解能通关"且"求解器也能找到解"。修改后 6 关全部通过验证。
记录 3:碰撞动画与粒子调优
- 我的要求:"碰撞时箭头沿垂直方向抖动并变红约 0.45s;飞出时有尾迹与爆散粒子;用缓动函数让动画自然。"
- AI 完成:生成
ShakeAnimation(衰减正弦波)、FlyAnimation(ease-out-cubic)、ParticleSystem与 4 种缓动函数。 - 效果:抖动 amplitude 初版 20px 像"抽搐";粒子无 alpha 衰减、消失突兀。
- 人工修改:amplitude 调到 8 并加
decay = 1 - t;粒子按剩余寿命线性衰减 alpha;尾迹每帧只生成 2 个小粒子保证性能。
五、测试结果
采用手工测试 + 自动化单元测试双重验证。作业要求的 6 项测试:
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 飞出动画 + 粒子尾迹,从网格移除,剩余数 −1,得分 +100 | ✅ |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误 −1 | 抖动 + 变红 + 红色阻挡线,失误 −1,得分 −50 | ✅ |
| T03 | 点击边缘且朝外的箭头 | 正常消失,不越界 | 上/下/左/右四边边缘箭头均正常飞出,无异常 | ✅ |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 弹出结算面板(星级/得分/用时),可进入下一关 | ✅ |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 弹出失败面板,"再试一次"可重开 | ✅ |
| T06 | 游戏进行中重新开始 | 布局与失误次数恢复 | 棋盘/失误/得分/计时/撤销栈全部重置 | ✅ |
自动化单元测试:共 44 个用例全部通过(路径检测 22 + 关卡/求解器/生成器 14 + 存档 8)。另有 15 项手工集成测试、6 项边界/异常测试、性能测试(60 FPS 稳定、求解器 12 箭 ~5ms)全部通过。详见 docs/TEST_REPORT.md。
运行测试:
python -m unittest discover -s tests -v
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.5 | 1.0 | −0.5 |
| Python 与图形库学习 | 2.0 | 1.0 | −1.0 |
| 游戏界面实现 | 3.0 | 2.5 | −0.5 |
| 路径与碰撞逻辑实现 | 2.0 | 1.5 | −0.5 |
| 关卡设计 | 2.0 | 2.5 | +0.5 |
| AIGC 辅助开发 | 1.0 | 1.5 | +0.5 |
| 测试与修改 | 2.0 | 2.0 | 0 |
| README 与博客撰写 | 1.5 | 1.5 | 0 |
| 附加功能开发(选做) | — | 3.0 | — |
| 合计 | 15.0 | 16.5 | +1.5 |
差异反思:关卡设计超时(初版死锁需反复验证)、AIGC 协作超时(AI 代码需多轮审查);学习阶段因有 Pygame 基础而节省。完整分析见 docs/PSP.md。
七、心得体会
AI 带来的帮助:AIGC 极大加速了"体力活"——渲染、动画、音效、存档这类模板化代码几乎一次成型;更重要的是提供了算法思路(DFS + 状态去重的求解器)和自动化测试的编写,让我能把精力放在玩法设计与验证上。
出现的问题:AI 代码并非开箱即用。路径检测的负索引越界、关卡死锁、动画参数过猛、循环导入、numpy 缺失崩溃……这些问题 AI 初版都没有发现,全靠人工审查、试玩和单元测试暴露并修复。我深刻体会到:AI 能写出"看起来对"的代码,但边界条件与死锁仍需人来把关。
自己的收获:
- 学会了用"求解器 + 单元测试"自动验证关卡可解性,把"看起来能过"变成"机器证明能过";
- 理解了数据驱动动画(状态 + 缓动函数)与模型/渲染分离的工程价值;
- 掌握了程序化音效合成(波形 + 包络),做到零素材、零版权风险;
- 认识到 PSP 记录的意义:附加功能最容易超时,下次应预留缓冲并先写测试(TDD)。
总体而言,这次作业让我完整走了一遍"需求 → 设计 → 编码 → 测试 → 文档"的小型软件流程,也看清了人机协作中各自的角色。










浙公网安备 33010602011771号