软件工程第二次作业

软件工程第二次个人作业:利用 AIGC 开发“一箭又一箭”小游戏

项目 内容
这个作业属于哪个课程 202601软件工程
这个作业要求在哪里 2026秋软件工程个人作业(第二次)
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102401434
姓名 包学丰
GitHub 仓库 OneArrowAgain

一、项目展示

1. 开始界面

开始界面展示游戏标题、规则说明和“开始游戏”按钮。

开始界面

2. 游戏界面

游戏界面显示当前关卡、剩余箭头数量、剩余失误次数和重新开始按钮。

第一关

第一关游戏界面

第三关

第三关游戏界面

3. 全关卡通关界面

完成全部三个关卡后,显示独立设计的最终通关界面,使用深蓝背景、金色奖杯和庆祝装饰,并提供重新挑战按钮。

全关卡通关界面

4. 失败界面

失误次数耗尽后显示失败结果,玩家可以重新挑战当前关卡。

失败界面

5.游戏演示动图

demo

二、项目介绍

1. 游戏规则

“一箭又一箭”是一款点击式箭头解谜游戏,使用Python和Pygame实现。

  • 棋盘中的箭头分为上、下、左、右四种方向。
  • 玩家使用鼠标左键点击箭头。
  • 如果箭头前进方向没有其他箭头阻挡,箭头沿方向飞出棋盘并消失。
  • 如果前方存在其他箭头,当前箭头不会消失,并短暂变红。
  • 每次点击被阻挡的箭头,剩余失误次数减1。
  • 清空当前关卡后显示通关结果,可以进入下一关。
  • 失误次数耗尽后显示失败,可以重新开始当前关卡。

2. 开发环境

项目 环境或工具
操作系统 Windows
开发工具 Visual Studio
编程语言 Python 3.9.13
图形库 Pygame 2.6.1
版本管理 Git、GitHub
AIGC工具 Codex

3. 主要功能

项目实现了以下基础功能:

  • 开始、游戏、通关和失败界面;
  • 四种方向的单格箭头;
  • 鼠标点击和路径阻挡判断;
  • 箭头飞出动画;
  • 碰撞变红与失误扣除;
  • 三个可以通关的关卡;
  • 重新开始、下一关和全部通关后重玩;
  • 动画期间限制其他箭头点击。

4. 界面特色与素材说明

界面优化主要围绕信息清楚、状态明确和视觉层次展开:

  • 顶部状态卡片将关卡、箭头数量和失误次数分组;
  • 圆角棋盘和悬停反馈帮助定位鼠标;
  • 绿色与红色区分成功和失败;
  • 独立的金色奖杯页面突出全部通关;
  • 渐变、阴影和装饰图形丰富界面,但不改变游戏规则。

箭头、奖杯、徽章和背景装饰均通过Pygame代码绘制,没有使用原商业游戏的美术素材或音效。

5. 安装与运行

在项目目录中执行:

python -m pip install -r requirements.txt

运行游戏:

python OneArrowAgain.py

也可以在Visual Studio中打开项目,选择主程序后运行。

三、实现思路

1. 文件结构与职责

核心项目结构如下:

OneArrowAgain/
├── OneArrowAgain.py       # 界面、动画、事件处理和游戏流程
├── game_logic.py          # 四方向路径阻挡判断
├── levels.py              # 三个正式关卡的数据
├── TESTING.md             # 手工测试记录
├── requirements.txt       # Python依赖
├── README.md              # 项目说明
└── assets/
    └── screenshot/        # 游戏截图

开发初期,我先将窗口、界面和事件处理放在一个主文件中,便于逐步运行和排错。

开始实现路径检测时,将规则判断拆分到game_logic.py;制作正式关卡时,再建立levels.py。主程序负责显示和交互,其他模块分别负责规则和数据。

2. 箭头与关卡的数据表示

每个箭头使用字典保存三个信息:

{"row": 3, "col": 4, "direction": "LEFT"}
  • row:箭头所在行;
  • col:箭头所在列;
  • direction:箭头朝向。

行列从0开始,方向使用UPDOWNLEFTRIGHT四个字符串。

关卡数据使用列表保存。以下是第一关的数据:

{
    "mistakes": 3,
    "arrows": [
        {"row": 0, "col": 1, "direction": "UP"},
        {"row": 1, "col": 4, "direction": "RIGHT"},
        {"row": 3, "col": 2, "direction": "DOWN"},
        {"row": 4, "col": 0, "direction": "LEFT"},
        {"row": 5, "col": 5, "direction": "RIGHT"},
        {"row": 3, "col": 4, "direction": "LEFT"},
    ],
}

三个关卡分别包含6、10和14个箭头,使用6×6棋盘,每关有3次失误机会。

界面显示的关卡编号从1开始,而列表索引从0开始,因此读取关卡时需要减1:

level = LEVELS[current_level - 1]

3. 鼠标点击检测

鼠标事件提供窗口坐标,需要先判断鼠标是否在棋盘内,再换算成格子的行列。

def get_clicked_arrow(mouse_pos):
    """根据鼠标位置查找被点击的箭头"""
    mouse_x, mouse_y = mouse_pos

    # 鼠标在棋盘外时直接返回
    if not (
        BOARD_X <= mouse_x < BOARD_X + BOARD_WIDTH
        and BOARD_Y <= mouse_y < BOARD_Y + BOARD_HEIGHT
    ):
        return None

    # 窗口坐标转换成棋盘行列
    col = (mouse_x - BOARD_X) // CELL_SIZE
    row = (mouse_y - BOARD_Y) // CELL_SIZE

    # 查找该格子中的箭头
    for arrow in arrows:
        if arrow["row"] == row and arrow["col"] == col:
            return arrow

    return None

例如棋盘起始横坐标为240、格子宽度为70,鼠标横坐标为415,那么:

(415 - 240) // 70 = 2

对应第2列,即从左到右的第三列。

边界判断采用左闭右开的范围,避免鼠标恰好位于棋盘右侧边界时被换算成第6列。

界面优化后,格子之间增加了视觉间距,但点击检测仍然使用原来的完整网格坐标。点击空白格或棋盘外时返回None,不消除箭头,也不扣除失误。

4. 四方向路径检测

基础版中,一个箭头只占一个格子。因此不需要复杂的物理碰撞系统,只需要检查同一行或同一列中的前方箭头。

方向 前方阻挡的判断条件
UP 同一列,其他箭头的行号更小
DOWN 同一列,其他箭头的行号更大
LEFT 同一行,其他箭头的列号更小
RIGHT 同一行,其他箭头的列号更大

完整检测函数如下:

def is_blocked(selected_arrow, all_arrows):
    """判断选中箭头的前进方向上是否存在其他箭头"""
    selected_row = selected_arrow["row"]
    selected_col = selected_arrow["col"]
    direction = selected_arrow["direction"]

    for other_arrow in all_arrows:
        # 不检查箭头自身
        if other_arrow is selected_arrow:
            continue

        other_row = other_arrow["row"]
        other_col = other_arrow["col"]

        if direction == "UP":
            if other_col == selected_col and other_row < selected_row:
                return True

        elif direction == "DOWN":
            if other_col == selected_col and other_row > selected_row:
                return True

        elif direction == "LEFT":
            if other_row == selected_row and other_col < selected_col:
                return True

        elif direction == "RIGHT":
            if other_row == selected_row and other_col > selected_col:
                return True

    return False

函数发现任意一个符合条件的箭头时,就返回True;遍历结束仍没有阻挡,则返回False。

这里检测的是整条前进路径,不只是相邻格子。即使前方隔着几个空白格,只要仍然存在其他箭头,也不能飞出。

阻挡判断只与其他箭头的位置有关,与其他箭头的朝向无关。例如一个朝右箭头前方存在朝上箭头,仍然会被阻挡。

检测函数遍历一次箭头列表,时间复杂度为O(n),其中n是当前剩余箭头数。对于本项目的小型棋盘,这种方法简单且足够使用。

5. 点击后的消除与碰撞处理

主程序获得被点击的箭头后,调用路径检测函数。以下是鼠标事件处理中的关键代码节选:

blocked = is_blocked(selected_arrow, arrows)

if blocked:
    mistakes_left = max(0, mistakes_left - 1)
    collision_arrow = selected_arrow
    collision_until = pygame.time.get_ticks() + 500

    if mistakes_left == 0:
        result_kind = "failed"
        game_state = RESULT
else:
    # 成功时先播放动画,不立即删除
    flying_arrow = selected_arrow
    flight_offset_x = 0.0
    flight_offset_y = 0.0

selected_arrow = None

有阻挡时,箭头保留,失误减1,并记录500毫秒的红色反馈时间。使用max(0, ...)保证失误次数不会变成负数。

无阻挡时,程序保存正在飞出的箭头,并将偏移量归零,交给后续动画更新函数处理。

绘制时根据当前时间选择颜色:

current_time = pygame.time.get_ticks()

if arrow is collision_arrow and current_time < collision_until:
    arrow_color = (220, 70, 70)
elif arrow is selected_arrow:
    arrow_color = (240, 140, 50)
else:
    arrow_color = (45, 95, 150)

6. 界面优化方法

界面装饰主要使用Pygame绘图,不依赖额外商业素材:

  • 渐变背景通过逐条绘制色带实现;
  • 圆角卡片使用pygame.draw.rect()border_radius实现;
  • 阴影通过在原矩形下方绘制偏移矩形实现;
  • 成功与失败徽章使用圆形和线段组合;
  • 奖杯使用圆环、矩形和多边形组合;
  • 彩纸位置随时间变化,形成飘落效果。

这些视觉效果与核心规则分开,优化绘制函数时不需要改动路径检测。

四、AIGC使用过程

本项目使用Codex辅助开发。以下记录根据真实开发对话整理,需求描述为概括。

子任务 借助何种AIGC技术 我的要求 AI实现或提供了什么 效果如何 人工操作与修改
鼠标点击 Codex 如何识别被点击的箭头并解决报错 提供坐标转换和选中反馈代码,分析缩进及变量作用域问题 录入时出现缩进错误和arrow未定义错误,修复后正常 根据AI指出的位置调整缩进,将颜色判断放回函数内部
路径检测 Codex 如何判断四方向阻挡并拆分文件 提供同行、同列坐标比较逻辑,建议创建game_logic.py 有阻挡和无阻挡情况得到不同结果 创建模块、导入函数并增加测试箭头验证
关卡与流程 Codex 如何实现三个关卡、失败和下一关 提供关卡数据、消除顺序检查和流程代码 三个关卡能够通关,整合时出现旧变量引用和缩进问题 替换旧函数、修复分支缩进,并本人试玩三个关卡
飞出动画 Codex 如何让箭头沿方向飞出 提供位移更新、动画交互限制和结束后删除方案 箭头能沿正确方向移动,飞出后更新数量和通关状态 修改绘制函数与主循环,并进行手工测试

开发中的典型问题

鼠标事件录入后曾出现:

IndentationError: expected an indented block

箭头颜色判断放到函数外后又出现:

NameError: name 'arrow' is not defined

我向Codex提供截图和实际代码,AI读取后指出了具体行号。我按照建议修改并重新运行。

拆分关卡数据后,重新开始函数仍引用已经删除的initial_arrows,也导致运行失败。修改为读取当前关卡数据后,重新开始恢复正常。

这些问题让我认识到,局部代码正确不代表整合后一定正确。复制代码后,还需要检查缩进、变量作用域和旧代码是否已经替换。

五、测试结果

1. 测试方式与范围

本项目采用本人手工操作测试。根据最终运行检查和既有测试记录,基础玩法、三个关卡及新版界面均运行正常。

详细基础测试记录见仓库中的TESTING.md

本次没有编写自动化测试,以下结论仅针对实际检查的手工测试场景,不代表覆盖了所有可能情况。

2. 基础功能测试

编号 测试操作 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出并消失,剩余数量减1,失误不变 箭头沿朝向飞出棋盘后消失,剩余数量减1,失误次数不变 通过
T02 点击前方有阻挡的箭头 箭头保留并产生反馈,失误减1 箭头短暂变红且未消失,剩余失误次数减1 通过
T03 点击边缘且朝向棋盘外的箭头 正常飞出,不发生越界错误 边缘箭头正常飞出并消失,程序没有出现越界错误 通过
T04 清除当前关卡全部箭头并点击下一关 显示通关并进入下一关 最后一个箭头飞出后显示通关,按钮正常切换关卡 通过
T05 连续碰撞直到失误耗尽 显示失败并允许重新开始 失误次数减至0后显示失败,重新开始能恢复当前关卡 通过
T06 消除一个箭头、碰撞一次后重新开始 恢复初始布局、箭头数量和失误次数 当前关卡恢复初始布局与数量,失误次数恢复为3 通过

3. 关卡试玩

关卡 初始箭头数 是否本人完整通关 实际结果
第一关 6 可以清空棋盘,显示过关结果并进入第二关
第二关 10 可以清空棋盘,显示过关结果并进入第三关
第三关 14 可以清空棋盘,并显示独立的全部通关庆祝页面

三个关卡均存在可行的消除顺序,已由本人实际试玩通关。

4. 动画与边界交互测试

测试内容 预期结果 实际结果 是否通过
动画期间点击其他箭头 不启动其他箭头操作 其他箭头不响应,当前动画正常继续 通过
动画期间重新开始 清除动画并恢复当前关卡 动画清除,棋盘和失误次数恢复 通过
点击空白格 不消除箭头、不扣失误 游戏数据没有变化 通过
点击棋盘外 不触发箭头操作,不报错 程序正常运行,游戏数据没有变化 通过
全部通关后重玩 返回第一关并恢复初始数据 恢复第一关的6个箭头和3次失误机会 通过

5. 测试总结

本次测试覆盖了基本规则、边界处理、动画交互、重新开始、关卡切换和结果页面分流。

在上述手工测试覆盖的场景中,各项功能符合预期,未发现异常。开发中曾出现的缩进、变量作用域和旧变量引用问题已修复。

后续可以增加自动化测试,系统覆盖四个方向的有阻挡、无阻挡、后方箭头及不同行列等组合。

六、Git与项目管理

我在开发初期建立GitHub仓库,随后分阶段更新程序、依赖、README、测试记录和截图,而不是最后一次性上传整个项目。

开发中遇到过远程分支比本地更新而无法推送,以及文件修改后没有创建Commit就直接推送的问题。

通过实际操作,我理解了三个步骤:

git add:选择本次要提交的文件
git commit:创建本地版本记录
git push:将提交上传到GitHub

项目通过.gitignore排除Visual Studio缓存、Python缓存和虚拟环境。

截图统一保存在assets/screenshot中。界面优化后替换同名图片,README和博客继续引用这些图片地址。

七、PSP表格

本项目实际总投入约10小时。由于开发过程中没有逐项计时,实际耗时采用开发结束后的回顾估算,阶段分配并非精确计时结果。

预计耗时列为整理阶段的参考估算,并非开发前记录的原始预计值。差异按“实际耗时-预计耗时”计算。

任务 预计耗时(小时,参考估算) 实际耗时(小时,回顾估算) 差异(小时)
需求分析与游戏设计 1.0 0.5 -0.5
Python与图形库学习 2.0 1.0 -1.0
游戏界面实现与优化 3.5 2.5 -1.0
路径与碰撞逻辑实现 2.0 1.0 -1.0
关卡设计 1.0 0.5 -0.5
AIGC辅助开发 1.5 2.0 +0.5
测试与修改 2.0 1.5 -0.5
README与博客撰写 2.5 2.0 -0.5
合计 15.5 11.0 -4.5

耗时分析

按本次回顾估算,界面实现与优化、测试修改和文档整理占用了较多时间。界面不仅需要完成初版,还进行了状态卡片、渐变背景和全部通关页面等调整。

Codex提供了实现思路、代码示例和错误定位帮助,但代码录入、运行验证、关卡试玩和Git操作仍需要本人完成。

上述差异仅用于回顾分析,不能据此认定AI准确节省了4.5小时。后续开发中,我会在开始前记录预计耗时,并在每个阶段结束后及时记录实际耗时,提高PSP数据的准确性。

八、心得体会

1. AI带来的帮助

Codex帮助我将作业拆分成较小的开发步骤,从环境配置逐步推进到界面、鼠标点击、路径检测、关卡和动画。

在不熟悉Pygame写法时,AI提供的示例可以作为学习起点。发生错误后,结合截图和实际文件分析,也能更快找到问题位置。

2. 我遇到的问题

本次开发多次出现缩进问题。我开始时更关注代码内容,没有充分注意代码属于哪个函数或条件分支。

后来我认识到,Python缩进决定执行逻辑。录入代码后,需要检查缩进、变量作用域,以及新旧代码是否已经正确衔接。

Git操作也是一个学习过程。保存文件、创建Commit和推送是不同步骤,直接推送不会自动上传尚未提交的修改。

3. 界面优化的体会

初版界面以纯色背景和文字为主,能够完成操作,但视觉层次比较简单。

优化时,我没有先增加新的玩法,而是通过卡片、图标、配色和反馈突出已有功能。普通过关与失败使用不同颜色,全部通关再使用独立的奖杯庆祝画面,使不同游戏状态更容易区分。

界面改动也提醒我:按钮位置变化后,需要重新检查点击区域;结果页面分流后,需要验证第三关失败不会被误判为全部通关。

4. 我的收获

通过本次开发,我逐步了解了Pygame主循环、鼠标事件、二维坐标转换、列表和字典,以及基本游戏状态管理。

使用AIGC并不意味着省略理解和测试。AI提供的代码进入项目后,仍然需要由我运行、验证,并对最终提交负责。

5. 后续改进方向

如果继续完善项目,我希望增加路径检测的自动化测试、更多关卡和提示功能,并进一步整理主程序结构。

相比增加大量附加功能,我更希望先保证基础规则正确、交互稳定和代码容易理解。

九、总结

本项目实现了“一箭又一箭”的基础玩法,包括四方向阻挡判断、箭头飞出、碰撞失误、三个关卡,以及通关、失败和重新开始流程。

在基础功能完成后,进一步优化了游戏信息卡片、棋盘、开始与结果界面,并为全部通关设计了独立的庆祝页面。

整个开发过程采用Codex辅助与本人本地操作、运行测试相结合的方式,源码、运行说明和截图已通过GitHub进行管理。

posted @ 2026-09-17 21:29  twilduduidis  阅读(7)  评论(0)    收藏  举报