第二次个人作业-arrowagain小游戏的开发
第二次个人作业-arrowagain小游戏的开发
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401209 |
| GitHub 仓库 | 仓库链接 |
一、项目展示
总体演示效果如下(仅展示部分功能和界面,后续会详细进行展示)。

开始界面
开始界面:

开始界面包含游戏标题、规则示意、开始游戏、关卡选择、玩法说明、退出游戏和音效开关。
中间的示意区域用两支箭头说明最核心的游戏规则:如果箭头正前方存在其他箭头,它就会受到阻挡;如果从当前位置到棋盘边缘之间没有其他箭头,它就可以直接飞出棋盘。做到见图知意
如果本地保存了尚未完成的残局,主按钮会从“开始游戏”变为“继续游戏”,玩家可以恢复上一次保存时的棋盘、失误次数、用时和得分状态。
游戏过程
游戏过程的动态展示:

游戏界面分成左右两个区域:左侧是箭头棋盘,右侧是关卡信息与操作区域。
- 左侧棋盘根据关卡自动适配 6×6、7×7 或 8×8 的网格;
- 箭头使用四种不同颜色区分上、下、左、右方向;
- 右上角用三颗爱心表示本关剩余的失误机会;
- 信息面板实时显示棋盘大小、剩余箭头数、失误机会、用时和当前分数;
- 玩家可以使用提示、重新开始、查看说明或保存当前残局;
- 鼠标悬停到箭头上时会出现描边和放大反馈,点击时会出现波纹与粒子效果。
我们还提供了提示功能。点击“提示”或按下 H,系统会用金色光圈标出一支当前一定能够飞出的箭头。提示不会直接替玩家操作,也不会改变棋盘,不过每次新提示会扣除 100 分。
通关画面

清空棋盘中的全部箭头后,游戏进入通关结算。结算卡片会显示本关得分、通关时间、提示次数和 1~3 星评价,并保存该固定关卡的最佳得分、最短用时与最高星级。
失败画面


每一关固定有 3 次失误机会。当玩家第三次点击被阻挡的箭头并完成碰撞反馈后,游戏进入失败状态,底层棋盘停止响应点击。失败界面会显示本局用时和已经获得的过程分数,并提供“重新挑战”和“返回首页”等操作。
关卡选择

这一部分我们额外加入了三种不同难度的随机挑战和通过三个基础关卡后的三个隐藏关卡,截图中的第456在游戏初始化时是被锁住的,只有通过第三关以后才会解锁。
二、项目介绍
游戏简介
本项目名为 ArrowAgain(箭途),是一款以观察和顺序推理为核心的单人点击解谜游戏。玩家需要判断每支箭头前方是否存在阻挡,并选择正确的消除顺序,使所有箭头依次飞出棋盘。
游戏规则
棋盘左上角为 (0, 0),行号向下递增,列号向右递增。每个格子最多存在一支箭头,箭头方向只有 UP、DOWN、LEFT、RIGHT 四种。
玩家点击箭头后,程序从箭头的下一格开始,沿箭头方向逐格检查:
- 如果到达棋盘边界前发现其他箭头,本次点击判定为碰撞;
- 如果一直检查到棋盘外仍没有发现箭头,本次点击判定为成功;
- 成功箭头播放飞出动画并被移除;
- 碰撞箭头不会消失,但会扣除 1 次失误机会;
- 清空本关全部箭头即可通关,失误次数降到 0 则挑战失败。
界面设计
游戏使用统一的可爱星空主题。背景负责营造轻松、友好的氛围,棋盘与功能区则使用深色面板保证箭头和文字的对比度。
界面截图如下:

- 向上箭头使用青色,向下箭头使用紫色;
- 向左箭头使用金色,向右箭头使用蓝色;
- 成功反馈使用绿色,碰撞与失败反馈使用红色;
- 可操作按钮具有悬停高亮、按下位移和禁用状态;
- 关卡结果使用星级、分数和时间共同表达完成质量;
- Windows 下启用了高 DPI 感知,避免系统缩放造成字体和图形模糊。
主要功能
目前游戏已经实现以下功能:
- 完整的开始、关卡选择、游戏、帮助、通关、失败和全部通关界面;
- 上、下、左、右四方向箭头及正确的直线路径判断;
- 成功飞出、受阻碰撞、短尾迹、波纹和粒子反馈;
- 每关固定 3 次失误机会,以及重新开始和失败重试;
- 三个基础关卡:6×6/12 支箭、7×7/16 支箭、7×7/20 支箭;
- 三个 8×8 扩展关卡,分别包含 24、28、32 支箭;
- 关卡选择、挑战关卡解锁和最佳成绩记录;
- 计时、得分、提示扣分和 1~3 星评价;
- 休闲、标准、困难三档随机可解关卡;
- 当前残局与音效设置的本地保存;
- 可关闭的程序合成音效;
- Windows 单文件可执行程序。
游戏特色
项目使用 Python 与 Pygame 开发,在完成课程要求的开始界面、游戏界面、结果界面、四方向箭头、碰撞反馈、三次失误和三个基础关卡后,又增加了关卡选择、扩展关卡、计时评分、提示、存档、随机可解关卡、粒子音效和 Windows 可执行文件等功能。
三、实现思路
技术选型与项目结构
项目使用 Python 3.13 和 Pygame 2.6.1。Pygame 负责窗口、事件、鼠标输入、字体、图形绘制、动画计时和音频播放;核心规则使用普通 Python 编写,不依赖 Pygame,因此能够独立进行单元测试。
箭头与方向的表示
方向使用枚举表示,并统一提供 (dr, dc) 方向向量:
class Direction(str, Enum):
UP = "UP"
DOWN = "DOWN"
LEFT = "LEFT"
RIGHT = "RIGHT"
@property
def vector(self):
return {
Direction.UP: (-1, 0),
Direction.DOWN: (1, 0),
Direction.LEFT: (0, -1),
Direction.RIGHT: (0, 1),
}[self]
关卡模板使用不可变的 ArrowSpec 保存箭头 ID、行、列和方向。进入关卡时,程序根据模板创建可修改的运行时 Arrow 列表。这样重新开始关卡时只需再次从模板创建运行数据,不会出现“重开后少箭头”或原关卡被修改的问题。
箭头图形没有依赖 Unicode 箭头字符,而是通过 pygame.draw.polygon 绘制一个基础右箭头,再按照方向旋转坐标。这样四种箭头在不同电脑上都能保持相同形状和清晰度。
关卡的表示
每个 Level 保存以下内容:
- 关卡编号与名称;
- 棋盘行数与列数;
- 不可变的箭头定义;
- 一条经过验证的参考通关顺序;
- 标准时间、难度和所属关卡包。
加载关卡时会检查棋盘尺寸、箭头是否越界、ID 是否重复、坐标是否重复,以及参考顺序是否包含每一支箭头。
路径检测方法
路径检测是本游戏最重要的核心逻辑。程序先把当前所有箭头的位置整理成集合,再从被点击箭头的下一格开始沿方向向量逐格扫描:
def is_blocked(arrow, occupied, rows, cols):
dr, dc = arrow.direction.vector
row, col = arrow.row + dr, arrow.col + dc
while 0 <= row < rows and 0 <= col < cols:
if (row, col) in occupied:
return True
row += dr
col += dc
return False
occupied 使用集合保存坐标,单次位置查询的平均复杂度为 O(1);扫描步数最多为棋盘的一行或一列长度,因此一次阻挡判断的时间复杂度为 O(max(rows, cols))。当前最大棋盘只有 8×8,这一算法足够简单、直观且可靠。
路径检测只返回“是否受阻”,不负责动画和界面跳转。点击结算函数根据结果返回 FLY、COLLIDE 或 IGNORED,界面层再决定播放哪一种反馈。这种做法避免了规则代码与 Pygame 绘制代码互相耦合。
动画与反馈
箭头飞出与碰撞动画通过 delta time 更新,不使用阻塞式等待。成功飞出采用先快后慢的缓动,碰撞使用正弦偏移产生短促往返效果。
箭头实际是否删除由动画完成事件决定:点击成功时先把箭头状态标记为 FLYING,动画结束后才从会话列表中移除并检查是否通关。这样可以保证玩家看到完整的飞出过程。
得分与星级
最终得分由基础分、失误奖励、时间奖励和提示扣分组成:
基础分 = 成功飞出的箭头数 × 100
失误奖励 = 通关时剩余失误机会 × 150
时间奖励 = max(0, 标准时间 - 实际秒数) × 10
提示扣分 = 提示次数 × 100
无失误、未使用提示且在标准时间内通关可以获得 3 星;最多失误一次、最多使用一次提示并在 1.5 倍标准时间内完成可以获得 2 星;其他已通关情况获得 1 星。失败局为 0 星,也不会覆盖已有的最佳纪录。
提示功能
提示功能直接复用核心路径检测方法,先找出当前所有不受阻挡的箭头,再分别模拟移除这些候选箭头,计算哪一支箭头能够解锁更多后续选择。
系统优先提示“移除后新增可飞箭头数”最多的候选;如果多个候选效果相同,则按照行、列和 ID 排序,确保相同局面总是得到稳定结果。提示只负责高亮,不会替玩家执行点击。
随机可解关卡
随机关卡采用逆向构造方法:从解法的最后一步开始向前放置箭头。每次新放入的箭头都必须保证其前方不存在已经放置的箭头,然后把完整放置顺序反转,得到一条保证可执行的通关顺序。
生成完成后,程序仍会调用和固定关卡相同的 validate_level() 与 validate_solution() 进行二次检查,并计算初始可飞箭头数、阻挡依赖数量和最长依赖深度,用于区分休闲、标准和困难三档难度。
进度保存
游戏使用 JSON 保存固定关卡的通关状态、最佳得分、最佳时间、最佳星级、音效开关和当前残局。Windows 下默认保存在用户的本地应用数据目录,不会写入打包程序内部。
保存时先写入临时文件,再原子替换正式存档,减少写入中断导致文件损坏的概率。读取时会检查版本号、数据类型、箭头 ID 和数值范围;存档不存在或内容无效时会回退到默认进度,不阻止游戏启动。
四、AIGC使用过程
| 子任务 | 借助何种 AIGC 技术 | 本人提出的要求 | AI 实现或提供了什么 | 实际效果 | 人工修改与判断 |
|---|---|---|---|---|---|
| 作业需求分析与基础策划 | Codex | 阅读课程作业要求,整理一份可以拆解、分阶段实现的游戏设计开发文档 | 分析基础评分项,整理游戏规则、程序结构、界面布局、关卡数据、测试方案和开发阶段,生成《游戏策划.md》 | 将较长的作业要求转化为可逐项完成和验收的开发任务,明确了路径检测、失误机制和关卡流程 | 本人根据实际需求将三关棋盘调整为 6×6、7×7、7×7,要求第一关至少 10 支箭,并把每关失误机会统一修改为 3 次 |
| 基础游戏代码实现 | Codex | 按照策划完成可运行的 Python 与 Pygame 游戏,并保证基础评分项正确 | 将项目拆分为数据模型、规则、关卡、动画、界面和主程序等模块,实现四方向箭头、鼠标点击、飞出、碰撞、失败、通关和重开流程 | 完成了三个可通关的基础关卡,并通过路径、边界、三次失误和完整流程等自动化测试 | 本人实际运行程序并提供错误截图和界面反馈,根据运行结果继续要求修正启动方式、界面表现和交互细节 |
| 界面与原创背景设计 | Codex + OpenAI 图像生成 | 改善开始、游戏和失败界面的美观程度,生成更加可爱的原创背景,并解决文字和画面模糊问题 | 生成深蓝星空、云层和可爱箭头角色背景;重新设计深色面板、按钮、箭头配色和结果卡片;增加 Windows 高 DPI 感知 | 界面风格更加统一,文字和箭头保持清晰,背景素材与中央功能区不会互相遮挡 | 本人认为初版界面不够美观且画面模糊,要求改为可爱风格;同时要求游戏界面和结果界面使用相同背景 |
| 扩展功能策划与范围调整 | Codex | 根据作业的附加分要求,设计能够分部分实现的扩展方案,同时不能破坏已经完成的基础游戏 | 生成《游戏策划扩展.md》,规划计时评分、星级、提示、关卡选择、进度保存、随机关卡、动画音效和打包等功能 | 扩展功能具有明确的模块、数据结构、测试方法和实施顺序,能够在基础版上逐步开发 | 本人审阅方案后认为“撤销上一步”和“AI 自动求解”这个扩展功能不太适合放在游戏中,会影响游戏体验 |
五、测试结果
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 正常播放飞出动画,动画结束后箭头消失 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头碰撞返回并保留,失误机会减少 1 次 | 通过 |
| T03 | 点击边缘且朝向棋盘外的箭头 | 正常消失,不发生越界错误 | 箭头正常飞出并消失,程序未出现异常 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 正常显示通关结算,点击“下一关”后成功切换 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 第 3 次失误后进入失败界面,可以重新挑战本关 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 当前关卡重新加载,箭头全部恢复,失误机会重置为 3 | 通过 |
| T07 | 点击棋盘空白格 | 游戏状态不变,不扣失误次数 | 箭头数量和失误次数均未改变 | 通过 |
| T08 | 使用提示功能 | 高亮一支当前可飞出的箭头 | 正确显示金色提示光圈,棋盘状态不变 | 通过 |
| T09 | 保存并继续游戏 | 恢复保存时的残局和游戏数据 | 成功恢复剩余箭头、失误次数、用时和分数 | 通过 |
| T10 | 连续生成两个随机关卡 | 产生不同布局,并且两个关卡均可通关 | 两次生成的箭头位置和方向不同,且都通过可解性验证 | 通过 |
六、PSP表格
| 任务 | 预估耗时(分钟) | 实际耗时(分钟) | 差异(分钟) |
|---|---|---|---|
| 需求分析与游戏设计 | 20 | 30 | +10 |
| Python 与图形库学习 | 30 | 20 | -10 |
| 游戏界面实现 | 10 | 15 | +5 |
| 路径与碰撞逻辑实现 | 10 | 15 | +5 |
| 关卡设计 | 30 | 20 | -10 |
| AIGC 辅助开发 | 60 | 40 | -20 |
| 测试与修改 | 30 | 20 | -10 |
| README 与博客撰写 | 180 | 240 | +60 |
| 合计 | 370 | 400 | 30 |
从PSP表格中可以看出我把大部分时间都花在了README 与博客撰写部分,其他部分的时间加起来可能都没有这部分多,这得益于agent的快速发展大大加快了编程的速度,花费时间更多的往往已经不是编程,更多的是游戏的美术和策划部分。而个人博客的撰写需要自己不断润色语言,正确辨析AI生成的内容,不断修改内容和增强可读性。
心得体会
本人之前有过一段游戏开发的经历(负责编程部分后续获得中国计算机设计大赛省二等奖),刚好对此颇有感触,尤其是agent的进步对游戏开发的影响,我也是在比赛期间正式接触了codex,在此之前我依旧使用传统的LLM对话,把游戏策划案发给GPT,让GPT一步步教我实现游戏的功能:把某个C#游戏脚本挂在某个物品上、在某个地方创建一个新的场景、在新的场景创建一个物品、在物品上设计粒子特效,诸如此类.虽然能够实现游戏功能,但效率却极其低下,遇到问题也只能截图发给GPT,但是codex的出现彻底改变了我的开发进度。
Agent在繁杂的游戏开发中简直就是神一样的存在,你可以直接把你要实现的效果和需求直接发给他,等他实现以后运行一下游戏验收一下效果,并且验收极其简单,只需要玩个一两次就能知道开发效果。大大降低了开发游戏的门槛,甚至可以说一个完全没有接触过游戏开发的人学习个几天就能自己做出一个能在本地运行的2D、3D小游戏。
但是需要警惕的是:Agent的出现会在很大程度上不断堆叠游戏的屎山代码,让程序的可维护性大大降低。如果出现了bug很难溯源和修复,因为agent在你看不见的后台不停生成上百行乃至上千行代码,然后放到同一个程序中,结果就是你遇到bug只能让agent扫描整个文件夹自己找bug修bug。项目的工程性受到严重破坏,agent固然好,但你的语法基础、工程基础不能丢,不是有了agent就天下无敌,更重要的是要知道agent正在干什么,干的对不对。
以上心得体会同样适用于本次Python游戏开发
GitHub 与 README
commit截图如下:

README截图如下:


游戏中的音效、图片来源说明如下:

浙公网安备 33010602011771号