2026 秋软件工程个人作业(第二次)——《一箭又一箭》
2026 秋软件工程个人作业(第二次)——《一箭又一箭》
| 这个作业属于哪个课程 | 福州大学2026年软件工程 |
|---|---|
| 这个作业要求在哪里 | 福州大学2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401228 |
| GitHub 仓库 | 点击此处传送 |
一、项目展示
这里我录制了B站视频,我的声音有点小,音效有点大声,请大家见谅。
可运行的程序,我放在Github上的Release上了.
下面是采用图表介绍的形式。
| 开始界面 | 关卡选择 |
|---|---|
![]() |
![]() |
| 游戏界面 | 箭头飞出 |
|---|---|
![]() |
![]() |
| 6x6 铺满(第 3 关) | 8x8 铺满(第 4 关) |
|---|---|
![]() |
![]() |
| 碰撞弹回 | 本关通过 |
|---|---|
![]() |
![]() |
| 本关失败(失误耗尽,含彩蛋动图) | 暂停菜单 |
|---|---|
![]() |
![]() |
| 返回首页确认 | AI 求解后的结算(彩蛋) |
|---|---|
![]() |
![]() |
二、项目介绍
2.1 游戏规则
棋盘中分布着朝上、下、左、右四个方向的单格箭头。玩家点击某个箭头后,程序检查它前进方向到棋盘边界之间是否有其他箭头:
- 路径畅通:箭头飞出棋盘并消失;
- 路径被阻挡:箭头冲向阻挡者、撞上后弹回原位并变红,同时消耗一次失误;被堵过的箭头会一直保持红色,直到它成功飞出;
- 失误次数耗尽,或倒计时归零,本关失败;
- 清空本关全部箭头即可通关。
2.2 界面设计
- 共 6 个关卡:第 1 关 5x5 入门,第 2 关 6x6,第 3 关 6x6 铺满,第 4~6 关 8x8 铺满;
- 开始界面:渐变背景 + 漂浮装饰箭头 + 自动播放的迷你棋盘(循环演示箭头飞出);
- 游戏界面:左侧显示关卡名、剩余箭头、剩余失误、剩余时间;右侧为暂停 / 重新开始 / AI 求解 / 回到主页 按钮;格子大小随棋盘自适应(8x8 时自动缩小);
- 通关结算:按本关失误数评定 3 颗星(0 失误 3 金星、1 失误 2 金星、2 失误 1 金星),全部通关显示总评星级。
2.3 主要功能
- 图形化界面(pygame-ce),开始 / 游戏 / 通关 / 失败四类界面;
- 四方向箭头、鼠标点击、路径检测、飞出与碰撞反馈;
- 失误次数、限时(箭头数 × 0.75 秒)、重新开始;
- 6 个可通关关卡(导入时自动校验无死局);
- 暂停菜单(继续 / 重新开始 / 回到首页,返回前有"记录不保存"确认);
- 音效 8 种(点击、飞出、碰撞、通关、失败、倒计时滴答、按钮悬停、邪恶大笑),全部由代码合成;
- 星级结算、关卡选择(含缩略图与历史最佳星级)。
2.4 特色 / 附加功能
- AIGC 辅助生成的关卡:铺满棋盘的关卡用"逆向构造法"生成,天然保证可通关;
- AI 自动求解彩蛋:一键自动通关,但会触发"你试图使用不属于你的力量"的结算界面;
- 原创音效合成:不依赖任何第三方音频素材,无版权问题;
- 全程标红选错的箭头:当箭头被堵住不能正常通过时,该箭头会全程标红。
2.5 关卡介绍
| 关卡 | 棋盘大小 | 箭头数 | 设计重点 |
|---|---|---|---|
| 1 | 5×5 | 8 | 边缘飞出与简单阻挡 |
| 2 | 6×6 | 16 | 前后同向、隔格阻挡 |
| 3 | 6×6 | 36 | 铺满棋盘,横向纵向依赖交错 |
| 4 | 8×8 | 64 | 高密度下的连续解除 |
| 5 | 8×8 | 64 | 高密度下的连续解除 |
| 6 | 8×8 | 64 | 高密度下的连续解除 |
难度介绍: 第1,2,3关 层层递进; 第4,5,6关难度相同,都是铺满整个(8x8)格子。
三、实现思路
3.1 箭头、方向与关卡的表示
方向用字符串 up/down/left/right 表示,对应行列增量:
DIRS = {"up": (-1, 0), "down": (1, 0), "left": (0, -1), "right": (0, 1)}
箭头用 (row, col, direction) 表示(本次基础版全部为单格箭头)。关卡是字典:
{"name": "第 1 关", "rows": 5, "cols": 5, "mistakes": 3,
"arrows": [(0, 1, "right"), (4, 1, "up"), ...]}
3.2 路径检测(重点)
从箭头所在格出发,沿方向逐格前进,越界即可飞出,遇到其他箭头即被阻挡:
def is_blocked(arrows, arrow, rows, cols):
dr, dc = arrow.delta
occupied = set()
for a in arrows:
if a is not arrow:
occupied.update(a.path)
for (r, c) in arrow.path: # 单格箭头 path 只有一个格子
rr, cc = r + dr, c + dc
while 0 <= rr < rows and 0 <= cc < cols:
if (rr, cc) in occupied:
return True
rr += dr
cc += dc
return False
3.3 关卡可通关性校验与生成
关键性质:消除箭头只会减少障碍,不会让原本可飞出的箭头变得被阻挡。因此可以反复贪心移除"当前可飞出"的箭头,若能把棋盘清空,则一定存在通关顺序:
def solve_order(arrows, rows, cols):
remaining = list(arrows)
order = []
progress = True
while progress and remaining:
progress = False
for a in list(remaining):
if not is_blocked(remaining, a, rows, cols):
order.append(a); remaining.remove(a); progress = True
return order if not remaining else None
levels.py在导入时对所有关卡调用solvable(),一旦有死局直接报错;- "铺满棋盘"的关卡使用逆向构造法(
tools/build_levels.py):从内向外依次放置箭头,每放一个都要求它飞出方向上不会撞到已放置的箭头。这样后放的箭头一定先被移除,天然保证可通关。
3.4 动画与状态机
- 游戏状态:
start / level_select / playing / paused / level_clear / game_over / all_clear; - 飞出:箭头逻辑上立即从棋盘移除(避免继续阻挡别人),同时播放位移动画,动画结束再判定胜负;
- 碰撞:先冲出到阻挡箭头前,再平滑飞回原位(前 40% 冲出、后 60% 回位);
- 计时与胜负都延迟到动画结束后结算,避免动画被打断。
3.5 AI 自动求解
载入关卡时用 solve_order() 预先算好该关的点击顺序;点击"AI 求解"后每 0.32 秒自动点掉一个箭头(计时暂停),清空后进入特殊结算界面。
四、AIGC 使用过程
以下均为开发过程中真实发生的协作记录。
记录 1:路径检测与箭头绘制
| 子任务 | 借助何种 AIGC | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 箭头绘制 | Claude / DeepSeek | 给出用多边形绘制箭头的思路与顶点公式 | 方向写反、且退化成一条细线 | 把 x/y 的行列增量对调,并放大头部,恢复正常 |
| 碰撞反馈 | ChatGPT / Claude | 生成"原地左右晃动"的动画代码 | 太单薄,和题目想要的"撞上去再回来"不符 | 改为"冲出→弹回"两段式缓动,并让被堵箭头保持红色 |
| 关卡设计 | Claude / DeepSeek | 生成随机铺排 + 求解器校验的关卡生成脚本 | 6x6 可行,8x8 铺满时随机法成功率几乎为 0 | 改用"逆向构造法",从内向外放置,保证可通关 |
| 飞出音效 | DeepSeek | 用噪声/正弦合成的 whoosh 代码 | 呼啸感太强、太短、后半太重 | 反复调整频率、包络、时长,最终改为单声短促的"ju" |
以下我给出两张我使用AI的图片,不全,只是为了稍微展示一下过程


说明:音效通过 tools/make_sounds.py 用代码合成,多次按"更尖/更轻/更短"的反馈迭代参数。
本来还想去网上寻找一些神秘音效的,但是怕什么版权问题,就不想去搞了。
五、测试结果
单元测试:python -m unittest discover -s tests -v(10 项全部通过)。
手工测试(题目要求的 T01~T06):
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 蓝色箭头飞出并消失 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头变红弹回,失误 -1 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 正常飞出,无越界报错 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 显示星级结算,可进入下一关 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 显示失败界面(含彩蛋动图),可重新开始 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局、失误、计时全部恢复 | 通过 |
补充测试:
- 暂停后计时停止、继续后恢复;
- 时间归零显示"时间到!"失败;
- AI 求解后计时暂停,清空后进入彩蛋结算,可进入下一关;
- 8x8 关卡在窗口内完整显示,无越界。
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 1.0 | 0 |
| Python 与图形库学习 | 1.5 | 1.0 | -0.5 |
| 游戏界面实现 | 2.0 | 3.0 | +1.0 |
| 路径与碰撞逻辑实现 | 2.0 | 2.0 | 0 |
| 关卡设计 | 2.0 | 3.5 | +1.5 |
| AIGC 辅助开发 | 2.0 | 4.0 | +2.0 |
| 测试与修改 | 1.5 | 2.0 | +0.5 |
| README 与博客撰写 | 1.5 | 1.5 | 0 |
| 合计 | 13.5 | 18.0 | +4.5 |
说明:实际耗时明显超出预估,主要集中在界面打磨、关卡生成算法(8x8 铺满)和音效反复调整上。
七、心得体会
AI就是新时代的“黑奴”,又便宜又好用。可以说,我这个项目离了AI,我完全复现不出来。对于代码的生成,修改都是我指导AI做的。你敢想嘛,就在9月18日下午四五点左右,有个骚年才知道“def”在python中是表示“函数”的意思,并且他在第二天借助就把所有的代码整完了,毫无疑问Deepseek得了MVP。只要沟通到位,这点难度的项目对于AI而言,简直太简单了。我发现对于我不擅长的东西,比如说音乐,在让AI帮我调整音效的时候,我一直都是不满意的,没有达到一直我想要的效果,我也不知道怎么沟通,只能说“声音太粗了/太细了”,这种比较范的语言来让AI自己感受,最终我也只是选了我不怎么抵触的音效来加入游戏中,并没有说改的多好。不过对于那种好沟通的,基本我说一声,它都能完成,并且仅生成一次就符合我的预期。也是在撰写心得的时候,我也才开始反思,对于像我这样技术不太过关的码农,要先提升的可能不是编码能力,而是我该如何把需求讲好,讲明白了。但这也不是说我以后就不用手敲了,我只是觉得在这个AI时代,AI写的代码会比我写的好,写的工整,在我还未真正成长之前,我只能先靠AI完成任务,并从中习得一些编码能力。
附:项目结构
arrow_game/
├── main.py # 程序入口
├── board.py # 箭头数据结构、路径检测与关卡求解器
├── levels.py # 关卡数据(导入时自动校验可通关)
├── game.py # pygame 界面、动画与游戏流程
├── audio.py # 音效加载与播放(无音频设备时自动静音)
├── assets/ # 音效、GIF、图片等素材
├── tools/ # 音效合成、关卡生成、调难等脚本
├── screenshots/ # 游戏截图
├── tests/ # 单元测试
├── dist/ArrowOut.exe # 打包后的可执行文件
├── requirements.txt
└── README.md













浙公网安备 33010602011771号