软件工程第二次个人作业
| 项目 | 内容 |
|---|---|
| 📚 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 📋 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次) |
| 🎯 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 🪪 学号 | 102402136 |
| 💻 GitHub 仓库 | https://github.com/MieSheeeep/Arrow-Go-Poof |
一、🎯 开做之前
看到这个任务的时候还算挺震惊的,因为我看着下面的描述,没太理解我们到底是要开发一个什么,只觉得还挺复杂的,一下子涉及到了玩法还原、动作交互、UI 设计等等方面。
因此去借鉴了一下原游戏。我想有这么几个需要注意的点:
- 箭头是有长度和曲折的,而我们不需要;
- 箭头的飞出有一个较为流畅的动画,我们可以参考;
- 错误后生命值可以显示在上方,并且将错过的箭头标为警示的颜色,而且错误提示是先让箭头撞到已有箭头再退回来,更流畅一些;
- 原游戏的地图不一定是方形的,可以有各种奇异的形状,而我们只有方格,反而可能更好做(也许可以当拼豆?);
- 还有一个很重要的点,是箭头飞行的时候我们允许什么操作。原游戏是只要点击顺序没有错,就可以飞出。我们也可以参考;
- 生成地图可能是一个需要注意的地方,不能有无解情况出现。
1.1 ✨ 关于附加功能
目前的想法是开发到:
- 得分、计时或星级评价:得分先不做,计时功能参考原游戏,然后按照完成时间进行星级评分吧!甚至加一个 combo 功能哈哈?
- 将程序打包为可执行文件:我想这个应该不是很难,可以尝试一下;
- 更流畅的动画和音效:尽力而为吧,可能得多使用 GPT image 了。
其余功能后续再说,带着这些想法开始实践吧。
二、🎮 项目展示
一款像素风休闲小游戏
技术栈:
Python 3.13、Pygame 2.6
2.1 🕹️ 游戏主体演示
首页点击开始游戏后即可进入第一关:金苹果,逐关解锁,共三关。

2.1.1 🍎 第一关:金苹果
首页点击开始游戏后进入第一关。
2.1.2 🔴 第二关:精灵球

2.1.3 🎀 第三关:HelloKitty

⚠️ 游戏以及博客仅仅为个人课程作业使用,不允许转载此部分,如有侵犯版权,请联系我将清除。
2.2 🔍 一些细节
2.2.1 🔴 错误警示

箭头设计:箭头较多,导致如果使用普通箭头画面看起来脏乱而不美观,故而提取方向核心信息,并设计新的箭头。
2.2.2 💡 HINT 下一个可消除箭头

2.2.3 🤖 AI 自动求解

2.2.4 🔥 Combo 连击系统

得分upup
2.2.5 ⏸️ 暂停

2.2.6 ↩️ 撤回

三、📖 项目介绍
3.1 ✨ 玩法设计亮点
- 拼豆结合原箭头飞出游戏,游戏整体更美观,完成清除有成就感;
- 加入了 Combo 得分系统。连击数越高,单次得分越高,总分数也决定星级;
- 像素量较大以及 Combo 才能得到高分、倒计时的限定加入,使得游戏即使在箭头只有单个格子的情况下依然具有难度,需要专注力投入才可能取得三星,同时可以享受 Combo 带来的爽感。
3.2 🎯 游戏规则
倒计时结束或者生命耗空即为失败;清除所有箭头即为成功。清除后下方拼豆图完全变亮。
四、💡 实现思路
整体数据结构只保留两张网格:
arrow_grid:保存U/D/L/R、.与None;color_grid:保存隐藏颜色。
其中:
None是图案边界;.可穿过;- 其余箭头才会阻挡。
4.1 🧭 路径检测(核心)
📂 点击展开:路径检测核心代码
def _find_blocker(self, row: int, col: int) -> tuple[int, int] | None:
row_delta, col_delta = DIRECTION_DELTAS[self.arrow_grid[row][col]]
row += row_delta
col += col_delta
while self.in_bounds(row, col):
cell = self.arrow_grid[row][col]
if cell is None:
return None # 越过图案边界,视为无阻挡
if cell in ARROWS:
return row, col # 遇到第一个箭头,即 blocker
row += row_delta
col += col_delta
return None
4.2 ⚡ 即时清除
成功时 Board 立即写入 ".";飞行动画只是视觉,不会阻塞后续点击。
📂 点击展开:即时清除逻辑代码
blocker = self._find_blocker(row, col)
if blocker is not None:
return MoveResult(False, row, col, cell, "blocked", blocker)
self.arrow_grid[row][col] = "."
return MoveResult(True, row, col, cell, "clear")
Game 只消费 Board 的结果,并生成得分和动画:
📂 点击展开:Game 层结果处理代码
result = self.board.click(row, col)
if result.reason == "clear":
self.animations.append(FlyOutAnimation(row, col, result.direction))
self.combo += 1
self.score += 10 * self.combo
if self.board.is_cleared():
self.level_summary = LevelSummary(
self.elapsed_seconds, self.mistakes,
self.score, self.max_score,
_stars_for_score(self.score, self.max_score),
)
阻挡时保留原箭头、扣生命、清空 Combo 并创建碰撞动画。
星级按本关得分比例结算:
满连击最高分为
5 × N × (N + 1),85% / 60% 分别为 3 / 2 星。
4.3 💡 提示系统
HINT 只返回一个可安全消除的坐标,不直接修改棋盘,而AI自动求解和它同根同源,调用同一代码,只不过出发了循环和改变棋盘。
📂 点击展开:提示系统代码
elif ui.hint_rect().collidepoint(event.pos):
ui.hint_cell = game.hint()
def hint(self) -> tuple[int, int] | None:
if self.state is not GameState.PLAYING:
return None
return self.board.first_clearable_arrow()
UI 绘制前检查该格仍是箭头,避免陈旧高亮:
📂 点击展开:UI 高亮校验代码
if self.hint_cell is None or self.game.state is not GameState.PLAYING:
return
row, col = self.hint_cell
if self.game.board.get_cell(row, col) not in {"U", "D", "L", "R"}:
return
五、🤖 AIGC 使用过程
按照要求记录至少 3 次具有代表性的 AI 协作过程。
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 需求分析 | ChatGPT | 需求文档构建 | 很全面,也有我的想法 | 无 |
| 界面设计 | ChatGPT image 2.5 | 图像设计 | 不错,啊哈哈 | 无 |
| 路径检测与状态分层 | Codex | 设计 Board/Game/UI 分层,生成方向检测和状态转换测试 | 骨架可直接复用 | 人工核对边界、非法点击、重复点击和生命值归零 |
| 飞出动画调试 | ChatGPT/Codex | 追踪 Board 清除、Game 动画列表和 UI 绘制之间的数据流 | 定位到箭头“突然消失”的原因 | 调整动画速度,把飞出距离改为越过窗口边界的方向距离 |
| 关卡设计与可通关验证 | Codex | 根据 .px 拼豆图案生成固定方向布局和验证顺序 |
三关均可通关 | 大尺寸 Hello Kitty 等比例压缩为 18×17,固定种子结果 |
| 界面美化与动画打磨 | Claude Code | 阅读代码后先跑通 183 个测试作基线,再只改 ui.py 实现渐变面板、进度条平滑、连击弹跳、爱心跳动、掉血红光、结算面板入场 |
全部特效落地且测试保持 183 通过 | 核对命中区域与测试锁定坐标不变,微调结果面板间距 |
💭 这次协作让我最有感的是 「先测后改」:
如果 AI 直接闷头改样式,很可能把测试锁定的布局坐标改坏;而它先跑测试再动手,收尾时又跑一遍确认,省掉了我很多排查时间。
六、✅ 测试结果
记录测试项目、预期结果、实际结果和是否通过。
6.1 🧪 自动化测试
📂 点击展开:自动化测试命令
python -m pytest -v
python -m compileall -q main.py src tests
当前结果以本机最新命令输出为准:
✅ 186 passed
自动化测试覆盖:
Board 规则、四方向路径、三关可通关顺序、固定种子布局、飞出与碰撞动画、扣心反馈、倒计时与按总分结算的星级、开始/通关/失败/暂停/重开、提示、撤销、连击与得分、自动求解、存档读档、音效波形合成、随机关卡生成、鼠标事件路由和 UI 布局。
6.2 📋 测试用例
| 编号 | 测试项目 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头从逻辑棋盘清除并飞出 | Game 创建 FlyOutAnimation,测试通过 |
✅ 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | CollisionAnimation 命中 blocker 并扣除生命,测试通过 |
✅ 通过 |
| T03 | 点击边缘且朝向棋盘外的箭头 | 正常消失,不发生越界 | Board 边界检测通过,测试通过 | ✅ 通过 |
| T04 | 清除本关全部箭头 | 显示通关并进入下一关 | 三关工厂和 next_level() 测试通过 |
✅ 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重开 | FAILED 状态拒绝普通点击,结果按钮重开,测试通过 |
✅ 通过 |
| T06 | 游戏进行中重新开始 | 棋盘和失误次数恢复 | restart() 清空动画/错误标记并恢复关卡,测试通过 |
✅ 通过 |
| T07 | 三个拼豆关卡的固定布局 | 每次启动方向相同且存在通关顺序 | 固定种子复算、已冻结顺序逐步清空,测试通过 | ✅ 通过 |
| T08 | 飞出与碰撞动画 | 飞出有蓄力并越过窗口;碰撞变红、回退后保留错误标记 | FlyOutAnimation 阶段与越界距离、CollisionAnimation 阶段与 error_cells 时序测试通过 |
✅ 通过 |
| T09 | 倒计时 | 仅对局计时;暂停/通关/失败后冻结;重开清零;超时失败 | Game.elapsed_seconds 状态转换与超时测试通过 |
✅ 通过 |
| T10 | 总得分星级结算 | 达到最高分 85%/60% 的边界时正确获得 3/2 星,低于 60% 为 1 星 | 得分边界、时间/失误不直接影响星级与 StarRevealAnimation 测试通过 |
✅ 通过 |
| T11 | 游戏中重开与返回主菜单 | 操作按钮不触发棋盘点击,状态正确复位 | 事件路由与 return_to_menu() 测试通过 |
✅ 通过 |
| T12 | 暂停、继续与暂停菜单操作 | 暂停时计时冻结,继续后计时恢复;重开/返回菜单不触发棋盘点击 | PAUSED 状态与事件路由测试覆盖 |
✅ 通过 |
七、📊 PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 0.6 | 1.5 | +0.9 |
| Python 与图形库学习 | 1.0 | 1.0 | +0.0 |
| 游戏界面实现 | 1.0 | 1.0 | +0.0 |
| 路径与碰撞逻辑实现 | 0.4 | 0.5 | +0.1 |
| 关卡设计 | 1.0 | 1.0 | +0.0 |
| AIGC 辅助开发 | 4.0 | 5.0 | +1.0 |
| 测试与修改 | 3.0 | 4.0 | +1.0 |
| README 与博客撰写 | 1.0 | 2.0 | +1.0 |
| 合计 | 12.0 | 16.0 | +4.0 |
八、💬 心得体会
AI帮我快速拆分规则、生成代码骨架和测试,但最终仍要靠自己验证。
特别是ai写了一大堆的测试,其实我都不大明白它到底在测试什么,最终的呈现效果也并不尽人意。在贴图效果上有非常多的错位错误,最终我还得自己动手进行调试。
然后还有很重要的一点,AI在撰写这项任务或者规划完成这项任务的时候,似乎太过于注重工程化了,以一个软件开发的角度去进行撰写。
在规划的时候我也让ai参与进来了,导致最后整个项目看起来,并没有真正的从一个Player的角度去看待,怎么样才是“爽”的,而更多只是像一个工程化实现。
还有一个关于最小完成集(MVP)的失败,和整个项目的缺点逻辑是一致的,它被我理解成了一个最小功能集,而不是一个最小游玩集。

浙公网安备 33010602011771号