软件工程课程第二次个人作业 —— “一箭又一箭” 小游戏
| 项目内容 | 内容 |
|---|---|
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice/ |
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice/homework/16718 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成 “一箭又一箭” 小游戏 |
| 学号 | <102401623> |
| GitHub 仓库 | https://github.com/DUJIAWEI123374/game/edit/main/README.md |
一、项目展示
-
开始界面:
![开始界面]
![f94de7d258c0f86eeb6f2cc99858e49c]()
-
游戏过程:
![游戏过程]
![0abed5cfaa45555e49659eb58a19d942]()
-
碰撞反馈(红叉 + 晃动 + “被阻挡!”):
![碰撞反馈]
![bb20e201abc352d8293a3194513d5be5]()
-
通关界面:
![通关界面]
![4140ef7417a8ea3985445f39ddfc151f]()
-
失败界面:
![失败界面]
![d17100744974c6146da909a0ebef25f3]()
二、项目介绍
游戏规则:棋盘网格中放置上、下、左、右四个方向的箭头。点击箭头后,程序沿箭头方向从相邻格开始逐格检查直到棋盘边界:途中没有其他箭头时,箭头飞出棋盘并消失;途中存在其他箭头时,箭头被阻挡,不能消失,同时消耗一次失误次数。点击被阻挡的箭头会有晃动、红叉和 “被阻挡!” 文字反馈。清空本关全部箭头即通关并进入下一关;失误次数耗尽则本关失败,可以重新开始。
界面设计:
-
开始界面:游戏标题、规则说明、开始按钮、五个关卡选择按钮;
-
游戏界面:顶部显示当前关卡名、剩余箭头数、剩余失误数(爱心标识),以及 “重新开始 / 提示 / 自动通关 / 返回菜单” 四个按钮;中部为棋盘,箭头飞出时有位移动画和淡出,碰撞时有晃动、红叉和提示文字;
-
通关 / 失败界面:半透明弹窗显示 “通关!” 或 “失败!”,提供 “下一关 / 重新开始 / 返回菜单” 按钮。
主要功能:
-
四方向箭头的绘制、点击与路径检测;
-
飞出(位移动画 + 淡出)与碰撞(晃动 + 红叉 + 文字)两类视觉反馈;
-
失误次数管理与重新开始;
-
5 个可通关关卡(满足 “至少 3 关” 要求),难度递增;
-
附加功能:提示(高亮下一步)、自动通关(程序按求解顺序自动点击)、关卡选择、程序合成音效、演示模式(一键输出截图与 GIF)。
特色:核心逻辑层(logic.py)与界面层(main.py)完全分离,逻辑层不依赖 pygame,可以直接用单元测试覆盖全部点击判定;关卡可解性由求解器自动验证,保证不存在 “无法通关” 的布局。
三、实现思路
1. 箭头、方向与关卡如何表示
-
棋盘用二维数组
grid表示,每个格子要么是None(空),要么是一个方向字符串"up" / "down" / "left" / "right"; -
关卡用字符串数组描述,
^ v < >四个字符对应四个方向,.表示空格,可读性高、便于手工调整:
"^>..",
"....",
"..v<",
"...."
- 每个关卡包含名称、失误次数和棋盘布局,定义在
levels.py中。
2. 路径检测方法(重点)
点击 (r, c) 处的箭头后,沿箭头方向从相邻格开始逐格前进,直到棋盘边界:
def path\_is\_blocked(board, r, c):
  direction = board.arrow\_at(r, c)
  if direction is None:
  return False
  dr, dc = DIRECTIONS\[direction]
  nr, nc = r + dr, c + dc
  while board.in\_bounds(nr, nc): # 每步先判断是否越界
  if board.has\_arrow(nr, nc):
  return True # 途中遇到箭头 -> 被阻挡
  nr += dr
  nc += dc
  return False # 直到边界都畅通 -> 可飞出
关键点:
-
边界安全:循环每一步都先用
in_bounds判断,位于边缘且朝向棋盘外的箭头循环体一次都不执行,直接返回 “可飞出”,不会发生数组越界(对应测试 T03); -
四方向统一:四个方向只是坐标增量不同,用
(dr, dc)增量表统一处理,不写四份重复代码; -
空格不参与:只有格子里有箭头才会阻挡路径。
3. 点击判定与状态机
GameState 封装 “棋盘 + 失误次数 + 状态(进行中 / 通关 / 失败)”。点击结果分为 fly / blocked / won / lost / none 五种,界面层根据结果播放对应动画:
-
fly:清除箭头 + 飞出动画; -
blocked:失误减 1 + 碰撞动画; -
won:清空后进入通关弹窗; -
lost:失误耗尽进入失败弹窗。
4. 关卡可解性验证(附加的求解器)
为满足 “每个关卡都有合理通关顺序”,实现了一个 DFS + 记忆化求解器:不断尝试消除 “当前可以飞出” 的箭头,递归搜索直到棋盘清空。每一关在提交前都通过求解器验证存在 “零失误” 通关顺序,并逐关模拟试玩确认。
四、AIGC 使用过程
本次开发全程使用 豆包(Doubao) AIGC 工具协作完成。以下为 5 次有代表性的协作过程(均来自真实开发记录)。
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 需求分析与代码结构设计 | 豆包 | 将作业需求拆解为纯逻辑层(棋盘 / 路径检测 / 状态机)与 pygame 界面层分离的架构,给出数据表示方案(方向字符串 + 二维数组) | 结构清晰,逻辑层可独立测试 | 确认使用 Pygame 图形库,确定 5 个关卡的规模与失误次数设定 |
| 路径检测实现 | 豆包 | 生成四方向统一的路径检测代码(增量表 + 逐格循环) | 基本可用,四个方向与边界处理统一 | 编写测试后发现 “边缘朝外” 场景的用例预期写错,修正测试;确认循环内先判越界,杜绝数组越界 |
| 关卡设计 | 豆包 | 生成 5 个关卡数组,初版第 5 关存在箭头互相阻挡的死锁 | 测试暴露 “第 5 关无法通关”,求解器返回无解 | 人工分析死锁原因(同行互挡闭环),调整布局后重新用求解器验证,全部关卡可零失误通关 |
| 碰撞反馈动画 | 豆包 | 编写晃动(正弦偏移)、红叉、飘起文字的碰撞动画 | 初版有 Bug:碰撞效果在第一帧就被清理逻辑误删,红叉尺寸过小 | 调试发现效果清理条件写反(getattr 默认值误判),修正过滤逻辑并放大红叉,像素级验证反馈清晰可见 |
| 测试用例与运行验证 | 豆包 | 生成 T01~T06 自动化测试 + 关卡求解器校验工具 + 演示模式(截图 / GIF) | 12 个测试全部通过,五张截图与 GIF 用于 README 和博客 | 修复测试用例自身的预期错误;修正演示脚本点错格子的问题;发现 pygame 字体枚举在某机器崩溃,改为直接加载字体文件路径 |
五、测试结果
采用 “自动化单元测试 + 演示模式试玩” 两种方式。自动化测试文件:tests/test_logic.py,运行结果 12 个用例全部通过。
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 点击后箭头从棋盘移除,播放飞出动画 | ✅ |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头保留,失误 5→4,晃动 + 红叉 + “被阻挡!” | ✅ |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 上 / 下 / 左 / 右四个边缘朝向场景均正常飞出,无越界 | ✅ |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 清空后弹出 “通关!”,可进入下一关 | ✅ |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 失误归零后弹出 “失败!”,重新开始恢复初始状态 | ✅ |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局与失误次数均恢复为初始值 | ✅ |
补充验证:
-
每一关都用求解器验证存在 “零失误” 通关顺序,并模拟试玩全部通关(
tools/check_levels.py); -
演示模式对开始界面、游戏过程、碰撞、通关、失败五个场景逐张截图确认界面元素完整、文字清晰。
六、PSP 表格
下表 “实际耗时” 为参考值,请按你本人实际开发情况填写。
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 0.5 | -0.5 |
| Python 与图形库学习 | 2.0 | 1.0 | -1.0 |
| 游戏界面实现 | 3.0 | 2.5 | -0.5 |
| 路径与碰撞逻辑实现 | 2.0 | 1.5 | -0.5 |
| 关卡设计 | 1.0 | 1.0 | 0 |
| AIGC 辅助开发 | 2.0 | 2.0 | 0 |
| 测试与修改 | 1.5 | 1.5 | 0 |
| README 与博客撰写 | 1.5 | 1.5 | 0 |
| 合计 | 14.0 | 11.5 | -2.5 |
七、心得体会
AI 带来的帮助:
-
把模糊需求快速变成可运行结构:拿到作业要求后,AI 很快给出了 “逻辑层 / 界面层分离”“状态机驱动点击判定” 的架构方案,省去了大量从零设计的时间;
-
自动化测试帮我抓出了真问题:AI 生成的 T01~T06 测试在第一次运行时就有 7 个失败,其中既有我测试用例预期写错,也暴露了 “第 5 关死锁无法通关” 这种单靠肉眼很难发现的严重问题;
-
调试效率明显提升:碰撞动画不显示的问题,靠逐帧截图 + 像素统计定位到是效果清理条件写反,AI 辅助排查把定位时间压缩到很短。
出现的问题:
-
AI 生成的代码不能直接信任:第 5 关初版布局存在互相阻挡的死锁,必须依赖求解器验证才能发现;碰撞效果被误删是逻辑层的小错误,但表现为 “界面没有反馈”,非常隐蔽;
-
AI 也会受测试用例本身误导:有一次测试失败其实是测试用例的预期写错(单箭头点击即通关应返回 won 而非 fly),需要自己理解规则后修正用例;
-
环境兼容问题要靠真机验证:pygame 的字体枚举在某台 Windows 上直接崩溃,AI 无法预判,必须在自己机器上实际运行才能发现。
收获:AI 是高效的 “结对程序员”,但它给出的每一行代码都应该由自己理解、验证和负责。本次作业让我真正体会到 “AI 生成 → 测试验证 → 人工修改” 的闭环开发方式,也让我对路径检测、状态机、单元测试这些基础概念有了更扎实的理解。





浙公网安备 33010602011771号