2026 秋软件工程个人作业(第二次)
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401304 |
| GitHub 仓库 | https://github.com/Sakura-x000/arrow-game |
一、项目展示
1. 关卡选择界面

一开始只能选第 1 关,其他关卡灰色“未解锁”。通关后自动解锁下一关。每关显示已获得的星数和最快用时,限时模式显示最高分。
2. 游戏界面

顶部显示当前关卡、剩余箭头、失误次数、用时。下面两行按钮:暂停、撤销、提示、重新开始、返回。棋盘是彩色箭头,四方向。
3. 通关界面

弹出“太棒了!”,按失误次数显示 1~3 星,并显示本关用时。第 1~5 关有“下一关”和“返回选关”。
4. 失败界面

失误达到 3 次时弹出“再试一次吧!”,可以“重来”或“返回选关”。返回不会解锁下一关。
5. 限时模式


第 6 关是限时模式,进关前弹出玩法说明。地图随机生成,30 秒内点击箭头得分,连续 3 连击 +2 秒,点到被挡箭头 -2 秒。结算显示连击、用时、分数和最高分。
二、项目介绍
游戏规则
- 棋盘是网格,每个格子里可能有一个箭头,方向为上、下、左、右。
- 点击箭头,程序检查它前进方向上有没有别的箭头。
- 前方没有阻挡 → 箭头飞出棋盘并消失。
- 前方有阻挡 → 箭头原地晃动变红,失误次数 +1。
- 清空全部箭头 → 通关,按失误次数获得 1~3 星。
- 失误达到 3 次 → 失败,可以重来或返回选关。
- 通关当前关卡解锁下一关。
关卡设计
| 关卡 | 网格 | 类型 |
|---|---|---|
| 第 1 关 | 4x4 | 普通 |
| 第 2 关 | 4x4 | 普通 |
| 第 3 关 | 4x4 | 普通 |
| 第 4 关 | 5x5 | 普通 |
| 第 5 关 | 6x6 | 普通 |
| 第 6 关 | 7x7 | 限时模式,随机生成 |
界面设计
- 深蓝渐变背景,带装饰圆点
- 顶部深色圆角卡片显示关卡信息
- 棋盘用浅色卡片包住
- 按钮圆角 + 阴影 + 悬停变色
- 结算弹窗居中,带圆角和阴影
主要功能
- 四个方向的箭头
- 鼠标点击交互
- 路径阻挡判断
- 飞出动画(渐隐)
- 碰撞反馈(晃动 + 变红)
- 失误计数
- 6 个关卡(3 个 4x4、1 个 5x5、1 个 6x6、1 个限时模式)
- 关卡选择与解锁
- 星级评价
- 每关用时记录
- 限时模式:倒计时、连击、加分、最高分
- 撤销(限 3 次)
- 提示(限 3 次,高亮可飞箭头)
- 暂停、保存进度、继续存档
- 重新开始、返回选关
三、实现思路
1. 箭头怎么表示
每个关卡是一个二维列表,每个格子要么是 0(空),要么是 'U' / 'D' / 'L' / 'R'。
['R', 0, 0, 'U'],
表示第 0 行第 0 列是朝右的箭头,第 0 行第 3 列是朝上的箭头。
2. 方向怎么表示
用一个字典把方向字母翻译成“行变化、列变化”:
DIRS = {
'U': (-1, 0), # 上:行 -1,列不变
'D': (1, 0), # 下:行 +1,列不变
'L': (0, -1), # 左:行不变,列 -1
'R': (0, 1), # 右:行不变,列 +1
}
因为 Pygame 和二维列表的 y 轴都向下,所以“上”对应行 -1,“下”对应行 +1。
3. 路径检测
点一个箭头时,沿它的方向一格一格往外走,只要遇到非空格子就说明被挡:
def is_blocked(r, c, direction):
dr, dc = DIRS[direction]
nr, nc = r + dr, c + dc
while 0 <= nr < ROWS and 0 <= nc < COLS:
if board[nr][nc] != 0:
return True
nr += dr
nc += dc
return False
比如朝右 R,就从 c+1 一直看到最右列;朝上 U,就从 r-1 一直看到最上行。
4. 飞出方向
飞出速度直接用同一个 DIRS:
dr, dc = DIRS[cell]
vx = dc * 22 # 列变化 → 横向
vy = dr * 22 # 行变化 → 纵向
这样箭头指向哪,就飞向哪,不会错。
5. 画箭头
为了不出错,四个方向分别写死顶点坐标,不做旋转:
- 朝右:箭头指向 +x
- 朝左:箭头指向 -x
- 朝上:箭头指向 -y
- 朝下:箭头指向 +y
6. 撤销
每次点击箭头前,把当前棋盘、失误、用时存进一个栈:
def push_undo():
undo_stack.append({
"board": [[cell for cell in row] for row in board],
"mistakes": mistakes,
"elapsed_ms": get_elapsed_ms(),
})
点“撤销”时弹出栈顶恢复。每关限 3 次。
7. 提示
找出当前所有前方无阻挡的箭头,随机选一个高亮:
def find_free_arrows():
result = []
for r in range(ROWS):
for c in range(COLS):
cell = board[r][c]
if cell != 0 and not is_blocked(r, c, cell):
result.append((r, c))
return result
高亮闪烁 2 次,每关限 3 次。
8. 限时模式
- 每关进前先弹玩法说明
- 30 秒倒计时,点掉箭头 +1 分,3 连击 +2 秒
- 点到被挡箭头 -2 秒,连击清零
- 时间到结算,分数 = 箭头数 + 剩余秒数 ÷ 2
- 地图随机生成时避免面对面箭头,保证有解
四、AIGC 使用过程
记录 1:路径检测
| 项目 | 内容 |
|---|---|
| 子任务 | 路径检测 |
| AIGC 工具 | DeepSeek |
| 提问 | 请帮我解释一下 Python 里 is_blocked 函数是怎么判断箭头前方有没有阻挡的。 |
| AI 提供 | 解释了 DIRS 字典的作用、while 循环怎么沿方向走、any 和 range 怎么用。 |
| 效果 | 帮助我理解了代码逻辑,确认方向字典用 (dr, dc) 是对的。 |
| 人工修改 | 原本想用 any 简写,后来改成 while 循环,更容易看懂。 |
记录 2:飞出动画
| 项目 | 内容 |
|---|---|
| 子任务 | 飞出渐隐动画 |
| AIGC 工具 | ChatGPT |
| 提问 | 我想给这个 Pygame 小游戏加一个箭头飞出时的渐隐动画,请给我代码。 |
| AI 提供 | 用 pygame.Surface 加 SRCALPHA 画半透明箭头,每帧增加 fade 值。 |
| 效果 | 基本可用,箭头飞出时慢慢消失。 |
| 人工修改 | 调整了每帧位移量和渐隐速度,让动画更自然。 |
记录 3:关卡设计
| 项目 | 内容 |
|---|---|
| 子任务 | 第 3 关设计 |
| AIGC 工具 | Kimi |
| 提问 | 请帮我设计一个 4x4 的“一箭又一箭”关卡,要求有解,并给出通关顺序。 |
| AI 提供 | 给出布局和通关顺序。 |
| 效果 | 第一次给的布局有死局,同一行两个相对箭头互相挡。 |
| 人工修改 | 手工调整布局,把相对箭头放到不同行,最终确定第 3 关。 |
记录 4:撤销功能
| 项目 | 内容 |
|---|---|
| 子任务 | 撤销 |
| AIGC 工具 | DeepSeek |
| 提问 | 用 Python 实现撤销上一步,保存棋盘和状态,限 3 次。 |
| AI 提供 | 用一个 list 当栈,每次点击前 append 当前状态,撤销时 pop。 |
| 效果 | 可用。 |
| 人工修改 | 加了最多 50 步限制,防止内存太大;每关重置次数。 |
记录 5:限时模式
| 项目 | 内容 |
|---|---|
| 子任务 | 限时模式 |
| AIGC 工具 | ChatGPT |
| 提问 | 用 Pygame 做一个 30 秒倒计时模式,点箭头加分,3 连击加时。 |
| AI 提供 | 用 pygame.time.get_ticks() 记录每帧间隔,扣倒计时。 |
| 效果 | 基本可用。 |
| 人工修改 | 加了结算界面、最高分记录、地图随机生成。 |
记录 6:界面排版
| 项目 | 内容 |
|---|---|
| 子任务 | 顶部按钮排版 |
| AIGC 工具 | Kimi |
| 提问 | 游戏顶部有 5 个按钮和 3 行信息,怎么排不重叠。 |
| AI 提供 | 建议按钮分两行靠右,信息靠左动态排。 |
| 效果 | 可用。 |
| 人工修改 | 按窗口宽度动态算按钮位置,信息按渲染宽度依次排。 |
五、测试结果
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头沿指向飞出,渐隐后消失 | ✅ 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头原地晃动变红,失误 +1 | ✅ 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 箭头正常飞出,无越界、无报错 | ✅ 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 弹出“太棒了!”弹窗,显示星数 | ✅ 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 弹出“再试一次吧!”弹窗,可重来 | ✅ 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局恢复初始,失误归零 | ✅ 通过 |
| T07 | 通关第 1 关后返回选关 | 第 2 关解锁 | 第 2 关从灰色变为可点击 | ✅ 通过 |
| T08 | 通关时按失误次数计算星数 | 失误 0 次 3 星,1 次 2 星,2 次 1 星 | 星数与失误次数对应正确 | ✅ 通过 |
| T09 | 第 5 关通关后 | 进入限时模式弹窗 | 弹窗显示玩法说明 | ✅ 通过 |
| T10 | 失败后返回选关 | 不解锁下一关 | 下一关仍为灰色 | ✅ 通过 |
| T11 | 点撤销 | 恢复上一步,次数 -1 | 棋盘、失误、用时都恢复 | ✅ 通过 |
| T12 | 点提示 | 高亮可飞箭头,闪两次 | 黄色高亮闪烁 | ✅ 通过 |
| T13 | 暂停并保存 | 存档,选关界面显示“有存档” | 存档生效 | ✅ 通过 |
| T14 | 继续存档 | 恢复棋盘、失误、用时 | 状态恢复 | ✅ 通过 |
| T15 | 限时模式倒计时 | 30 秒倒计时,3 连击 +2 秒 | 倒计时正常 | ✅ 通过 |
| T16 | 限时模式结算 | 显示连击、用时、分数、最高分 | 符合预期 | ✅ 通过 |
六、PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1 | 1 | 0 |
| Python 与图形库学习 | 2 | 2 | 0 |
| 游戏界面实现 | 3 | 4 | +1 |
| 路径与碰撞逻辑实现 | 2 | 2.5 | +0.5 |
| 关卡设计 | 1 | 2 | +1 |
| 撤销、提示、暂停、存档 | 2 | 2.5 | +0.5 |
| 第 4、5 关扩大网格 | 1 | 1 | 0 |
| 限时模式 | 2 | 3 | +1 |
| 界面排版优化 | 1 | 2 | +1 |
| AIGC 辅助开发 | 2 | 2 | 0 |
| 测试与修改 | 2 | 2.5 | +0.5 |
| README 与博客撰写 | 2 | 2 | 0 |
| 合计 | 21 | 26.5 | +5.5 |
七、心得体会
这次作业让我第一次完整地做了一个小游戏,也第一次真正用 AIGC 工具辅助开发。
AI 带来的帮助:
- 帮我搭出了游戏框架,省去了从零开始写界面的时间。
- 帮我解释了路径检测的逻辑,让我理解了方向字典的用法。
- 帮我设计了关卡、动画、撤销、提示、限时模式。
- 界面美化时给了不少建议。
遇到的问题:
- 方向判断一开始总出错,箭头指向和飞出方向不一致。后来发现问题出在方向字典的元组顺序上,统一改成
(dr, dc)后就好了。 - 关卡设计很容易出现死局,同一行两个相对箭头会互相挡。后来学会先手工验证一遍再写进关卡数据。
- 限时模式随机生成箭头时,第一次也出现了面对面箭头,后来加了生成前的检测。
- 界面一开始很简陋,后来一步步调颜色、加卡片、加圆角。按钮太多时还会遮挡,最后改成两行靠右排列。
- 窗口尺寸和关卡网格大小相关,进不同关卡要重新调整窗口,一开始忘了处理,导致闪退。
收获:
- 理解了二维网格游戏的基本结构:数据、方向、路径检测、动画、状态管理。
- 学会了怎么和 AI 协作:AI 给代码,我负责运行、测试、发现问题、让它改。
- 知道了 AI 生成的代码不能直接用,必须自己跑一遍,尤其是方向、边界、布局这些地方。
- 学会了把一个大功能拆成几个小步骤,每步跑通再继续。
总的来说,这次作业让我对 Python 和游戏开发有了直观的认识,也让我更清楚 AI 能帮什么、不能帮什么。

浙公网安备 33010602011771号