软件工程第二次个人作业

项目 内容
📚 这个作业属于哪个课程 H202601软件工程与软件工程实践
📋 这个作业要求在哪里 2026 秋软件工程个人作业(第二次)
🎯 这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
🪪 学号 102402136
💻 GitHub 仓库 https://github.com/MieSheeeep/Arrow-Go-Poof

一、🎯 开做之前

看到这个任务的时候还算挺震惊的,因为我看着下面的描述,没太理解我们到底是要开发一个什么,只觉得还挺复杂的,一下子涉及到了玩法还原、动作交互、UI 设计等等方面。

因此去借鉴了一下原游戏。我想有这么几个需要注意的点:

  • 箭头是有长度和曲折的,而我们不需要;
  • 箭头的飞出有一个较为流畅的动画,我们可以参考;
  • 错误后生命值可以显示在上方,并且将错过的箭头标为警示的颜色,而且错误提示是先让箭头撞到已有箭头再退回来,更流畅一些;
  • 原游戏的地图不一定是方形的,可以有各种奇异的形状,而我们只有方格,反而可能更好做(也许可以当拼豆?);
  • 还有一个很重要的点,是箭头飞行的时候我们允许什么操作。原游戏是只要点击顺序没有错,就可以飞出。我们也可以参考;
  • 生成地图可能是一个需要注意的地方,不能有无解情况出现。

1.1 ✨ 关于附加功能

目前的想法是开发到:

  • 得分、计时或星级评价:得分先不做,计时功能参考原游戏,然后按照完成时间进行星级评分吧!甚至加一个 combo 功能哈哈?
  • 将程序打包为可执行文件:我想这个应该不是很难,可以尝试一下;
  • 更流畅的动画和音效:尽力而为吧,可能得多使用 GPT image 了。

其余功能后续再说,带着这些想法开始实践吧。


二、🎮 项目展示

一款像素风休闲小游戏

技术栈:Python 3.13、Pygame 2.6

2.1 🕹️ 游戏主体演示

首页点击开始游戏后即可进入第一关:金苹果,逐关解锁,共三关。

开始界面(封面)

2.1.1 🍎 第一关:金苹果

首页点击开始游戏后进入第一关。

2.1.2 🔴 第二关:精灵球

第二关游戏界面

2.1.3 🎀 第三关:HelloKitty

第三关游戏界面

⚠️ 游戏以及博客仅仅为个人课程作业使用,不允许转载此部分,如有侵犯版权,请联系我将清除。


2.2 🔍 一些细节

2.2.1 🔴 错误警示

箭头撞击变红效果

箭头设计:箭头较多,导致如果使用普通箭头画面看起来脏乱而不美观,故而提取方向核心信息,并设计新的箭头。

2.2.2 💡 HINT 下一个可消除箭头

提示

2.2.3 🤖 AI 自动求解

ai

2.2.4 🔥 Combo 连击系统

combo

得分upup

2.2.5 ⏸️ 暂停

暂停

2.2.6 ↩️ 撤回

撤回


三、📖 项目介绍

3.1 ✨ 玩法设计亮点

  • 拼豆结合原箭头飞出游戏,游戏整体更美观,完成清除有成就感;
  • 加入了 Combo 得分系统。连击数越高,单次得分越高,总分数也决定星级;
  • 像素量较大以及 Combo 才能得到高分、倒计时的限定加入,使得游戏即使在箭头只有单个格子的情况下依然具有难度,需要专注力投入才可能取得三星,同时可以享受 Combo 带来的爽感。

3.2 🎯 游戏规则

倒计时结束或者生命耗空即为失败;清除所有箭头即为成功。清除后下方拼豆图完全变亮。


四、💡 实现思路

整体数据结构只保留两张网格:

  • arrow_grid:保存 U/D/L/R、. 与 None;
  • color_grid:保存隐藏颜色。

其中:

  • None 是图案边界;
  • . 可穿过;
  • 其余箭头才会阻挡。

4.1 🧭 路径检测(核心)

📂 点击展开:路径检测核心代码
def _find_blocker(self, row: int, col: int) -> tuple[int, int] | None:
    row_delta, col_delta = DIRECTION_DELTAS[self.arrow_grid[row][col]]
    row += row_delta
    col += col_delta
    while self.in_bounds(row, col):
        cell = self.arrow_grid[row][col]
        if cell is None:
            return None          # 越过图案边界,视为无阻挡
        if cell in ARROWS:
            return row, col      # 遇到第一个箭头,即 blocker
        row += row_delta
        col += col_delta
    return None

4.2 ⚡ 即时清除

成功时 Board 立即写入 ".";飞行动画只是视觉,不会阻塞后续点击。

📂 点击展开:即时清除逻辑代码
blocker = self._find_blocker(row, col)
if blocker is not None:
    return MoveResult(False, row, col, cell, "blocked", blocker)
self.arrow_grid[row][col] = "."
return MoveResult(True, row, col, cell, "clear")

Game 只消费 Board 的结果,并生成得分和动画:

📂 点击展开:Game 层结果处理代码
result = self.board.click(row, col)
if result.reason == "clear":
    self.animations.append(FlyOutAnimation(row, col, result.direction))
    self.combo += 1
    self.score += 10 * self.combo
    if self.board.is_cleared():
        self.level_summary = LevelSummary(
            self.elapsed_seconds, self.mistakes,
            self.score, self.max_score,
            _stars_for_score(self.score, self.max_score),
        )

阻挡时保留原箭头、扣生命、清空 Combo 并创建碰撞动画。

星级按本关得分比例结算:

满连击最高分为 5 × N × (N + 1),85% / 60% 分别为 3 / 2 星。


4.3 💡 提示系统

HINT 只返回一个可安全消除的坐标,不直接修改棋盘,而AI自动求解和它同根同源,调用同一代码,只不过出发了循环和改变棋盘。

📂 点击展开:提示系统代码
elif ui.hint_rect().collidepoint(event.pos):
    ui.hint_cell = game.hint()

def hint(self) -> tuple[int, int] | None:
    if self.state is not GameState.PLAYING:
        return None
    return self.board.first_clearable_arrow()

UI 绘制前检查该格仍是箭头,避免陈旧高亮:

📂 点击展开:UI 高亮校验代码
if self.hint_cell is None or self.game.state is not GameState.PLAYING:
    return

row, col = self.hint_cell

if self.game.board.get_cell(row, col) not in {"U", "D", "L", "R"}:
    return

五、🤖 AIGC 使用过程

按照要求记录至少 3 次具有代表性的 AI 协作过程。

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
需求分析 ChatGPT 需求文档构建 很全面,也有我的想法 无
界面设计 ChatGPT image 2.5 图像设计 不错,啊哈哈 无
路径检测与状态分层 Codex 设计 Board/Game/UI 分层,生成方向检测和状态转换测试 骨架可直接复用 人工核对边界、非法点击、重复点击和生命值归零
飞出动画调试 ChatGPT/Codex 追踪 Board 清除、Game 动画列表和 UI 绘制之间的数据流 定位到箭头“突然消失”的原因 调整动画速度,把飞出距离改为越过窗口边界的方向距离
关卡设计与可通关验证 Codex 根据 .px 拼豆图案生成固定方向布局和验证顺序 三关均可通关 大尺寸 Hello Kitty 等比例压缩为 18×17,固定种子结果
界面美化与动画打磨 Claude Code 阅读代码后先跑通 183 个测试作基线,再只改 ui.py 实现渐变面板、进度条平滑、连击弹跳、爱心跳动、掉血红光、结算面板入场 全部特效落地且测试保持 183 通过 核对命中区域与测试锁定坐标不变,微调结果面板间距

💭 这次协作让我最有感的是 「先测后改」:

如果 AI 直接闷头改样式,很可能把测试锁定的布局坐标改坏;而它先跑测试再动手,收尾时又跑一遍确认,省掉了我很多排查时间。


六、✅ 测试结果

记录测试项目、预期结果、实际结果和是否通过。

6.1 🧪 自动化测试

📂 点击展开:自动化测试命令
python -m pytest -v
python -m compileall -q main.py src tests

当前结果以本机最新命令输出为准:

✅ 186 passed

自动化测试覆盖:

Board 规则、四方向路径、三关可通关顺序、固定种子布局、飞出与碰撞动画、扣心反馈、倒计时与按总分结算的星级、开始/通关/失败/暂停/重开、提示、撤销、连击与得分、自动求解、存档读档、音效波形合成、随机关卡生成、鼠标事件路由和 UI 布局。

6.2 📋 测试用例

编号 测试项目 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头从逻辑棋盘清除并飞出 Game 创建 FlyOutAnimation,测试通过 ✅ 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 CollisionAnimation 命中 blocker 并扣除生命,测试通过 ✅ 通过
T03 点击边缘且朝向棋盘外的箭头 正常消失,不发生越界 Board 边界检测通过,测试通过 ✅ 通过
T04 清除本关全部箭头 显示通关并进入下一关 三关工厂和 next_level() 测试通过 ✅ 通过
T05 失误次数耗尽 显示失败并允许重开 FAILED 状态拒绝普通点击,结果按钮重开,测试通过 ✅ 通过
T06 游戏进行中重新开始 棋盘和失误次数恢复 restart() 清空动画/错误标记并恢复关卡,测试通过 ✅ 通过
T07 三个拼豆关卡的固定布局 每次启动方向相同且存在通关顺序 固定种子复算、已冻结顺序逐步清空,测试通过 ✅ 通过
T08 飞出与碰撞动画 飞出有蓄力并越过窗口;碰撞变红、回退后保留错误标记 FlyOutAnimation 阶段与越界距离、CollisionAnimation 阶段与 error_cells 时序测试通过 ✅ 通过
T09 倒计时 仅对局计时;暂停/通关/失败后冻结;重开清零;超时失败 Game.elapsed_seconds 状态转换与超时测试通过 ✅ 通过
T10 总得分星级结算 达到最高分 85%/60% 的边界时正确获得 3/2 星,低于 60% 为 1 星 得分边界、时间/失误不直接影响星级与 StarRevealAnimation 测试通过 ✅ 通过
T11 游戏中重开与返回主菜单 操作按钮不触发棋盘点击,状态正确复位 事件路由与 return_to_menu() 测试通过 ✅ 通过
T12 暂停、继续与暂停菜单操作 暂停时计时冻结,继续后计时恢复;重开/返回菜单不触发棋盘点击 PAUSED 状态与事件路由测试覆盖 ✅ 通过

七、📊 PSP 表格

任务 预估耗时(小时) 实际耗时(小时) 差异(小时)
需求分析与游戏设计 0.6 1.5 +0.9
Python 与图形库学习 1.0 1.0 +0.0
游戏界面实现 1.0 1.0 +0.0
路径与碰撞逻辑实现 0.4 0.5 +0.1
关卡设计 1.0 1.0 +0.0
AIGC 辅助开发 4.0 5.0 +1.0
测试与修改 3.0 4.0 +1.0
README 与博客撰写 1.0 2.0 +1.0
合计 12.0 16.0 +4.0

八、💬 心得体会

AI帮我快速拆分规则、生成代码骨架和测试,但最终仍要靠自己验证。
特别是ai写了一大堆的测试,其实我都不大明白它到底在测试什么,最终的呈现效果也并不尽人意。在贴图效果上有非常多的错位错误,最终我还得自己动手进行调试。

然后还有很重要的一点,AI在撰写这项任务或者规划完成这项任务的时候,似乎太过于注重工程化了,以一个软件开发的角度去进行撰写。
在规划的时候我也让ai参与进来了,导致最后整个项目看起来,并没有真正的从一个Player的角度去看待,怎么样才是“爽”的,而更多只是像一个工程化实现。

还有一个关于最小完成集(MVP)的失败,和整个项目的缺点逻辑是一致的,它被我理解成了一个最小功能集,而不是一个最小游玩集。

posted @ 2026-09-22 15:41  MieSheeeep  阅读(15)  评论(0)    收藏  举报