2026 秋软件工程个人作业(第二次)
2026 秋软件工程个人作业(第二次):I like arrow
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | H202601 软件工程与软件工程实践 |
| 这个作业要求在哪里 | 2026 秋软件工程个人作业(第二次) |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 ,并且进行测试还有优化 |
| 学号 | 102401533 |
| GitHub 仓库 | ddxww/arrow-order |
前言
GitHub Release 已发布:https://github.com/ddxww/arrow-order/releases/tag/v1.0.4
本次设计游戏花费了大量的额度,有没有好心人募捐我100美元上架steam。
演示视频在b站发布了一版,并非最新的版本,应该算是1.0:
https://www.bilibili.com/video/BV1mGep6AE5i/?spm_id_from=333.1387.list.card_archive.click&vd_source=223f93c9fabb753053717ab58090373a
2.0演示视频:
https://www.bilibili.com/video/BV1gVeP6SE72/?spm_id_from=333.1387.homepage.video_card.click
游戏的画面大概如下:

一、项目展示
我把游戏命名为《一箭又一箭·箭序》。项目使用 Python 3.13 和 pygame-ce 2.5.8 开发,默认窗口大小为 960×800,也支持按窗口大小缩放。游戏可以直接运行源码,也已经打包为 Windows EXE。
界面没有沿用参考项目的浅绿色方案,而是使用纯黑背景、深灰面板、浅紫主色、暖金色提示和亮莓红色碰撞反馈。后续在原有界面上加入了黑色高级 HUD 视觉:细网格背景、实时状态芯片、棋盘负载进度条、任务选择难度刻度和通关报告层。棋盘、箭头和按钮都由 Pygame 绘制,中文字体随项目一同分发。
1. 开始界面
开始页提供“开始游戏”“关卡选择”和“无尽模式”入口,右上角可以分别开关音乐和音效。
2. 关卡选择
普通模式共有 6 个固定关卡。初始只开放第一关,通关后逐关解锁;已经解锁的关卡可以重复挑战,关卡卡片会记录最好成绩。
3. 游戏过程
游戏页上方显示当前关卡、剩余箭头和剩余失误次数,中间是棋盘,下方有提示、重新开始和返回按钮。鼠标移到箭头上时,所在格会高亮。
路径畅通时,箭头会沿自身方向飞出棋盘,动画结束后再从数据中删除。若路径上有其他箭头,当前箭头会前冲、回弹并变红,同时标出最近的阻挡者。
使用提示后,程序只高亮一个当前可以消除的箭头,不会自动替玩家完成操作。
每关有 3 次失误机会。机会只剩 1 次时,游戏会出现红色视野边缘和双拍心跳提示;机会耗尽后进入失败页面。清空棋盘则显示本关用时、剩余机会、提示使用次数和星级。
挑战失败:
无尽模式累计通关 3 次后,会解锁一次特殊 CG。这个奖励不会改变普通关卡的解锁进度和最好成绩。
完整玩法演示:哔哩哔哩视频。上面的图片均来自我的 GitHub 项目展示区,由项目程序实际渲染,不是设计稿。
二、项目介绍
1. 游戏规则
棋盘的每个格子为空,或者放置一支朝上、下、左、右的箭头。玩家用鼠标左键点击箭头后,程序从箭头前方的相邻格开始,沿其方向一直检查到棋盘边界。
- 路径上没有其他箭头:播放飞出动画,随后消除该箭头。
- 路径上存在其他箭头:箭头保留在原位,播放碰撞反馈,并扣除一次失误机会。
- 阻挡者的方向不影响判断,两个箭头之间即使隔着空格也仍然会阻挡。
- 点击空格、棋盘外、已消除的位置或使用右键,不会改变棋盘,也不会扣除次数。
- 清空本关全部箭头后通关;3 次机会用完后失败,可以重新开始本关。
动画期间只接收一个棋盘动作,防止重复点击造成一次删除多个箭头或连续扣除机会。重开、静音和关闭窗口仍然可以使用。
2. 固定关卡
作业要求至少 3 个可通关关卡,我设计了 6 个固定关卡,难度按棋盘大小、箭头数量和阻挡关系逐步增加。每一关都含有四种方向。
| 关卡 | 名称 | 棋盘大小 | 箭头数 | 三星目标时间 | 设计重点 |
|---|---|---|---|---|---|
| 1 | 初识箭序 | 5×5 | 9 | 45 秒 | 边缘飞出与简单阻挡 |
| 2 | 留意空隙 | 5×5 | 12 | 55 秒 | 隔着空格也会阻挡 |
| 3 | 交错之间 | 6×6 | 19 | 75 秒 | 横向和纵向依赖交错 |
| 4 | 逐一解锁 | 6×6 | 23 | 85 秒 | 连续解除多层阻挡 |
| 5 | 四向交织 | 7×7 | 31 | 110 秒 | 更长的路径与更高密度 |
| 6 | 最后之序 | 7×7 | 36 | 125 秒 | 综合四方向判断 |
关卡模板不会在游戏过程中被修改。开始和重开时,程序重新复制一份棋盘,因此不会出现重玩后布局缺失的问题。
3. 附加功能
完成基础玩法后,我加入了几项附加功能:
- 每次挑战有 3 次提示,提示会高亮一个当前可以飞出的箭头,但不会替玩家点击。
- 关卡逐关解锁,并将最好成绩、星级和音乐设置保存到本地。
- 通关至少获得 1 星;剩余 2 次及以上机会再得 1 星;在目标时间内完成再得 1 星。
- 音效和背景音乐可以分别关闭。背景音乐与操作音效由项目代码合成,没有使用商业游戏素材。
- 无尽模式会随机生成 5×5 至 7×7 的可解棋盘,不改变普通关卡进度。
- 游戏右下角提供奖杯成就入口,目前包含三个成就:“👍”需要完成全部六个普通关卡;“完美通关”需要六关全部达到三星;“我爱arrow”需要无尽模式累计通过三关。未完成时显示锁定状态和当前进度,解锁状态会保存到本地。
- 程序已使用 PyInstaller 打包为 Windows EXE,运行时不需要安装 Python,也不需要联网。
三、实现思路
1. 项目结构
我没有把所有内容写在一个文件里,而是把规则、关卡、计分、随机生成和界面流程分开:
game.py 游戏状态、事件循环、绘制、动画和音频
arrowgame/rules.py 路径检测、消除与求解
arrowgame/levels.py 六个固定关卡
arrowgame/scoring.py 计时、星级和最好成绩
arrowgame/endless.py 随机可解关卡生成
tests/ 规则、流程、计分和无尽模式测试
其中 rules.py 不依赖 Pygame,可以直接用普通二维数据测试。这样在界面发生变化时,核心规则仍然能单独验证。
2. 箭头、方向和关卡的表示
棋盘用二维网格表示,. 是空格,U/D/L/R 分别表示上、下、左、右。四个方向统一映射为行列增量:
DIRECTIONS = {
"U": (-1, 0),
"D": (1, 0),
"L": (0, -1),
"R": (0, 1),
}
例如第一关的关卡模板是:
(
"U.U.U",
".....",
"L.U.R",
".....",
"D.D.D",
)
关卡数据保存在不可变的字符串元组中,真正开始游戏时调用 fresh_board() 转成列表。消除箭头只修改这份运行中的副本。
3. 路径检测
路径判断的重点是从“箭头前方的下一格”开始检查,而不是从箭头本身开始;循环时先判断坐标是否仍在棋盘内,再读取格子。这样可以避免 Python 负索引把上边界错误地读成最后一行。
def first_blocker(board, row, col):
for r, c in path_cells(board, row, col):
if board[r][c] not in EMPTY:
return r, c
return None
def can_exit(board, row, col):
rows, cols = _shape(board)
if not (0 <= row < rows and 0 <= col < cols):
return False
if board[row][col] in EMPTY:
return False
return first_blocker(board, row, col) is None
path_cells() 根据方向增量逐格前进,直到离开边界。只要路径上遇到一个非空格,first_blocker() 就返回最近阻挡者;一路没有遇到箭头时,can_exit() 才返回 True。一次判断只扫描一行或一列,时间复杂度为 O(max(行数, 列数)),额外空间为路径长度;当前棋盘最大为 7×7,这部分开销很小。
4. 关卡可解性
固定关卡在加载时会检查棋盘是否为矩形、是否包含四种方向,并运行求解器。求解器找到当前能飞出的箭头,尝试删除后继续搜索;所有箭头都能删除时返回完整顺序,找不到合法动作则判定无解。
def solve_order(board):
initial = tuple(tuple(row) for row in board)
@lru_cache(maxsize=None)
def search(state):
if count_arrows(state) == 0:
return ()
for row, col in available_arrows(state):
rest = search(remove_arrow(state, row, col))
if rest is not None:
return ((row, col),) + rest
return None
return search(initial)
这里使用带缓存的深度优先搜索,既能给出可解结论,也能保存一条合法通关顺序。游戏页新增“自动求解”按钮,点击后会按这条合法顺序逐支播放飞出动画;运行时按钮会显示“停止自动求解”,再次点击会取消后续解题步骤,让当前箭头完成后恢复手动操作。提示高亮状态下也可以直接启动,启动时只取消高亮,不退还已经使用的提示次数。自动求解期间棋盘点击会被忽略,但停止、重开、返回和静音仍然有效。它既方便演示,也方便检查动画和通关结算流程。
无尽模式采用反向插入方式生成棋盘:每次只把新箭头放在当时可以飞出的位置,因此反向删除时一定存在合法顺序。程序还会检查箭头数量、四种方向和依赖深度;随机尝试没有在限定次数内得到合适布局时,会对已验证的固定关卡做旋转或镜像作为保底。
5. 动画和状态切换
程序区分首页、选关、游戏、飞出动画、碰撞反馈、单关通关、失败、全部完成、无尽结算等状态。同一时刻只处理一个棋盘动作。
飞出动画约 0.18 秒,动画结束时才真正删除格子。碰撞反馈约 0.14 秒,先扣除一次机会,再播放前冲回弹和变色;最后一次碰撞反馈结束后才进入失败页。缩短反馈时长后,连续点击的等待感更低,同时仍保留清楚的动画反馈。所有动画都按经过时间推进,没有使用 sleep() 阻塞主循环,所以窗口在动画中仍能关闭或重开。
重开会清空旧动画并重新复制关卡模板。结果页出现后,按钮区域会重新生成,底层棋盘不再接收点击。
四、AIGC 使用过程
本项目主要使用 Codex 协助需求分析、编码、测试、打包和文档整理。下面的记录来自实际开发会话,没有把项目完成后的总结倒写成虚构过程。
下面选取 3 次具有代表性的过程,分别对应星级与胜利反馈、无尽模式与特殊 CG、最后一次机会反馈。每次都按“我的要求—AI 完成—实际效果—我的修改”记录,并附上开发过程截图。本节的 3 次代表性过程和对应截图另整理在 AIGC 使用过程记录,包括星级与胜利反馈、无尽模式与特殊 CG、最后一次机会的心跳和红色边缘效果。
| 次数 | 子任务 | 我提出的要求 | AI 完成的内容 | 实际效果 | 我是否修改及修改内容 |
|---|---|---|---|---|---|
| 1 | 需求分析 | 阅读课程作业和参考博客,先复述要求,再给出完整方案,每个阶段留确认节点 | 整理了规则、界面、六关、测试、打包和博客材料的计划,并建立 PRD | 方案覆盖了作业的基础要求,也列出了提示、存档等扩展 | 有。我确认采用 Python + Pygame、6 个固定关卡、每关 3 次机会和 3 次提示 |
| 2 | 界面设计 | 界面要清楚,但配色不能和参考博客一样;完整版完成后再将背景改为黑色 | 先生成首页、选关、游戏、提示、碰撞和结果页预览,再统一调整深色主题 | 第一版字体偏细,部分状态数字也不一致;黑底初版还需要重新检查文字对比 | 有。我确定纯黑背景、深灰面板和浅色文字,并保留四方向彩色箭头 |
| 3 | 规则与关卡 | 按已确认方案完成四方向判断、六关、动画、提示和重开 | 将纯规则放入独立模块,为六关生成合法解序,并接入完整游戏流程 | 四方向、远距离阻挡、边缘和重开测试通过;六关均可自动清空 | 有。我要求先给出可玩的 EXE,再由我本人上机检查手感;自动解序没有被当作本人试玩 |
| 4 | 扩展与反馈 | 增加星级、计时、音乐、最后一次机会反馈和无尽模式 | 增加三星规则、本地成绩、程序合成音乐与心跳、随机可解关卡及相应测试 | 新增功能测试通过;音频设备不可用时也能静音运行 | 有。我提供反馈图片并决定展示时机;没有把原商业游戏的代码、关卡或音频放入项目 |
| 5 | 测试与交付 | 打包 Windows 程序、上传 GitHub,并按作业结构写博客草稿 | 生成 EXE、ZIP、README、测试报告、截图和 Markdown 草稿;创建并推送公开仓库 | 源码运行、资源加载和 33 项当前自动检查通过 | 有。我保留最终发布和课程提交操作,博客中的学号、本人试玩和心得由我最后确认 |
代表性过程一:星级评价和胜利反馈
我提出了按剩余机会和通关时间评定三颗星的要求,并要求三星时显示指定图片、播放胜利音效。AI 完成计时、星级计算、最好成绩保存和结算反馈后,我又要求把得星条件写到界面中,并让图片和声音过渡更自然。
代表性过程二:无尽模式
我要求随机生成第 1~6 关难度区间内的可解棋盘,无尽模式不评价星级,累计通关三次后显示特殊 CG。AI 增加了随机生成、通关计数,允许失败后重试原棋盘。
代表性过程三:最后一次机会反馈
我要求剩余一次机会时显示指定图片,随后渐隐,并加入心跳和红色视野边缘。第一版反馈出现得太突然,心跳也不够明显,因此我又要求补充淡入淡出、增强低频,并让红色边缘随心跳轻微变化,同时保证棋盘仍然清晰。
这几轮协作中,AI 写了主要代码,我负责给出规则边界、选择功能、查看界面效果并决定是否接受结果。课程要求提交者理解关键代码,因此我还需要能说明方向增量、路径检测、关卡副本、动画状态和存档分别解决了什么问题。
最后一次机会反馈的图片:
五、测试结果
测试环境为 Windows、CPython 3.13.5、pygame-ce 2.5.8 和 SDL 2.32.10。2026 年 9 月 15 日重新运行当前源码:unittest 测试 26 项全部通过,另直接运行 7 项纯规则测试也全部通过,共 33 项。
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 动画结束后只删除一次,箭头数量减一 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 返回最近阻挡者,箭头保留并播放碰撞反馈,机会减一 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 正常消失,不发生越界错误 | 上、下、左、右四条边均能正确处理 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 前五关进入单关结算,第六关进入全部完成页 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 第三次碰撞反馈结束后进入失败页,重开恢复本关 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 布局、3 次机会、3 次提示和动画均恢复 | 通过 |
| T07 | 检查四个方向的相邻及远距离阻挡 | 路径上的任意箭头都会阻挡,身后及其他行列不影响判断 | 四个方向均找到最近阻挡者,隔着空格也没有漏判或误判 | 通过 |
| T08 | 点击空格、棋盘外或在动画期间重复点击 | 无效输入不扣次数,动画期间只执行第一次有效操作 | 棋盘和机会保持正确,没有重复删除或连续扣次 | 通过 |
| T09 | 使用提示、通关解锁并重新读取存档 | 提示只扣一次,下一关解锁,最好成绩和声音设置能够恢复 | 提示高亮可消除箭头;重新创建游戏对象后进度和设置读取正确 | 通过 |
| T10 | 连续生成并求解无尽模式棋盘 | 棋盘含四种方向、数量符合难度范围,而且始终存在完整解序 | 随机关卡与保底布局均通过可解性检查,失败重试不改变原棋盘 | 通过 |
除作业指定的 T01 至 T06 外,我还检查了这些情况:
| 范围 | 实际检查结果 |
|---|---|
| 四方向与隔空阻挡 | 相邻和远距离阻挡均正确;身后及其他行列不会误判 |
| 六关可解性 | 六关均包含四个方向,自动求解得到完整合法顺序并清空棋盘 |
| 输入与状态 | 空格、越界位置和动画期间重复点击不会造成额外删除或扣次 |
| 计时与星级 | 暂停画面不计入用时,结算后计时冻结,星级边界与最好成绩更新正确 |
| 存档兼容 | 旧存档可以读取,不可信字段会被忽略,音效和音乐设置分别保存 |
| 音频降级 | 没有音频设备时游戏仍可运行;音乐、操作音效和心跳互不占用通道 |
| 无尽模式 | 随机棋盘保持可解;失败重试保持原棋盘;通关次数不改变普通关卡进度 |
| 资源缺失 | 个别反馈图片缺失时回退到普通结果页,不影响核心玩法 |
自动测试只能说明程序在设定输入下符合预期,不能代替作业要求的本人试玩。本人上机试玩记录将在发布前据实补入:
| 关卡 | 试玩日期 | 是否通关 | 操作感受与修改 |
|---|---|---|---|
| 1 初识箭序 | 2026/9/16 | 是 | 爽 |
| 2 留意空隙 | 2026/9/16 | 是 | 尚可 |
| 3 交错之间 | 2026/9/16 | 是 | 还行 |
| 4 逐一解锁 | 2026/9/16 | 是 | 还不错 |
| 5 四向交织 | 2026/9/16 | 是 | 酣畅淋漓! |
| 6 最后之序 | 2026/9/16 | 是 | 还不错 |
本人通过游戏的截图:
游戏更新与问题修复
完成初版后,我继续根据实际操作反馈做了两次更新。第一次发现:使用提示后,如果手动点击了提示箭头,再点击“自动求解”,程序仍可能按照旧的初始解序访问已经清空的格子,导致游戏退出。修复后,自动求解启动时会读取当前棋盘并重新生成合法解序;队列遇到已经消除的坐标时会跳过,失效时也会重新计算,不再抛出异常。
第二次反馈是点击响应偏慢。原先飞出动画约 0.32 秒、碰撞反馈约 0.26 秒,连续操作时需要等待较长时间。我将它们分别缩短为约 0.18 秒和 0.14 秒,同时保留动画期间一次只处理一个动作的规则,避免快速连点造成重复消除。修改后重新完成响应时长测试、规则测试、六关可解性检查,并重新打包 Windows 程序。
这两次更新都先由我提出具体的操作问题,再由 AI 定位代码和修改实现,最后由我查看截图、运行程序并确认修复效果。截图保留了问题描述、修改结果和测试信息,作为本次游戏迭代的记录。
成就系统更新
在后续版本中,我增加了三个可以查看和保存进度的成就:
- 👍:完成全部六个普通关卡。
- 完美通关:六个普通关卡全部达到三星,图标为金色奖杯。
- 我爱arrow:无尽模式累计通过三关。
游戏右下角的奖杯按钮可以打开成就面板。未解锁项目会显示锁定状态和当前进度,达到条件后会变为金色的“已解锁”状态。普通关卡成绩和无尽模式累计次数都会写入本地存档,重新启动游戏后不会丢失。
六、PSP 表格
预计耗时在实施方案确定时填写。实际耗时根据本次开发会话、Git 提交时间和测试记录整理。
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.00 | 1.60 | +0.60 |
| Python 与图形库学习 | 1.00 | 1.00 | 0.00 |
| 游戏界面实现 | 2.00 | 2.60 | +0.60 |
| 路径与碰撞逻辑实现 | 2.00 | 2.20 | +0.20 |
| 关卡设计 | 1.25 | 1.40 | +0.15 |
| AIGC 辅助开发 | 1.75 | 1.70 | -0.05 |
| 测试与修改 | 2.75 | 2.50 | -0.25 |
| README 与博客撰写 | 1.25 | 1.50 | +0.25 |
| 合计 | 13.00 | 14.50 | +1.50 |
这里的 AIGC 辅助开发只统计专门整理提示、检查输出和协调任务的时间。AI 完成界面或规则时所用的时间已经分别计入对应阶段,没有再次相加。
七、心得体会
作业差不多花了一天来测试和优化,虽然感觉还有很多可以优化的比如游戏商城或者道具系统,更重要的是充值系统!,但是额度不允许我继续发挥创造力。这次作业里,AIGC 最直接的帮助是把需求、实现和测试连在了一起。我一开始给出的不只是“做一个箭头游戏”,还确认了每关次数、动画期间如何处理点击、重开要恢复什么、最后一关结束后,还有无尽模式。规则写清楚以后,后面的代码和测试才有统一标准。开发过程中也出现过需要继续检查的问题(也找朋友测试了一下,帮忙提提建议)。第一版预览的中文字体太细,棋盘附近的间距和状态数字不够统一;我提出配色不能照着参考博客做,完整版完成后又把背景改成纯黑。为保证黑底下仍然清楚,卡片、棋盘、按钮、提示和碰撞状态也同步调整成深色体系。测试第一次在受限临时目录中运行还遇到了权限错误。换到正常 Windows 临时目录重新执行后,26 项 unittest 才完整通过;纯规则测试又单独运行了 7 项。还有在运行游戏时,点击提示后再点击自动解题会退出游戏等。这个过程提醒我,命令报错不等于代码一定有错,应该先区分运行环境问题和程序断言失败。我对核心实现的理解是:方向映射决定箭头每一步的行列变化,路径检测只查看箭头前方同一行或同一列;关卡模板必须复制后再修改;动画状态负责保证一次点击只产生一次结果;存档只保存已解锁关卡和成绩,不保存未完成棋盘。求解器能验证关卡存在合法顺序,但不能代替我亲自玩一遍,因为操作手感、文字是否容易读、关卡是否太难都不是“可解”两个字能说明的。游戏差不多做完以后,就自己试玩了所有关卡,毕竟大部分都是ai帮忙做的,对大部分的知识学习也并没有掌握很多,但是更新游戏以及添加图片或是设计ui界面确实挺好玩的,这也算第一次开发游戏,对游戏开发也有了自己的见解。
commit如下:
做完后真是燃尽了:
感谢您的观看!奖励你一只可爱的猫咪🐱:
To be continued...




浙公网安备 33010602011771号