一、项目基本信息
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 前往班级 |
| 这个作业要求在哪里 | 前往查看 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401309 |
| GitHub 仓库 | 前往主页 |
二、项目展示
2.1 开始界面

说明:标题画面含三行规则提示与「新游戏 / 选关 / 继续游戏」三个入口。有未完成存档时才会显示「继续游戏」。
2.2 游戏过程

说明:玩家观察箭头方向与阻挡关系,点击箭头使其飞出或受阻;顶栏实时显示关卡名、余箭、余次与用时。
2.3 通关 / 失败


说明:通关显示星级、得分、用时、失误;失败可「再战」;全部通关显示全通画面。
2.4 视频

三、项目介绍
3.1 游戏目标
玩家需要观察箭头方向和相互阻挡关系,通过合理顺序点击箭头,使全部箭头飞出棋盘。
3.2 基础规则
| 状态 | 行为 |
|---|---|
| 前方无箭头 | 箭头飞出并消失 |
| 前方有箭头 | 箭头不能消失,消耗一次失误次数,播放碰撞反馈 |
| 全部箭头清空 | 当前关卡通过 |
| 失误次数归零 | 当前关卡失败 |
| 点击重开 | 恢复进入当前关卡时的初始状态 |
3.3 操作
鼠标左键 :点击箭头 / 按钮
「撤销」按钮 :回退最近一次结算(无历史时禁用)
「重开」按钮 :恢复本关开局快照
鼠标滚轮 :以鼠标位置为中心缩放棋盘
鼠标中键拖拽 :平移棋盘
Home 键 :缩放归位到适合窗口
标题「选关」 :进入关卡选择界面
标题「继续游戏」 :恢复上次未完成的关卡
四、实现思路
4.1 项目架构
项目采用:
状态机 + 规则 / 表现分离
核心模块:
main.py 入口 + 主循环
↓
scenes.py 场景状态机(标题/选关/对局/结果)
┌──┴─────────┐
view.py anim.py 表现层:绘制 / 摄像机 / 动画
↑
rules.py solver.py score.py save.py 规则层(不 import pygame)
↑
levels.json 关卡数据(数据 / 规则分离)
说明:规则层负责盘面、射线、余次、快照、撤销、评分、求解与存档,全部为纯逻辑;表现层只把规则层结果画出来并处理输入。关卡坐标只进 levels.json,改关不改判定。
4.2 箭头表示
单支箭头使用:
id row col dir
例如:
{
"id": "a",
"row": 1,
"col": 0,
"dir": "right"
}
4.3 路径检测(关键代码)
定义四方向增量:
DIRS = {
"up": (-1, 0),
"down": (1, 0),
"left": (0, -1),
"right": (0, 1),
}
从箭头相邻格开始逐格扫描,核心代码如下(rules.py):
def _ray(self, row, col):
idx = self.arrow_at(row, col)
if idx is None:
return None
arrow = self.arrows[idx]
dr, dc = DIRS[arrow["dir"]]
r, c = row + dr, col + dc
# 关键:先判断格子在不在盘内,再读占用。
# 否则 Python 负索引会绕到网格另一头,边缘朝外箭会判错。
while 0 <= r < self.rows and 0 <= c < self.cols:
j = self._blocked_by(r, c, idx)
if j is not None:
return False, j # 先碰到箭 → 阻挡
r += dr
c += dc
return True, None # 一路空到边界 → 可飞
五、关卡设计
5.1 当前关卡
| 关卡 | 规模 | 箭头数量 | 余次 | 主要训练内容 |
|---|---|---|---|---|
| L0 教程 | 3×5 | 3 | 5 | 认识飞出与阻挡 |
| L1 顺序入门 | 4×4 | 5 | 3 | 先清除挡路箭头 |
| L2 交叉 | 5×5 | 7 | 3 | 行列交叉阻挡 |
| L3 收束 | 5×6 | 9 | 3 | 较长依赖关系 |
| L4 脉冲走廊 | 6×7 | 12 | 4 | 大盘 + 明显分支 |
| L5 交错方阵 | 7×8 | 16 | 4 | 多出口 + 中间链 |
| L6 深空编队 | 8×9 | 20 | 5 | 大盘观察、行列交织 |
| L7 终端迷阵 | 9×10 | 26 | 5 | 高难度基础关 |
六、游戏测试
6.1 基础测试
| 编号 | 测试内容 | 预期 | 实际 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击无阻挡箭头 | 飞出消失 | 规则层 + 冒烟通过 | ✅ |
| T02 | 点击被阻挡箭头 | 不消失、扣次 | 规则层通过 | ✅ |
| T03 | 点击边缘箭头 | 正常飞出 | 规则层通过 | ✅ |
| T04 | 清空关卡 | 进入通关流程 | 冒烟通过 | ✅ |
| T05 | 余次耗尽 | 进入失败流程 | 冒烟通过 | ✅ |
| T06 | 中途重开 | 恢复开局 | 冒烟通过 | ✅ |
6.2 扩展测试
| 编号 | 测试内容 | 预期 | 实际 | 是否通过 |
|---|---|---|---|---|
| T07 | 撤销成功飞出 | 箭头恢复 | 规则层 test_undo_fly 通过 |
✅ |
| T08 | 撤销恢复余次 | 余次还原 | 规则层 test_undo_blocked 通过 |
✅ |
| T09 | solver 求解 | 返回合法通关序 | 规则层 test_solver_all_levels 通过 |
✅ |
| T10 | solution 一致 | 参考解清空本关 | 规则层 test_reference_solution 通过 |
✅ |
| T11 | 存档 | 重启后恢复 | 规则层 test_save_roundtrip 通过 |
✅ |
另由冒烟测试覆盖:评分 / 星级(
test_score)、碰撞返回动画(BlockedReturn)、摄像机缩放 / 平移、音效容错;exe 打包待无 Python 环境实测。
七、AIGC 使用过程
本部分来自真实开发记录。
7.1 第一次:策划与架构(Cursor)
| 项目 | 内容 |
|---|---|
| 工具 | Cursor |
| 我的需求 | 把作业说明书拆成可落地的策划案与代码框架 |
| AI 提供内容 | 玩法拆解、增量分层、规则表、流程、接口分表 |
| 实际效果 | 可作骨架,偏说明书口吻 |
| 我做的修改 | 按策划案重写,关卡外置为数据文件 |
| 最终结论 | 保留其分层与增量思路,落地为「状态机 + 规则/表现分离」 |
7.2 第二次:核心规则 / 测试(Claude Code)
| 项目 | 内容 |
|---|---|
| 工具 | Claude Code |
| 我的需求 | 实现射线判定、撤销、关卡可解性核验 |
| AI 提供内容 | _ray 边界处理、快照撤销、依赖图求解、自动化测试 |
| 实际效果 | 规则层 11 项测试通过 |
| 我做的修改 | 修正 L1/L3 参考序、pygame SysFont 坑 |
| 最终结论 | 规则层与表现层分离后,判定可脱离 pygame 先行测试 |
7.3 第三次:扩展功能(ChatGPT + Claude Code)
| 项目 | 内容 |
|---|---|
| 工具 | ChatGPT + Claude Code |
| 我的需求 | 扩展优先级分析与实现(撤销/评分/存档/摄像机/UI/音效/打包) |
| AI 提供内容 | 优先级表、可运行代码、关卡数据、测试用例 |
| 实际效果 | E1–E9 全部落地,测试通过 |
| 我做的修改 | 修正 L7 大盘溢出、统一 E 编号、补注释 |
| 测试结果 | 规则层 + 冒烟全过 |
7.4 后续 AIGC 记录
| 日期 | 功能 | 工具 | AI 结果 | 人工修改 | 测试结果 |
|---|---|---|---|---|---|
| 09-22 | 关卡 + solver | ChatGPT/Claude | 依赖图求解 | 采纳 | 通过 |
| 09-22 | 撤销 | Claude | 快照栈 | 采纳 | 通过 |
| 09-22 | 评分/存档 | Claude | score/save 模块 | 采纳 | 通过 |
| 09-22 | UI/音效/打包 | Claude | 霓虹配色 + 自制音效 + spec | 采纳 | 通过 |
八、扩展功能
8.1 扩展一:撤销一步
问题:误点被挡的箭会扣失误次数,降低容错体验。
设计:Session 内维护快照栈,每次结算前 _snapshot() 保存盘面与余次;undo() 弹栈恢复。
实现:rules.py 增加历史栈(上限 20),scenes.py 增加「撤销」按钮(无历史时禁用)。计时不回退,避免刷时间。
测试:T07/T08 通过。
8.2 扩展二:得分 / 计时 / 星级
最终规则:
总分 = 700 × 准确度 + 300 × 时间分 (0–1000)
准确度 = 1 − 失误次数 / 初始余次
时间分 = 用时 ≤ par_time 记满分,超时最多再给 2×par_time 的线性衰减
星级 = 得分 ≥ 900 三星,≥ 700 两星,否则一星
实现:game/score.py 纯逻辑;PlayScene 累计 elapsed(撤销不回退);结果画面显示星级/得分/用时/失误。
8.3 扩展三:保存进度
保存内容:unlocked_level、in_progress(关卡/箭头/余次/用时)、best(每关最佳分)。
保存时机:每次结算后自动保存;通关时解锁下一关并记最佳;失败清进行中。
加载时机:标题「继续游戏」读取 in_progress 恢复盘面、余次与用时。
异常存档处理:版本不符或 JSON 损坏时回退默认值,不影响启动。
8.4 扩展四:AI 自动求解
核心思想:把「谁必须先被清除」建模为 blocker → blocked 依赖图;删除箭头只会减少阻挡,故「不断选当前可飞箭」等价于 Kahn 拓扑排序,无需 DFS。
求解代码(solver.py):
def solve(level):
arrows, adj, indeg = build_dependency_graph(level) # j 挡 i → 边 j→i
q = deque(i for i, d in enumerate(indeg) if d == 0) # 入度 0 = 当前可飞
order = []
while q:
i = q.popleft()
order.append(i)
for j in adj[i]:
indeg[j] -= 1
if indeg[j] == 0:
q.append(j)
return None if len(order) != len(arrows) else [arrows[i]["id"] for i in order]
测试:T09 八关均返回完整解序,T10 solution 与运行规则一致。
8.5 扩展五:视口拖动 / 缩放
设计:BoardView 维护 zoom(0.45–2.0)与 pan_x/pan_y;滚轮以鼠标位置为中心缩放,中键拖拽平移,Home 归中;进入关卡先 fit 自动适配整盘。
边界:最小缩放 0.45、最大 2.0;大盘(9×10)自动缩小至完整显示。
8.6 扩展六:电子游戏风 UI
设计说明:深色底 + 霓虹(青箭头、红受阻、金星级),HUD 显示关卡/余箭/余次/用时,程序绘制箭头(缩放不糊),按钮禁用态降透明度。
8.7 扩展七:碰撞动画
目标动画:
点击 → 短距离前冲 → 碰撞点 → 闪烁 → 沿反方向缓动返回 → 恢复原位置
最终参数:
前冲时长:0.18s(ease-out cubic)
碰撞停顿:0.18–0.25s(碰撞圆环闪烁)
返回时长:0.25–0.58s(ease-in-out)
总时长:约 0.58s
8.8 扩展八:音效
| 事件 | 音效 | 状态 |
|---|---|---|
| 点击箭头 | click.wav | ✅ |
| 飞出 | fly.wav | ✅ |
| 受阻 | blocked.wav | ✅ |
| 撤销 | undo.wav | ✅ |
| 通关 | clear.wav | ✅ |
| 失败 | fail.wav | ✅ |
资源来源:全部为 tools/gen_sfx.py 程序合成的自制短音效,无版权问题。
8.9 扩展九:打包
打包工具:PyInstaller(yi_jian.spec,onefile、无控制台)。
构建命令:
python -m PyInstaller --noconfirm --clean yi_jian.spec
输出:dist/YiJianYouYiJian.exe
测试机器 / 结果:[待补充]
九、GitHub 开发过程
9.1 Commit 记录
| 时间 | Commit | 内容 |
|---|---|---|
| 09-21 | docs | 策划案与库笔记、作业记录与工程搭建 |
| 09-22 | feat | 基础功能完成 |
| 09-22 | feat | 扩展 P0(更多关卡、撤回、计时与等级)完成 |
| 09-22 | feat | 扩展 P1(选关、存档、配色 |
| 09-22 | feat | 扩展 P2(音效、相机移动缩放、打包 |
| 09-22 | docs | 截止总结 |
以仓库实际 commit 为准。
9.2 GitHub 展示页
仓库:https://github.com/UYESoarin/Software-Engineering/tree/main/AIGCGame
项目截图:

十、PSP
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异 |
|---|---|---|---|
| 需求分析与游戏设计 | 1.5 | 2.0 | +0.5 |
| Python 与图形库学习 | 1.0 | 1.0 | 0 |
| 游戏界面实现 | 2.5 | 2.0 | -0.5 |
| 路径与碰撞逻辑实现 | 2.0 | 1.5 | -0.5 |
| 关卡设计 | 1.5 | 1.5 | 0 |
| AIGC 辅助开发 | 1.5 | 1.5 | 0 |
| 测试与修改 | 1.5 | 1.0 | -0.5 |
| 扩展功能 | 3.0 | 1.5 | -1.5 |
| README 与博客撰写 | 2.0 | 1.0 | -1.0 |
| 合计 | 约 16.5 | 13.0 | -3.5 |
十一、遇到的问题与解决
| 问题 | 原因 | 解决方法 | AIGC 是否参与 |
|---|---|---|---|
| L1/L3 参考解与盘面不符 | 文档参考序写错,被挡箭排在前面 | 独立脚本核验可解性,修正参考序 | 是 |
pygame SysFont 抛 TypeError |
2.6.1 扫描 Windows 注册表字体 bug | 改用 Font(path) 直取 msyh.ttc |
是 |
| L7(9×10)棋盘超出窗口 | 固定 64px 格子 | 自适应 cell + 摄像机缩放 | 是 |
十二、心得体会
12.1 AIGC 带来的帮助
AIGC 显著加快了策划、代码骨架、扩展方案与测试的产出;依赖图求解等算法思路可直接复用。
12.2 AIGC 暴露的问题
AI 生成的参考解、接口假设可能出错,需独立核验;文档与代码需人工把关一致性。
12.3 人工判断的重要性
关卡可解性、边界条件、版本一致性这些正确性问题,必须由人工验证,AI 无法替代。
12.4 软件工程方面的收获
增量交付、数据/规则/表现分离、自动化测试回归、可拓展接口设计。
12.5 游戏开发方面的收获
状态机、帧循环与 dt 解耦、程序绘制、动画时序、摄像机坐标换算。
十三、最终总结
项目当前完成:基础玩法(11 条要求全部达成)+ 扩展(撤销、评分星级、存档、选关、摄像机、霓虹 UI、碰撞动画、音效、AI 求解、打包配置)。
最终关卡:8 关(L0–L7)。
最终测试:规则层 11 项 + 冒烟全过。
最终版本:v0.2 扩展版本(v1.0 提交版本待打包实测)。
GitHub:https://github.com/UYESoarin/Software-Engineering/tree/main/AIGCGame
浙公网安备 33010602011771号