软件工程第二次作业-AIGC辅助下的“一箭又一箭”解谜游戏开发

镖飞哪算哪:AIGC辅助下的“一箭又一箭”解谜游戏开发

一、 作业基本信息

项目 内容
这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/2026-01SoftwareEngineeringandSoftwareEngineeringPractice/homework/16718
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 052403108
GitHub 仓库 https://github.com/wang-wang06/one-arrow-game

一、 项目展示

1.1 开始界面

img

图1:极光主题的开始界面,包含游戏规则说明和进入游戏按钮。

1.2 游戏过程

img_2

图2:游戏主界面,左侧显示得分、时间、飞镖数量与失误次数,右侧为棋盘。

1.3 通关与失败界面

img_3

img_4

图3:通关界面(显示星级评价与得分)和失败界面(失误次数耗尽)。


二、 项目介绍

2.1 游戏规则

“镖飞哪算哪”是一款点击式解谜游戏。棋盘上随机分布着上、下、左、右四个方向的飞镖。

  • 🎯玩家点击飞镖,系统会检测飞镖前进方向到棋盘边界之间是否有其他飞镖阻挡。

  • 💯若前方畅通,飞镖飞出棋盘并消失,得 100 分。

  • 🚨若前方有阻挡,飞镖无法消失,产生碰撞晃动反馈,扣除 50 分并消耗一次失误机会。

  • 🚩 撤销机制:游戏过程中,玩家每执行一次操作(成功消除或碰撞),系统都会自动记录状态。点击“撤销上一步”按钮,可以撤回上次操作,最多支持连续撤销10步。

  • 👉 重新开始:玩家可随时点击“重新开始”按钮,将当前关卡的棋盘布局和失误次数重置为初始状态,方便快速重新挑战。

  • 🏆清空全部飞镖即可通关;失误次数耗尽则游戏失败。

2.2 界面设计与功能特色

  • 视觉风格:采用了“极光(Aurora)”主题,深空靛蓝背景搭配霓虹青、星云紫、极光绿等色彩,棋盘为冰蓝玻璃质感,带有透视网格和光晕效果。
  • 核心功能:包含开始界面、关卡选择、游戏界面、通关界面和失败界面。支持进度自动解锁(最高 6 关)。
  • 拓展功能:实现了提示功能(高亮可消除的飞镖)、撤销上一步(最多可撤销 10 步)、动态计分与计时星级评价系统(根据通关时间和失误次数评定 1-3 星),以及程序化音效(通过代码合成正弦波生成飞镖射出、碰撞和胜利音效,无需外部音频文件)。
  • 动态与反馈:飞镖消除时有流畅的飞出动画、消除涟漪效果和得分飘字;发生碰撞时飞镖会左右晃动,屏幕下方会弹出“前方有阻挡!”的提示,并产生涟漪反馈。

2.3 开发环境

  • 操作系统: Windows 11
  • 编程语言:Python 3.10 及以上
  • 图形库:Pygame 2.5.x
  • 开发工具:PyCharm
  • 第三方依赖pygame(可通过 pip install pygame 安装)
  • 运行依赖资源assets/dart.png(飞镖素材)、assets/shiweiyongchunheicuti.ttf(中文字体)
  • 跨平台兼容性:项目使用相对路径加载资源,并内置了系统字体备用链,支持在 Windows、macOS 和 Linux 环境下运行。

环境配置步骤:

  1. 安装 Python 3.x(安装时建议勾选“Add Python to PATH”)。
  2. 打开终端(CMD 或 PowerShell),执行 pip install pygame 安装图形库。
  3. 确保项目根目录包含 assets 文件夹及内部资源文件。
  4. 在项目根目录执行 python main.py 即可启动游戏。

三、 实现思路

3.1 箭头、方向与关卡表示

  • 箭头表示:使用字典
{"row": r, "col": c, "direction": d, "index": index}

表示每个飞镖。direction 为字符串 "up", "down", "left", "right"

  • 方向映射:通过 get_arrow_angle 函数将方向映射为图像的旋转角度(例如 "right": 135, "up": -135),用于加载和旋转 dart.png
  • 关卡表示:关卡由元组列表 (row, col, direction) 组成。为了保证关卡一定可通关,我编写了 is_generated_level_solvable 函数,利用“逆推法”验证:每次尝试从当前剩余飞镖中找出一个“前方无阻挡”的飞镖并将其移除,如果最后能全部移除,则该关卡可解。

3.2 核心路径检测方法

路径检测是游戏最核心的逻辑。实现思路是:根据方向设定行/列的步进(dr, dc),从当前飞镖位置向该方向逐步遍历,直到走出棋盘边界。如果途中遇到任何其他飞镖,则判定为有阻挡。

# 核心路径检测代码
def is_path_clear_for_arrows(arrow_list, row, col, direction):
    dr = dc = 0
    if direction == "up": dr = -1
    elif direction == "down": dr = 1
    elif direction == "left": dc = -1
    elif direction == "right": dc = 1
    
    cr, cc = row + dr, col + dc
    # 逐步向边界遍历
    while 0 <= cr < ROWS and 0 <= cc < COLS:
        for a in arrow_list:
            if a["row"] == cr and a["col"] == cc:
                return False  # 途中遇到其他飞镖,阻挡
        cr += dr
        cc += dc
    return True  # 安全到达边界,无阻挡

3.3 关卡生成与可解性验证

为了让游戏更有趣,我没有写死关卡,而是实现了随机生成可解关卡的算法。每次开局随机分配飞镖位置和方向后,会调用 is_generated_level_solvable 进行逆向推演:不断尝试从现有飞镖中找出一个“前方无阻挡”的飞镖并将其移除,如果最终能全部移除,说明该关卡一定有解。

# 逆向推演验证关卡是否可解
def is_generated_level_solvable(level_data):
    remaining = [{"row": r, "col": c, "direction": d} for r, c, d in level_data]
    while remaining:
        removable = None
        for a in remaining:
            if is_path_clear_for_arrows(remaining, a["row"], a["col"], a["direction"]):
                removable = a
                break
        if removable is None:
            return False  # 没有可消除的,说明死局
        remaining.remove(removable)
    return True

3.4 飞出与碰撞动画(交互反馈)

作业要求“箭头成功飞出和发生碰撞时,应有基本的动画或视觉反馈”。我在 update_flying_arrows 中引入了缓动函数(Easing Function),让飞镖先加速后减速地飞出,而不是生硬地线性移动。碰撞反馈则利用 math.sin 函数生成左右震动的偏移量。

# 飞行动画缓动函数(先加速后减速)
if t < 0.5:
    eased = 4 * t * t * t
else:
    eased = 1 - pow(-2 * t + 2, 3) / 2
a["x"] = a["start_x"] + (a["target_x"] - a["start_x"]) * eased
a["y"] = a["start_y"] + (a["target_y"] - a["start_y"]) * eased

3.5 状态管理与撤销机制(工程完整性)

游戏涉及得分、失误、布局等多个状态。每次点击操作前,通过 save_undo_state 利用 copy.deepcopy 保存当前快照,存入历史栈(最多 10 步)。当玩家点击“撤销上一步”时,undo_last_move 弹出最近一次快照并恢复状态。

# 保存状态快照,用于撤销
def save_undo_state():
    undo_history.append({
        "arrows": copy.deepcopy(arrows),
        "score": score,
        "mistakes": mistakes,
        "moving_arrows": copy.deepcopy(moving_arrows),
    })
    if len(undo_history) > MAX_UNDO: # 最多保留10步
        undo_history.pop(0)

3.6 点击处理与胜负判定

handle_arrow_click 函数是玩家交互的入口。它负责坐标转换、路径判断、得分扣除、触发动画和音效,并在每次操作后检查是否清空棋盘(通关)或失误归零(失败)。

# 点击处理(核心逻辑汇总)
def handle_arrow_click(mouse_pos):
    # ... 坐标检测 ...
    if is_path_clear(r, c, d):
        save_undo_state()
        score += SCORE_PER_ARROW
        create_flying_arrow(r, c, d, clicked["index"]) # 触发飞出动画
        arrows.remove(clicked)
        if not arrows:
            finish_level() # 通关判定
    else:
        save_undo_state()
        trigger_collision(r, c) # 触发失误与碰撞反馈

3.7 星级评价与时间管理

为了增加游戏的复玩性,我设计了基于“通关时间”和“失误次数”的星级评价系统。calculate_stars 函数根据玩家的表现动态计算1至3星,这促使玩家不仅要通关,还要追求更完美的解法。配合 format_time 函数,时间可以直观地以 MM:SS 形式显示在界面上。

# 星级评价算法
def calculate_stars(elapsed_time, mistakes_used):
    if elapsed_time <= 20 and mistakes_used <= 1:
        return 3
    if elapsed_time <= 35 and mistakes_used <= 3:
        return 2
    return 1

# 时间格式化(MM:SS)
def format_time(seconds):
    seconds = max(0, int(seconds))
    return f"{seconds // 60:02d}:{seconds % 60:02d}"

四、测试结果

4.1 测试环境与方法

  • 测试环境:Windows 10/11,Python 3.x,Pygame 库。
  • 测试方法:手工测试为主,针对游戏的核心规则和边界情况进行反复试玩验证,并观察控制台是否有报错。

4.2 测试用例与结果

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 飞镖播放平滑的减速飞出动画,随后消失,得分增加 100 分,伴有射出音效 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 飞镖原地左右晃动,屏幕下方弹出“前方有阻挡!”提示,得分扣除 50 分,失误次数减 1,伴有碰撞音效 通过
T03 点击位于边缘且朝向棋盘外的箭头 箭头正常消失,不发生越界错误 箭头顺利飞出棋盘,路径检测中的 while 循环在边界处安全结束,程序无报错或卡顿 通过
T04 消除本关全部箭头 显示通关并进入下一关 触发通关界面,播放胜利音效,显示星级评价,点击“进入下一关”按钮后正常加载新关卡 通过
T05 失误次数耗尽 显示失败并允许重新开始 触发失败界面并播放失败音效,点击“重新挑战”后,当前关卡重置,失误次数恢复为初始值 通过
T06 游戏进行中重新开始 箭头布局和失误次数恢复 点击“重新开始”按钮,棋盘重新随机生成布局,失误次数重置,得分清零,撤销历史清空 通过

4.3 额外边界测试(附加验证)

除了作业要求的 6 项必测内容,我还在测试过程中额外验证了以下场景:

  • 连续撤销:连续点击“撤销上一步”按钮,最多可回退 10 步,超过 10 步后按钮变为“暂无可撤销”状态,逻辑正常。
  • 提示功能:点击“提示”按钮,正确的可消除飞镖高亮显示,提示音效播放,高亮闪烁约 2 秒后自动消失,不影响正常游戏。
  • 跨平台字体:将项目复制到不同分辨率的环境下运行,中文字体通过相对路径加载成功,未出现乱码或报错。
  • 快速连点:在极短时间内连续点击同一个飞镖,程序未出现状态冲突、越界或卡死崩溃。

五、 AIGC 使用过程

在本次开发中,我主要使用了 ChatGPTDeepSeek 辅助开发。以下是 3 次具有代表性的 AIGC 使用过程,涵盖核心算法、动画反馈和跨平台兼容性:

5.1 AIGC 使用记录表

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
路径检测 ChatGPT 生成四个方向的网格路径检测代码,使用 while 循环逐步遍历 向上判断时出现数组越界错误(IndexError 修改边界条件,确保先判断行列是否越界再访问数组,修复后正常
关卡设计 DeepSeek 建议使用随机生成关卡数组,并给出了正向生成逻辑 生成的布局存在无法通关的死局,玩家可能无解可走 手工实现“逆向推演”算法(is_generated_level_solvable),从满盘反推消除,确保关卡一定可解
碰撞动画 ChatGPT 补全了箭头碰撞后的晃动代码,使用 math.sin 配合计时器生成偏移量 基本可用,但晃动幅度和节奏偏僵硬 调整动画速度与衰减系数,修正晃动帧数,使其反馈更自然

5.2 详细协作过程

过程一:路径检测逻辑与边界处理

  • 我的要求:“请帮我用 Python 写一个函数,判断二维网格中某一行列的箭头,沿指定方向到边界是否被其他箭头阻挡。”
  • AI 实现或提供了什么:AI 快速给出了基于 while 循环的代码框架,并使用了方向步进 drdc
  • 效果如何:初始代码在向上检测时出现了数组越界错误(IndexError)。
  • 人工修改:我分析了 AI 的代码,发现边界条件 while 0 <= cr < ROWS 写成了先访问数组再判断。我修改了循环条件,确保先进行边界判断,再进行同行同列的坐标比对,修复了越界问题。

过程二:关卡生成与可解性验证

  • 我的要求:“如何随机生成一箭又一箭的关卡,并且保证每个关卡都是绝对可以通关的?”
  • AI 实现或提供了什么:AI 提供了随机排列箭头位置和方向的代码,并建议通过正向模拟来验证。
  • 效果如何:正向生成非常容易出现“死局”(所有箭头都被互相阻挡),导致玩家无法通关。
  • 人工修改:我放弃了 AI 的正向思路,自己编写了 is_generated_level_solvable 函数,利用“逆向推演”来验证——每次从现有箭头中找出一个“前方无阻挡”的移除,直到全部移除,从而确保生成的关卡百分百可解。

过程三:中文字体跨平台兼容与 UI 设计

  • 我的要求:“写一个 Pygame 加载中文字体的代码,要求 Windows 下能正常显示。”
  • AI 实现或提供了什么:AI 给出了 C:/Windows/Fonts/msyh.ttc 这种写死绝对路径的写法,并使用了大量硬编码的 Rect 坐标绘制面板。
  • 效果如何:能在本地运行,但我意识到如果助教用 Mac 或 Linux 拉取代码会直接报错或乱码。
  • 人工修改:我进行了重构,将字体文件放进 assets 文件夹,改为相对路径 os.path.join("assets", "shihu.ttf") 加载,并增加了系统字体作为备用容错。同时,我将 AI 写死的坐标进行了参数化封装(如 draw_buttondraw_text_centered_with_glow),使 UI 更具可维护性。

六、 PSP 表格

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

6.1 耗时偏差分析

  • Python 与图形库学习:实际耗时比预估多出 1 小时,主要因为 Pygame 的缓动动画和程序化音效生成需要额外的学习和调试时间。
  • 游戏界面实现:实际耗时超出较多(+1.5 小时),因为“极光主题”的渐变背景、光晕面板和霓虹按钮需要手写大量的自定义绘制代码,比预想的复杂。
  • 路径与关卡逻辑:基本符合预估,AI 在算法思路上提供了帮助,但人工修改逆向推演算法多花了一些时间。
  • 整体偏差:总耗时超出预估约 33%,主要投入在界面美化和动画调试上。这让我认识到,UI/UX 的打磨往往比核心逻辑更耗费时间。

七、心得体会

本次“一箭又一箭”小游戏开发,是我第一次深度结合 AIGC 工具完成一个完整的软件项目。在这个过程中,我既体会到了 AI 带来的效率飞跃,也踩了不少 AI 生成代码的“坑”,更在实践中加深了对软件开发的理解。

7.1 AI 带来的帮助

  • 快速构建代码框架:在项目初期,AI 很快帮我理清了 Pygame 的事件循环、坐标系统与绘制逻辑,生成了基础的游戏框架,省去了大量查文档的时间。
  • 提供算法思路:在核心的“路径检测”和“缓动动画”上,AI 提供了清晰的实现思路(如使用 drdc 步进配合 while 循环进行遍历,以及利用三次贝塞尔公式实现平滑动画),极大降低了学习成本。
  • 拓展功能边界:在实现撤销、提示和星级评价等拓展功能时,AI 提供了状态快照和数学评价模型的代码片段,让我可以把更多精力放在游戏机制的设计上,而不是纠结于语法细节。

7.2 出现的问题

  • 边界处理不严谨:AI 生成的路径检测代码在向上(up)方向判断时,出现了数组越界(IndexError)。AI 写出的 while 循环是先访问数组再判断边界,这在边界情况下非常危险。
  • 算法存在逻辑漏洞:在关卡生成上,AI 最初给出的“正向随机生成”方案极易生成死局(所有箭头互相阻挡,玩家无解可走),如果直接使用,会导致关卡实际上无法通关。
  • 代码可维护性低:AI 生成的 UI 代码存在大量硬编码的 Rect 坐标和魔法数字,导致后期调整界面和优化布局时非常费力。

7.3 个人的收获与成长

  • 学会判断与审查 AI 代码:这次经历让我明白,AI 是强大的助手,但开发者必须是代码的最终负责人。不能盲目复制粘贴 AI 生成的代码,必须逐行理解,尤其是边界条件和路径加载这类容易出错的逻辑。
  • 算法思维与工程能力的提升:为了解决 AI 的死局问题,我自研了“逆向推演”算法来验证关卡可解性;为了解决跨平台问题,我学会了使用相对路径和容错机制;为了保证项目完整性,我封装了统一的按钮绘制和文字渲染函数。
  • 理解了“以 AI 为伴”的开发模式:AI 可以迅速提供 60 分的代码,但剩下 40 分的优化、边界处理、业务逻辑和用户体验,必须由开发者来完成。会提问、会 Debug、会重构,才是 AIGC 时代开发者的核心竞争力。
  • 体会到完整软件开发的成就感:从零开始设计界面、编写逻辑、调试动画、测试边界,直到最后看到游戏流畅运行、成功上传 GitHub,这个过程让我对软件工程有了更深刻的体会,也更有信心迎接未来的开发挑战。
posted @ 2026-09-21 23:45  王凯凤  阅读(6)  评论(0)    收藏  举报