软件工程个人作业2:一箭又一箭小游戏开发
软件工程个人作业2:一箭又一箭小游戏开发
一、作业基础信息
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 052405110 |
| GitHub 仓库 | a-small-game |
二、项目展示
本次开发的“一箭又一箭”小游戏使用 Python + Pygame 实现,拥有完整的开始界面、游戏主界面、通关界面、失败界面,支持多关卡切换、失误判定、碰撞反馈、重新开始功能。
运行gif:

开始界面:

游戏对局界面:

通关界面:

失败碰撞界面:

三、项目介绍
1. 游戏规则
棋盘上分布着朝上(U)、下(D)、左(L)、右(R)四个方向的箭头。玩家点击一个箭头后,程序检测其前进方向上的路径:
- 若箭头与棋盘边界之间没有其他箭头,箭头飞出棋盘并被消除,播放点击音效;
- 若路径上存在其他箭头,箭头不能被消除,并通过晃动、变红和“前方有阻挡!”文字给出碰撞反馈,同时消耗 1 次失误机会,播放错误音效;
- 每关共有 3 次失误机会;清空本关全部箭头即通关并进入下一关;失误次数耗尽则本关失败,可重新开始。
- 路径判定采用网格单格箭头:只需判断同一行(左右箭头)或同一列(上下箭头)、箭头与边界之间是否还有其他箭头。
2. 界面与功能特色
- 完整三级界面:开始页 → 游戏页 → 通关/失败结果页;
- 实时显示:当前关卡、剩余箭头数、剩余失误次数(心形UI)、计时;
- 动态反馈:箭头飞出有透明渐变和位移动画,碰撞有抖动和变色反馈;
- 内置关卡:设计了 5 个满格可通关合法关卡,布局合理、无死锁;
- 多素材集成:主菜单和游戏内加入了背景图片,游戏全程配有背景音乐(BGM)和交互音效。
四、实现思路与核心原理
4.1 箭头和方向怎么表示
方向用四个字符常量 U D L R,每个方向对应一组「行增量、列增量」:
DIRECTIONS = {
'U': (-1, 0), # 上
'D': (1, 0), # 下
'L': (0, -1), # 左
'R': (0, 1), # 右
}
这里有个容易搞反的地方:屏幕坐标系里 y 轴是向下的,所以第 0 行在最上面,"向上" 是行号减一。我一开始把 U 写成 (1, 0),结果所有上下箭头的路径检测都反了,直到实际试玩时才发现"明明朝上的箭头点了说被挡"。
棋盘用二维列表存储:board[r][c] 存放方向字符或 None(空格)。选二维列表而不是字典,是因为棋盘是稠密矩形网格,按坐标直接索引 O(1)。
4.2 路径检测(核心)
这是整个程序最关键的一段。做法是从箭头的下一个格子开始,沿它指的方向一格一格往外走:
def is_blocked(self, row, col):
d = self.board[row][col]
if d is None: return False
dr, dc = DIRECTIONS[d]
n = len(self.board)
r, c = row + dr, col + dc
while 0 <= r < n and 0 <= c < n:
if self.board[r][c] is not None:
return True # 碰到箭头 -> 被挡住
r += dr
c += dc
return False # 走出棋盘了 -> 可以飞出
几个关键点:
从下一格开始,不检测箭头自身所在的格子;
只沿方向向量走(同行或同列),不会跨行误判;
遇到边界自动停止,0 <= r < n 兜底,不会数组越界;
返回纯布尔值,调用方根据结果决定是消除还是扣失误,逻辑和界面完全解耦。
4.3 关卡设计:如何保证满格且有解
为了增加游戏画面饱满度和挑战性,我设计了 5 个满格(每个格子都有箭头)的关卡。
设计思路采用了两种必定有解的策略:
整行/整列同向(第 1-4 关):例如第一行全是 U,第二行全是 R。玩家只需按行或列的顺序依次点击,总能全部飞出。
螺旋矩阵(第 5 关):从最外圈开始,按顺时针方向 R -> D -> L -> U 排列,一层层往里清,最后清空中心点。这种设计在逻辑上保证了绝对有解,不会出现死锁。
4.4 音效与背景图集成
为了提升游戏体验,我在 assets 文件夹中引入了背景图与音频。在 Pygame 中,音频和图片的加载需要容错处理,否则文件缺失会导致游戏直接崩溃:
def load_audio(filename):
path = os.path.join(ASSETS_DIR, filename)
if os.path.exists(path):
try:
return pygame.mixer.Sound(path)
except pygame.error:
print(f"无法加载音频: {path}")
return None
游戏通过 pygame.mixer.music.play(-1) 实现背景音乐的循环播放。
五、AIGC 辅助开发过程(3次真实记录)
本作业使用 AIGC 工具(DeepSeek)辅助开发。以下是 3 次具有代表性的协作过程:
| 子任务 | 借助何种 AIGC 技术 | AI 实现或提供了什么 | 效果如何 | 人工修改 |
|---|---|---|---|---|
| 环境搭建 | DeepSeek | 给出安装 pygame 的命令和 VS Code 配置指导 |
电脑存在多个 Python 版本,pip 安装到了 3.11 而 VS Code 使用的是 3.12,导致报错 |
使用绝对路径 "C:\...\python.exe" -m pip install pygame 重新安装,并切换 VS Code 解释器解决 |
| 字体与资源加载 | DeepSeek | 生成 SysFont 加载字体及图片音频加载代码 |
运行时报 TypeError: expected str, bytes or os.PathLike object, not int,且图片音频死活加载不出来 |
改用 pygame.font.Font('C:/Windows/Fonts/msyh.ttc', size) 绕过兼容性 bug;排查发现 Windows 隐藏了文件扩展名(变成 .png.jpg),手动重命名后正常 |
| 满格关卡设计 | DeepSeek | 生成满格关卡数组与死锁检测思路 | 初版生成的关卡存在同行/同列互堵死锁,且每个格子都必须填满,难度失衡 | 采用“整行/整列同向”与“螺旋矩阵”结构重新设计,人工推演验证确保 5 关绝对有解 |
记录 1:环境搭建与依赖冲突(Python 版本冲突)
- 提出的要求:如何在 Windows 上为 Python 项目正确安装 pygame 并在 VS Code 中运行?
- AI 完成的工作:给出了基础的
pip install pygame命令,以及 VS Code 选择解释器的步骤。 - 实际效果与问题:电脑中存在 Python 3.11 和 3.12 两个版本。在 CMD 中执行
pip install默认安装到了 3.11,但 VS Code 默认使用的是 3.12。导致 VS Code 运行时报ModuleNotFoundError: No module named 'pygame'。 - 人工修改:通过绝对路径强制为 3.12 安装:
"C:\Users\...\Python312\python.exe" -m pip install pygame,并在 VS Code 中手动切换解释器版本,最终解决了环境问题。
记录 2:字体加载报错与资源路径排查(隐蔽陷阱)
- 提出的要求:给游戏加上中文文字、背景图片和背景音乐。
- AI 完成的工作:生成了
pygame.font.SysFont以及pygame.image.load、pygame.mixer.Sound的资源加载代码。 - 实际效果与问题:运行后游戏直接崩溃,报错
TypeError: expected str, bytes or os.PathLike object, not int。此外,图片和音频一直加载失败,但在电脑文件夹里明明能看到文件。 - 人工修改:① 发现是
SysFont的底层兼容性 bug,果断改用pygame.font.Font('C:/Windows/Fonts/msyh.ttc', size)直接加载系统字体;② 排查发现是 Windows 默认隐藏了文件扩展名,我的文件实际是bg_menu.png.jpg,手动开启扩展名显示并重命名后,图片和音乐终于成功加载。
记录 3:满格关卡设计(可解性验证)
- 提出的要求:把游戏扩充到 5 个关卡,保证每个格子都有箭头,且关卡要有解。
- AI 完成的工作:生成了多个满格关卡的二维数组,并提示可以用贪心思路验证。
- 实际效果与问题:AI 随机生成的满格关卡中,出现了同一行
L...R或者同一列U...D互堵死锁的情况,导致关卡根本无解。 - 人工修改:采用“整行同向”和“螺旋矩阵”的数学结构手动重写了 5 个关卡的数据。例如第五关从外圈顺时针排列,一层层向内清空,从逻辑上确保了绝对不会死锁。
六、项目测试结果
测试环境:Windows + Python 3.12.4 + Pygame 2.6.1
测试方式:手工测试与试玩验证
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失,播放音效 | 箭头飞出,剩余数量减少,音效正常 | ✅ 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1,有抖动反馈 | 箭头抖动变红,失误 3→2,播放错误音效 | ✅ 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 箭头正常消失,不发生越界错误 | 上下左右及角落箭头均正常飞出,无报错 | ✅ 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 进入结算页面,点击继续进入下一关 | ✅ 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 进入失败界面,点击重新开始恢复当前关 | ✅ 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局、失误次数、飞行动画均重置为初始状态 | ✅ 通过 |
| 附加 | 5个满格关卡可解性验证 | 每关都存在通关顺序 | 人工推演试玩,5关全部可正常通关 | ✅ 通过 |
测试小结:共 6 项核心测试及附加测试全部通过。测试不仅验证了需求,还真实暴露了开发中的多个 Bug(环境冲突、字体加载、隐藏扩展名、关卡死锁),体现了“先写用例、再验证”的价值。
七、PSP 个人软件开发过程量表
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 0.5 | -0.5 |
| Python 与图形库学习 | 1.0 | 1.5 | +0.5 |
| 游戏界面实现 | 2.0 | 2.0 | 0 |
| 路径与碰撞逻辑实现 | 2.0 | 1.5 | -0.5 |
| 关卡设计(含5关满格设计) | 1.0 | 2.0 | +1.0 |
| AIGC 辅助开发与排错 | 2.0 | 3.0 | +1.0 |
| 测试与修改 | 1.0 | 1.5 | +0.5 |
| README 与博客撰写 | 2.0 | 2.0 | 0 |
| 合计 | 12.0 | 14.0 | +2.0 |
八、心得体会
AI 带来的帮助:AIGC 把“从零搭框架”变成了“在草稿上修改”。路径检测、动画逻辑、资源加载这些成熟模式,AI 能一次性给出可用版本,让我把精力集中在真正需要判断的地方——边界条件、关卡可解性、交互细节。
出现的问题:AI 生成代码最大的风险是“看起来对、实际错”。本次 AI 的路径检测方向向量写错、关卡出现互堵死锁、SysFont 字体兼容性报错,都是只靠肉眼检查发现不了的。特别是在配置环境时,因为电脑装了两个 Python 版本,绕了很大的弯路。这提醒我:AI 是“高效的草稿生成器”,不是“可靠的代码评审员”,把 AI 代码直接当正确答案是最危险的用法。
我的收获:一是真正理解了本游戏路径检测与“互堵死锁”的本质,并学会用数学结构(整行同向、螺旋矩阵)去构造必定有解的关卡;二是掌握了“遇到报错先看终端输出、排查文件扩展名、使用绝对路径”的工程排错习惯;三是对 AI 协作有了更理性的定位——提问要具体,验证要独立(测试、试玩),修改要敢下手。这次查错让我亲身体会到,AI 修改过的代码必须回归测试,环境配置必须锱铢必较。
浙公网安备 33010602011771号