2026秋软件工程第二次个人作业
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice | |
|---|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice/homework/16718 | |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 | |
| 学号 | 102402104 | |
| GitHub 仓库 | https://github.com/asakinza/arrow-game |
项目展示
- 开始界面
开始界面包含游戏标题“一箭又一箭”、游戏规则说明以及“开始游戏”按钮。规则清晰列出了四条核心玩法,玩家进入游戏前可以快速了解操作方式。

- 游戏过程
游戏界面顶部显示当前关卡、剩余箭头数量和失误次数。棋盘为 8×8 网格,箭头使用不同颜色区分方向:红色向上、绿色向下、蓝色向左、黄色向右。点击箭头时,如果前方无阻挡,箭头会向对应方向飞出并逐渐缩小消失;如果前方有阻挡,箭头会红色晃动并消耗一次失误机会。

- 通关与失败界面
当棋盘上所有箭头被清除后,显示“关卡完成!”并提供“下一关”按钮;如果是最后一关完成,则显示“恭喜通关!”并提供“重新开始”按钮。当失误次数达到 3 次时,显示“游戏失败”并提供“重试”按钮。


项目介绍
-
游戏规则
“一箭又一箭”是一款基于网格的益智消除游戏。棋盘上分布着朝向上下左右四个方向的箭头,玩家需要按照正确的顺序点击箭头,使其飞出棋盘。规则如下:
点击箭头后,程序检查其前进方向上是否存在其他箭头;
若前方无阻挡,箭头会向对应方向飞出棋盘并消失;
若前方有阻挡,箭头无法飞出,会晃动并消耗一次失误机会;
失误次数达到 3 次,本关失败;
清除棋盘上所有箭头即可通关,进入下一关。 -
界面设计
开始界面:标题、规则说明、开始按钮;
游戏界面:顶部信息栏(关卡、剩余箭头、失误次数)、重玩按钮、8×8 棋盘;
结果界面:通关提示 + 下一关按钮,或失败提示 + 重试按钮。 -
主要功能
四种方向箭头的图形化显示;
鼠标点击选择箭头;
路径检测与碰撞判断;
飞出动画和碰撞晃动反馈;
失误次数统计与显示;
三个可通关关卡;
关卡切换、重新开始、失败重试。 -
特色
箭头使用“线条 + 三角形箭头”的绘制方式,视觉上更接近参考图风格;
不同方向使用不同颜色,便于玩家快速识别;
飞出动画中箭头会逐渐缩小,增强消除的爽快感;
碰撞时箭头红色晃动,反馈明显。 -
实现思路
-
箭头与方向的表示
棋盘使用二维列表 grid 表示,每个元素为整数:
0:空单元格;
1:向上箭头;
2:向下箭头;
3:向左箭头;
4:向右箭头。 -
方向向量通过字典 DIRECTIONS 定义:
DIRECTIONS = {
'UP': (0, -1),
'DOWN': (0, 1),
'LEFT': (-1, 0),
'RIGHT': (1, 0)
}
其中 (dx, dy) 分别表示列方向和行方向的增量。
- 路径检测方法
路径检测是游戏的核心逻辑。给定箭头所在的行 row、列 col,从其当前位置出发,沿箭头方向逐步前进,检查路径上是否存在其他箭头:
def check_path(self, row, col):
direction = self.grid[row][col]
dx, dy = DIRECTIONS[list(DIRECTIONS.keys())[direction - 1]]
r, c = row + dy, col + dx
while 0 <= r < GRID_SIZE and 0 <= c < GRID_SIZE:
if self.grid[r][c] != 0:
return False # 有阻挡
r += dy
c += dx
return True # 无阻挡,可以飞出
-
关键点说明:
从 row + dy, col + dx 开始检查,跳过自身;
while 循环条件同时判断行和列是否越界,确保不会出现数组越界;
如果路径上遇到非零元素,说明有阻挡,返回 False;
如果循环正常结束(走出棋盘边界),说明前方无阻挡,返回 True。
这种“逐步探测”的方式天然处理了边缘情况:当箭头位于边缘且朝向棋盘外时,循环体一次都不会执行,直接返回 True,箭头正常飞出。 -
飞出与碰撞的处理
飞出逻辑:当 check_path 返回 True 时,将该箭头从 grid 中置零,减少 arrows_left,并向 animating_arrows 列表中添加一条动画数据,记录起始位置、方向和进度。
碰撞逻辑:当 check_path 返回 False 时,增加 mistakes,并向 shake_arrows 列表中添加一条晃动数据,记录位置和计时器。 -
动画实现
飞出动画:每帧更新 progress,根据方向和进度计算偏移量,同时按比例缩小箭头尺寸;当 progress >= 1.0 时移除该动画。
晃动动画:每帧减少 timer,使用 sin(timer * 0.8) * 4 计算水平偏移,产生左右晃动效果;timer <= 0 时移除。 -
关卡数据
关卡使用与 grid 相同结构的二维列表定义,三个关卡分别设计了不同的布局:
关卡 1:简单的十字交叉,箭头数量少,适合熟悉规则;
关卡 2:需要按顺序清理,存在相互阻挡的箭头对;
关卡 3:复杂的回环布局,箭头数量多,需要仔细规划点击顺序。
每个关卡都经过实际试玩,确保存在合理的通关顺序。
AIGC 使用过程
记录 1:路径检测代码的生成与边界修复
| 项目 | 内容 |
|---|---|
| 子任务 | 路径检测 |
| AIGC 技术 | DeepSeek |
| AI 实现或提供了什么 | 生成四个方向的路径检测代码 |
| 效果如何 | 向上判断时出现越界 |
| 人工修改 | 修改边界条件后正常 |
我的要求:请帮我写一个函数,检查棋盘中某个箭头前方是否有阻挡,箭头有上下左右四个方向。
AI 的回复:AI 给出了一个 check_path 函数,使用 while 循环沿方向逐步检查。但初始版本在向上方向时,循环条件只判断了 r >= 0,没有同时判断 c 的范围,导致在某些边界情况下出现索引越界。
我的修改:将循环条件改为同时判断行和列:
while 0 <= r < GRID_SIZE and 0 <= c < GRID_SIZE:
修改后测试了四个方向的边缘情况,均不再出现越界错误。
实际效果:路径检测功能正常,T01、T02、T03 测试均通过。
记录 2:关卡数据的设计与验证
| 项目 | 内容 |
|---|---|
| 子任务 | 路径检测 |
| AIGC 技术 | DeepSeek |
| AI 实现或提供了什么 | 生成关卡数组 |
| 效果如何 | 存在无法通关的布局 |
| 人工修改 | 手工调整并试玩验证 |
我的要求:请帮我设计三个 8×8 的箭头关卡,用 0 表示空、1 表示上、2 表示下、3 表示左、4 表示右,要求每个关卡都能通关。
AI 的回复:AI 生成了三组关卡数据。其中关卡 2 的初始版本中,有两个箭头相互阻挡,且周围没有其他箭头可以先行清除,导致死局。
我的修改:手工调整了关卡 2 的布局,将相互阻挡的一对箭头改为由第三个箭头隔开,确保存在合法的清除顺序。调整后实际试玩验证,确认可以通关。
实际效果:三个关卡均可正常通关,T04 测试通过。
记录 3:碰撞晃动动画的补全
| 项目 | 内容 |
|---|---|
| 子任务 | 碰撞动画 |
| AIGC 技术 | DeepSeek |
| AI 实现或提供了什么 | 补全箭头晃动代码 |
| 效果如何 | 基本可用 |
| 人工修改 | 调整动画速度 |
我的要求:请帮我写一个碰撞时箭头左右晃动的动画效果,持续一小段时间后恢复。
AI 的回复:AI 建议使用 sin 函数计算水平偏移,并维护一个计时器列表。给出了核心代码:
offset_x = math.sin(shake['timer'] * 0.8) * 4
我的修改:初始版本中 timer 设为 30,晃动持续时间较长,视觉上不够干脆。我将其调整为 15,并适当增大振幅到 4 像素,使反馈更明显。
实际效果:碰撞反馈清晰,T02 测试通过。
六、测试结果
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头向对应方向飞出并缩小消失,剩余箭头数减 1 | ✅ |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头红色晃动,失误次数 +1,箭头仍在原位 | ✅ |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 箭头正常飞出,无报错 | ✅ |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 显示“关卡完成!”,点击“下一关”进入下一关 | ✅ |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 显示“游戏失败”,点击“重试”可重新开始 | ✅ |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 点击“重玩”后,棋盘恢复初始布局,失误次数归零 | ✅ |
补充测试:
连续点击同一个箭头:已飞出的箭头位置为空,点击无效,不消耗失误;
点击空白格子:无任何反应,不消耗失误;
最后一关完成后:显示“恭喜通关!”,点击“重新开始”回到第一关。
PSP 表格
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 1.5 | +0.5 |
| Python 与图形库学习 | 2.0 | 2.5 | +0.5 |
| 游戏界面实现 | 3.0 | 3.5 | +0.5 |
| 路径与碰撞逻辑实现 | 2.0 | 2.0 | 0 |
| 关卡设计 | 1.5 | 2.0 | +0.5 |
| AIGC 辅助开发 | 2.0 | 2.5 | +0.5 |
| 测试与修改 | 2.0 | 2.5 | +0.5 |
| README 与博客撰写 | 2.0 | 2.5 | +0.5 |
| 合计 | 15.5 | 19.0 | +3.5 |
实际耗时比预估多出约 3.5 小时,主要原因是路径检测的边界问题调试和关卡通关性验证花费了较多时间。AIGC 工具在代码生成方面节省了时间,但验证和修改仍需要人工投入。
心得体会
AI 带来的帮助
快速生成代码框架:AI 能够根据我的描述快速生成 check_path、动画更新等核心逻辑的代码框架,减少了从零开始编写的时间。
提供思路启发:在碰撞动画的实现上,AI 建议使用 sin 函数产生晃动效果,这个思路比我最初设想的“左右位移交替”更简洁。
辅助调试:当我描述“向上判断时越界”的问题时,AI 能够快速定位到循环条件的问题,并给出修改建议。
出现的问题
AI 生成的代码不能直接使用:路径检测的边界条件、关卡数据的可通关性都需要人工验证和修改。
关卡设计需要实际试玩:AI 生成的关卡布局存在死局,必须通过实际试玩才能发现。
动画参数需要调优:AI 给出的晃动时长和振幅偏保守,实际效果不够明显,需要根据视觉感受调整。
我的收获
理解了路径检测的核心逻辑:通过逐步探测的方式,可以简洁地处理四个方向和边界情况。
学会了用列表管理动画状态:将动画数据存储在列表中,每帧更新并移除已完成项,是一种通用的动画管理方式。
认识到 AIGC 是助手而非替代品:AI 可以加速开发,但关键逻辑的正确性、关卡的可玩性、视觉效果的调优仍然需要开发者自己负责。
对 AIGC 使用的反思
在使用 AIGC 的过程中,我深刻体会到“提要求”的重要性。模糊的需求会得到模糊的代码,而具体、有约束条件的需求才能得到可用的结果。同时,AI 生成的代码必须经过自己的理解和验证,不能盲目复制。只有真正理解了代码的逻辑,才能在出现问题时快速定位和修复。
浙公网安备 33010602011771号