软件工程第二次个人作业

项目 内容
这个作业属于哪个课程 2026 秋季软件工程
这个作业要求在哪里 2026 秋软件工程个人作业(第二次)
这个作业的目标 使用 Python 和 AIGC 完成"一箭又一箭"小游戏
学号 102401604
GitHub 仓库 https://github.com/cccccheyu/arrow-game

一、项目展示

完整演示 GIF

下面这段 GIF 录制了真实的一局游戏:主菜单 → 选关 → 进入第 2 关 → 点击被阻挡的箭头(碰撞反馈:抖动 + 红线 + 扣分)撤销恢复 → 按正确顺序消除全部箭头(飞出 + 粒子 + 连击加分)→ 三星通关结算
01-演示GIF-完整操作流程

各界面截图

开始界面 关卡选择
02-开始界面 03-关卡选择
游戏进行中 碰撞反馈
04-游戏进行中 05-碰撞反馈
提示功能 AI 自动求解
06-提示功能 07-自动求解
通关结算(三星) 失败界面
08-通关界面 09-失败界面
无尽模式 全通关结局
10-无尽模式 11-结局画面

二、项目介绍

2.1 游戏规则

  • 棋盘上分布若干带方向的箭头(上 ^、下 v、左 <、右 >)。
  • 点击一个箭头后,程序检查它前进方向上到棋盘边界之间是否还有其他箭头:
    • 无阻挡:箭头沿方向飞出棋盘并被消除,得分 +100(连击有额外加成);
    • 有阻挡:箭头不消失,播放抖动 + 变红 + 红色阻挡线反馈,消耗 1 次失误,得分 −50;
  • 清空本关全部箭头即通关,进入结算(按失误数评 1~3 星)并可进入下一关;
  • 失误次数耗尽则本关失败,可重新开始。

2.2 界面设计

采用 960×640 窗口、柔和深色渐变主题,四个方向用不同颜色区分(上=青、下=橙、左=绿、右=粉),一眼可辨。界面包含:

  • 开始界面:标题 + 开始游戏 / 无尽模式 / 音效开关 / 退出;
  • 关卡选择:6 个内置关卡卡片(显示最佳星级),未通关的关卡锁定;
  • 游戏界面:顶部 HUD(当前关卡、剩余箭头、剩余失误、得分、计时、连击),中部棋盘,底部功能按钮(重新开始 / 提示 / 撤销 / 自动求解 / 返回)与快捷键提示;
  • 结算界面:星星逐个点亮 + 得分 / 用时 / 失误统计 + 下一关 / 重玩 / 返回。

2.3 主要功能与特色

基础功能(作业要求,全部实现):图形界面、四方向箭头、鼠标点击、路径判断、飞出消除、碰撞反馈、失误次数显示、6 个可通关关卡、通关/失败界面、重新开始。

附加功能(附加分,全部实现)

附加项 实现
更多关卡 + 关卡选择 6 个内置关卡 + 选关界面 + 解锁进度
得分 / 计时 / 星级 连击加分、时间奖励、按失误评 1~3 星
提示 高亮"解锁最多后续"的安全箭头
撤销上一步 快照栈回退棋盘 / 失误 / 得分
保存进度 JSON 存档(解锁、最佳分、星级),重启恢复
随机生成可通关关卡 生成 → DFS 求解器验证 → 重试;无尽模式 5 档难度
AI 自动求解 DFS + 状态去重,一键演示通关
流畅动画 + 音效 缓动飞出 / 衰减抖动 / 粒子系统;程序化合成 7 种音效(无版权风险)
打包为可执行文件 PyInstaller 配置(build.spec / build.bat)

三、实现思路

3.1 方向与箭头的表示

方向用字符串枚举表示,delta 属性返回 (行增量, 列增量),把四个方向的差异收敛到一个元组,避免 if-else 散落:

class Direction(str, Enum):
    UP, DOWN, LEFT, RIGHT = "^", "v", "<", ">"

    @property
    def delta(self):          # (dr, dc)
        return _DELTAS[self]  # UP=(-1,0) DOWN=(1,0) LEFT=(0,-1) RIGHT=(0,1)

箭头 Arrow 持有 row / col / direction / state(IDLE / FLYING / SHAKING / GONE)与像素偏移量,供动画层读写。

3.2 关卡的表示

关卡用字符串布局描述,直观且便于手工设计与单元测试:

Level(id=2, name="四门大开", layout=(
    ">..^.",
    ".....",
    "^...v",
    ".....",
    ".v..<",
), miss_limit=3, solution=((0,3),(0,0),(2,0),(4,1),(4,4),(2,4)))

'.' 为空格,其余字符即箭头方向。build_board() 把布局解析成二维网格;solution 是一组已验证的通关顺序,供自动化测试校验关卡可解性。

3.3 路径检测(重点)

核心只有一个函数:从箭头的下一格出发,沿方向步进,只要还在棋盘内就检查是否有箭头;走出边界仍未遇到箭头即"通畅"。

def is_path_clear(board, row, col, direction) -> bool:
    dr, dc = direction.delta
    r, c = row + dr, col + dc                 # 从下一格开始,不含自身
    while 0 <= r < board.rows and 0 <= c < board.cols:
        if board.grid[r][c] is not None:      # 遇到箭头 → 被阻挡
            return False
        r += dr
        c += dc
    return True                               # 走到边界外 → 通畅

关键点:

  1. 循环条件同时约束上下界0 <= r < rows)。初版漏掉 r >= 0,导致第 0 行朝上的箭头进入负索引(Python 负索引不报错但会错误地读到最后一行),这是本次开发印象最深的一个 bug(详见 AIGC 记录 1)。
  2. 从下一格开始,避免把箭头自身当作阻挡物。
  3. direction.delta 统一四方向,同一份代码处理上下左右,天然保证四方向行为一致。

同文件还提供 first_blocker()(返回第一个阻挡物,用于画碰撞红线)、free_arrows()(当前可消除的箭头,用于提示)、path_cells()(路径格子,用于轨迹特效)。

3.4 飞出与碰撞

  • 飞出is_path_clear 为真 → 从棋盘逻辑移除,交给 FlyAnimation(ease-out-cubic 缓动)沿方向位移出界,同时 ParticleSystem 爆散 + 尾迹;
  • 碰撞:为假 → ShakeAnimation(衰减正弦波)沿垂直方向抖动并变红,first_blocker 画出红色阻挡线,失误 −1;失误归零触发失败。

3.5 整体架构

采用场景系统SceneManager 管理 Menu / LevelSelect / Game / Result / Ending 五个场景的切换,每个场景实现 handle_event / update / draw。模型层(board / path_check / solver)与渲染层(renderer)分离,模型不依赖 pygame,便于单元测试。


四、AIGC 使用过程

全程以 Qoder(Coding Agent) 为主,辅以 ChatGPT(算法讨论)与 DeepSeek(关卡交叉验证)。汇总表(作业参考格式):

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
路径检测 Qoder 生成四方向检测代码(delta 元组统一方向) 向上判断时负索引越界 0 <= r 边界条件 + 5 个边界测试
关卡设计 Qoder + DeepSeek 生成 6 关布局与通关顺序 关卡 2 顺序错、关卡 6 死锁 调整顺序 / 改箭头方向 + 写求解器自动验证
碰撞动画 Qoder 生成抖动 / 飞出 / 粒子三个动画类 抖动幅度过大、粒子消失突兀 amplitude 20→8、加 alpha 衰减
自动求解 ChatGPT + Qoder DFS + 状态去重思路与实现 初版无去重,12 箭较慢 加 visited 集合 + max_states 上限
程序化音效 Qoder 波形 + 包络合成 7 种音效 初版无包络、numpy 缺失会崩 加 attack/decay 包络 + 降级逻辑

下面展开 3 次最具代表性的记录(完整 6 次见 docs/AIGC_USAGE.md)。

记录 1:路径检测与边界越界

  • 我的要求:"实现 is_path_clear(board, row, col, direction),判断箭头前方到边界是否还有箭头;边缘箭头(如第 0 行朝上)不能越界。"
  • AI 完成:生成基于 while 循环 + direction.delta 的四方向检测代码。
  • 效果:基本可用,但 while 条件写成 r < rows 漏掉 r >= 0,朝上/朝左的边缘箭头进入负索引(不报错但逻辑错误)。
  • 人工修改:改为 0 <= r < rows and 0 <= c < cols,并补 5 个边界单元测试(T03 系列)验证。

记录 2:关卡设计与死锁修复

  • 我的要求:"设计 6 个 5x5~7x7 关卡,难度递增,每关都必须存在通关顺序,不能死锁。"
  • AI 完成:生成 6 关布局与声明的通关顺序;我另用 DeepSeek 独立交叉验证。
  • 效果:关卡 2 声明顺序有误(先点了被挡的 (2,4));关卡 6 出现 (2,6)v(4,6)^ 互挡死锁。
  • 人工修改:调整关卡 2 顺序、把关卡 6 的 (4,6)^ 改为 v;并编写 DFS 求解器 + test_levels.py,对每关自动验证"声明解能通关"且"求解器也能找到解"。修改后 6 关全部通过验证。

记录 3:碰撞动画与粒子调优

  • 我的要求:"碰撞时箭头沿垂直方向抖动并变红约 0.45s;飞出时有尾迹与爆散粒子;用缓动函数让动画自然。"
  • AI 完成:生成 ShakeAnimation(衰减正弦波)、FlyAnimation(ease-out-cubic)、ParticleSystem 与 4 种缓动函数。
  • 效果:抖动 amplitude 初版 20px 像"抽搐";粒子无 alpha 衰减、消失突兀。
  • 人工修改:amplitude 调到 8 并加 decay = 1 - t;粒子按剩余寿命线性衰减 alpha;尾迹每帧只生成 2 个小粒子保证性能。

五、测试结果

采用手工测试 + 自动化单元测试双重验证。作业要求的 6 项测试:

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 飞出动画 + 粒子尾迹,从网格移除,剩余数 −1,得分 +100
T02 点击前方有阻挡的箭头 箭头不消失,失误 −1 抖动 + 变红 + 红色阻挡线,失误 −1,得分 −50
T03 点击边缘且朝外的箭头 正常消失,不越界 上/下/左/右四边边缘箭头均正常飞出,无异常
T04 消除本关全部箭头 显示通关并进入下一关 弹出结算面板(星级/得分/用时),可进入下一关
T05 失误次数耗尽 显示失败并允许重新开始 弹出失败面板,"再试一次"可重开
T06 游戏进行中重新开始 布局与失误次数恢复 棋盘/失误/得分/计时/撤销栈全部重置

自动化单元测试:共 44 个用例全部通过(路径检测 22 + 关卡/求解器/生成器 14 + 存档 8)。另有 15 项手工集成测试、6 项边界/异常测试、性能测试(60 FPS 稳定、求解器 12 箭 ~5ms)全部通过。详见 docs/TEST_REPORT.md

运行测试:

python -m unittest discover -s tests -v

六、PSP 表格

任务 预估耗时(小时) 实际耗时(小时) 差异(小时)
需求分析与游戏设计 1.5 1.0 −0.5
Python 与图形库学习 2.0 1.0 −1.0
游戏界面实现 3.0 2.5 −0.5
路径与碰撞逻辑实现 2.0 1.5 −0.5
关卡设计 2.0 2.5 +0.5
AIGC 辅助开发 1.0 1.5 +0.5
测试与修改 2.0 2.0 0
README 与博客撰写 1.5 1.5 0
附加功能开发(选做) 3.0
合计 15.0 16.5 +1.5

差异反思:关卡设计超时(初版死锁需反复验证)、AIGC 协作超时(AI 代码需多轮审查);学习阶段因有 Pygame 基础而节省。完整分析见 docs/PSP.md


七、心得体会

AI 带来的帮助:AIGC 极大加速了"体力活"——渲染、动画、音效、存档这类模板化代码几乎一次成型;更重要的是提供了算法思路(DFS + 状态去重的求解器)和自动化测试的编写,让我能把精力放在玩法设计与验证上。

出现的问题:AI 代码并非开箱即用。路径检测的负索引越界、关卡死锁、动画参数过猛、循环导入、numpy 缺失崩溃……这些问题 AI 初版都没有发现,全靠人工审查、试玩和单元测试暴露并修复。我深刻体会到:AI 能写出"看起来对"的代码,但边界条件与死锁仍需人来把关

自己的收获

  1. 学会了用"求解器 + 单元测试"自动验证关卡可解性,把"看起来能过"变成"机器证明能过";
  2. 理解了数据驱动动画(状态 + 缓动函数)与模型/渲染分离的工程价值;
  3. 掌握了程序化音效合成(波形 + 包络),做到零素材、零版权风险;
  4. 认识到 PSP 记录的意义:附加功能最容易超时,下次应预留缓冲并先写测试(TDD)。

总体而言,这次作业让我完整走了一遍"需求 → 设计 → 编码 → 测试 → 文档"的小型软件流程,也看清了人机协作中各自的角色。

posted on 2026-09-13 17:35  lUoUl  阅读(8)  评论(0)    收藏  举报