第二次软工作业

软件工程第二次个人作业 —— 「一箭又一箭」小游戏

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/16717
这个作业的目标 使用 Python 和 AIGC 完成「一箭又一箭」小游戏
学号 102401330
GitHub 仓库 https://github.com/Gaoyypp/-2

一、项目展示

以下截图为我自行截取的游戏实际运行画面。

开始界面

menu

游戏进行中(含剩余箭头、剩余失误、当前关卡)

clear

碰撞反馈(箭头前顶弹回并变红)

collision

通关 / 失败界面

playing


二、项目介绍

游戏规则

「一箭又一箭」是一款点击式箭头解谜游戏:棋盘中散布着上、下、左、右四种方向的箭头,玩家需要观察箭头方向与相互阻挡关系,按合适顺序点击箭头,让所有箭头依次飞出棋盘。

  • 点击某个箭头后,程序检查其前进方向到棋盘边界之间是否有其他箭头;
  • 前方无阻挡:箭头飞出棋盘并消失;
  • 前方有阻挡:箭头被挡住不能消除,播放「前顶弹回 + 变红」的碰撞反馈,并消耗一次失误机会;
  • 消除当前关卡全部箭头即可进入下一关;
  • 失误次数耗尽则本关失败,可重新开始。

界面设计

游戏采用深色主题,包含三个主要界面:

  • 开始界面:游戏标题、规则说明与「开始游戏」按钮;
  • 游戏界面:顶部信息条(当前关卡、剩余箭头数量、剩余失误次数、重新开始按钮)+ 居中棋盘;
  • 结果界面:通关(下一关 / 返回菜单)与失败(重新开始 / 返回菜单)。

主要功能

  • 上 / 下 / 左 / 右四种方向箭头,正确的阻挡与边界判断;
  • 鼠标点击选择箭头,前方无阻挡时飞出动画、有阻挡时晃动变红;
  • 失误次数显示与耗尽判定;
  • 4 个可正常通关的关卡,通关 / 失败 / 重新开始流程完整;
  • 附带自动化测试与关卡可通关性校验。

特色

  • 逻辑与界面分离:核心路径检测、关卡求解独立成模块,可用 unittest 自动化测试;
  • 关卡自动校验:内置求解器,保证每个关卡都存在合理通关顺序,避免「关卡无法通关」;
  • 碰撞反馈明显:箭头向前一顶再弹回,同时由橙色变红。

三、实现思路

1. 箭头、方向与关卡的表示

箭头方向用一个「坐标增量」字典表示,U / D / L / R 分别对应上、下、左、右:

DIRECTIONS = {
    "U": (-1, 0),   # 行号减 1 => 向上
    "D": (1, 0),
    "L": (0, -1),
    "R": (0, 1),
}

棋盘用一个二维字符网格表示,每个格子取 U / D / L / R.(空格)。关卡数据直接写成等长字符串列表,直观易读:

Level(name="第 1 关", mistakes=5, grid=[
    "..U..",
    ".....",
    ".U.R.",
    ".....",
    "RR..D",
])

2. 路径检测(核心)

判断箭头能否飞出,本质是「沿方向逐格前进,看是否在到达边界前遇到其他箭头」:

def path_clear(self, r, c):
    d = self.get(r, c)
    dr, dc = DIRECTIONS[d]
    nr, nc = r + dr, c + dc
    while 0 <= nr < self.rows and 0 <= nc < self.cols:  # 未出界则继续
        if self.grid[nr][nc] != ".":                    # 遇到箭头 => 被阻挡
            return False
        nr += dr
        nc += dc
    return True                                          # 走到边界外 => 可飞出

边界处理的关键在于循环条件 0 <= nr < self.rows and 0 <= nc < self.cols:只要还在棋盘内就继续检查,一旦越界循环结束,返回 True,因此边缘箭头朝外时不会发生数组越界。

3. 关卡可通关性(求解器)

一个关卡「存在合理通关顺序」当且仅当每一步都存在至少一个「前方无阻挡」的箭头。这里有一个关键性质:消除一个箭头只会减少障碍、不会新增障碍,因此「当前可飞出的箭头集合」随消除过程单调递增,贪心地反复消除任意可飞出箭头,一定等价于最优解。基于此写出的求解器既能自动判断关卡是否可通关,也能直接给出通关顺序,用于校验关卡数据。

4. 程序结构

文件 职责
core.py 纯逻辑:棋盘、方向、路径检测、求解器(不依赖图形库)
game.py 会话层:关卡推进、失误次数、点击判定(同样可测)
levels.py 关卡数据
main.py pygame 界面:状态机、绘制、飞出 / 碰撞动画
test_game.py T01~T06 自动化测试

界面用状态机管理 MENU / PLAYING / LEVEL_CLEAR / ALL_CLEAR / FAILED 五种状态,飞出与碰撞分别用 FlyingArrowShakeEffect 两个动画对象实现,与逻辑层解耦。


四、AIGC 使用过程

本次开发全程借助 Claude Code 完成。以下记录 4 次有代表性的协作过程:

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
环境搭建 Claude Code 检测到 Python 3.14 下 pip install pygame 因缺少预编译 wheel、源码编译报错而失败,改用 pygame-ce(导入名仍为 pygame 一次安装成功,游戏正常导入 pygame 确认 pygame-ce 与作业要求兼容后采纳
路径检测 Claude Code 生成四方向路径检测函数,用 while 沿方向逐格检测并处理边界 基本正确,边缘朝外箭头不越界 初版用下标直接访问,我补充了「越界返回空」的兜底,并统一为 path_clear 语义
关卡设计 Claude Code 生成关卡数组,并写了一个 solve() 求解器自动校验可通关性 第 4 关首次设计出现「两个箭头面对面互指」的死锁,求解器直接定位 根据求解器定位重新设计第 4 关,直至校验通过
碰撞动画 Claude Code 实现飞出动画与「前顶弹回 + 变色」的碰撞反馈 基本可用,反馈明显 调整动画时长与位移幅度,让碰撞更自然

说明:以上记录均来自本次真实开发过程(环境报错、求解器定位死锁等都有对应日志),并非项目完成后补写。


五、测试结果

采用自动化测试(python -m unittest test_game -v),共 8 个用例全部通过:

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 箭头被消除,剩余数减 1
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 箭头仍在,mistakes_left 减 1
T03 点击边缘且朝外的箭头 正常消失,不发生越界 四个方向的边缘箭头均正常消除
T04 消除本关全部箭头 显示通关并进入下一关 逐关通关,最后一关 all_clear
T05 失误次数耗尽 显示失败并允许重新开始 mistakes_left 归 0,状态变 failed
T06 游戏进行中重新开始 布局和失误次数恢复 棋盘与失误次数均复位

此外还补充了两个关卡校验测试:所有关卡必须可通关、求解器给出的顺序每一步都必须合法。


六、心得体会

这次作业让我第一次完整地用 AIGC 工具「协同开发」一个小游戏,有几个明显的收获:

  1. AI 大幅缩短了环境与样板代码的时间。pygame 在 Python 3.14 下装不上的坑,如果自己查可能要折腾很久,AI 直接给出了改用 pygame-ce 的方案,一次解决。

  2. AI 生成的代码必须经过验证,不能直接信任。最典型的是关卡设计——AI 第一次给的第 4 关其实存在「面对面互指」的死锁,根本无法通关。我自己写的 solve() 求解器把这个问题暴露了出来,这让我意识到「可通关性」这种业务约束,光靠 AI 生成是不保险的,必须靠程序化校验兜底。

  3. 把逻辑和界面拆开,收益很大。核心的路径检测、关卡求解都是纯逻辑,可以脱离图形界面用 unittest 直接测,T01~T06 全部自动化通过。这比每次打开游戏手动点要可靠得多,也是这次项目里我最满意的一点。

  4. 对 AI 提问的质量决定产出质量。当我把需求拆成「棋盘表示、路径检测、可通关判定、动画反馈」几个清晰的子问题分别去问时,AI 的产出明显更可用;而笼统地要求「写个小游戏」反而容易得到无法运行的代码。

总的来说,AIGC 是很好的「副驾驶」,但最终的判断、验证和设计决策仍然要由自己来完成——尤其是「关卡能否通关」「边界会不会越界」这类正确性问题。

posted @ 2026-09-21 19:43  高一鹏  阅读(16)  评论(0)    收藏  举报