第二次软工作业
Python + AIGC 实现“一箭又一箭”小游戏
一、作业基本信息
| 项目内容 | 内容 |
|---|---|
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering |
| 这个作业要求在哪里 | <https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/16717 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401502 |
| GitHub 仓库 | https://github.com/Hyaliiin/OneArrowAgain |
二、项目展示
本项目使用 Python 和 Pygame 实现了一个“一箭又一箭”风格的点击式箭头解谜小游戏。
游戏包含开始界面、游戏界面、通关界面和失败界面,并实现了三关游戏、失误次数、重新开始、箭头飞行动画、碰撞反馈以及提示功能。
1. 开始界面
游戏启动后首先进入开始界面,玩家点击“开始游戏”按钮后进入第一关。

2. 游戏界面
游戏主体采用 5×5 网格表示棋盘。棋盘中的箭头包括上、下、左、右四种方向。
界面上同时显示当前关卡、剩余箭头数量、剩余失误次数以及“提示”和“重新开始”按钮。

3. 通关界面
当当前关卡中的箭头全部被清除后,程序会显示“挑战成功”,并允许玩家进入下一关。

4. 失败界面
玩家点击前方存在阻挡的箭头时会消耗一次失误机会。当失误次数耗尽后,本关失败,可以点击“重新挑战”重新开始当前关卡。

三、项目介绍
3.1 游戏规则
游戏棋盘中分布着若干不同方向的箭头。玩家需要根据箭头方向以及其他箭头的位置,判断哪些箭头当前可以飞出棋盘。
当点击一个箭头时,程序会检查该箭头前进方向到棋盘边界之间是否存在其他箭头。
如果路径中没有其他箭头,则该箭头可以沿当前方向飞出棋盘并被删除;如果路径中存在其他箭头,则本次操作失败,箭头不会被删除,同时触发红色晃动反馈,并扣除一次失误机会。
每关有 3 次失误机会。当所有箭头被正确清除后进入下一关,完成第三关后显示全部通关界面。
3.2 主要功能
本项目目前实现了以下功能:
- 开始界面、游戏界面、通关界面和失败界面;
- 上、下、左、右四种方向的箭头;
- 鼠标点击箭头;
- 四方向路径检测;
- 箭头飞出棋盘动画;
- 被阻挡箭头变红并晃动;
- 剩余箭头数量统计;
- 3 次失误机会;
- 当前关卡重新开始;
- 三个可正常通关的关卡;
- 单关通关与下一关功能;
- 全部关卡完成界面;
- 提示功能,可以高亮当前一个可以安全飞出的箭头。
四、实现思路
4.1 棋盘和箭头的数据表示
我采用二维列表表示游戏棋盘,每个列表元素对应棋盘中的一个格子。
例如:
level_1 = [
[".", "↑", ".", "→", "."],
["←", ".", ".", ".", "↑"],
[".", ".", "↓", ".", "."],
["←", ".", ".", "←", "."],
[".", "↑", ".", ".", "→"]
]
其中:
↑ 表示向上箭头
↓ 表示向下箭头
← 表示向左箭头
→ 表示向右箭头
. 表示空白位置
使用二维列表后,可以直接通过:
board[row][col]
得到某一个位置上的箭头。
这种方式也使路径检测比较简单,只需要根据箭头方向遍历对应的行或者列即可。
4.2 路径检测
路径检测是本项目最核心的部分。
我编写了:
def is_path_clear(row, col):
函数,用于判断指定箭头前方是否存在其他箭头。
例如,箭头朝上时:
if direction == "↑":
for r in range(row - 1, -1, -1):
if board[r][col] != ".":
return False
程序从当前位置的上一格开始,一直检查到第 0 行。
只要发现:
board[r][col] != "."
就说明前方存在箭头,因此返回:
False
表示当前箭头不能飞出。
如果遍历结束仍然没有发现其他箭头,则最后返回:
True
向下、向左和向右的判断方法相同,只是遍历方向不同。
因此整个算法的本质是:
上、下:检查同一列
左、右:检查同一行
4.3 鼠标点击位置转换
Pygame 获取到的是鼠标在窗口中的像素坐标,因此还需要将鼠标位置转换为棋盘中的行和列。
核心代码为:
col = (mouse_x - BOARD_X) // CELL_SIZE
row = (mouse_y - BOARD_Y) // CELL_SIZE
其中 BOARD_X 和 BOARD_Y 是棋盘左上角的位置,CELL_SIZE 是每个格子的边长。
这样就可以根据鼠标点击位置得到对应的:
board[row][col]
4.4 箭头绘制
一开始我尝试直接使用 Unicode 字符:
↑ ↓ ← →
配合字体绘制。
但是实际运行时,Pygame 默认字体不能正确显示这些字符,界面中出现了方框。
因此后续没有继续依赖字体,而是使用:
pygame.draw.line()
pygame.draw.polygon()
自己绘制箭头主体和箭头尖端。
这样不仅解决了字体兼容问题,还方便后续修改箭头颜色以及实现动画。
4.5 箭头飞出动画
当箭头路径畅通时,我没有让箭头直接消失,而是生成一个正在运动的箭头对象。
其中记录:
{
"direction": direction,
"x": x,
"y": y,
"dx": dx,
"dy": dy
}
每一帧更新:
flying_arrow["x"] += flying_arrow["dx"]
flying_arrow["y"] += flying_arrow["dy"]
直到箭头完全离开窗口。
这样相比直接删除箭头,游戏反馈更加明显,也符合题目中要求的“箭头飞出棋盘”。
4.6 碰撞反馈
如果点击的箭头前方存在阻挡,则箭头不会被删除。
程序会记录当前发生碰撞的格子:
blocked_cell = (row, col)
并在短时间内把箭头颜色改成红色。
同时根据时间不断改变箭头的横向偏移:
if shake_phase == 0:
arrow_center[0] -= 6
else:
arrow_center[0] += 6
形成左右晃动的效果。
每次错误点击还会执行:
mistakes_left -= 1
当:
mistakes_left <= 0
时,游戏状态切换为失败状态。
4.7 游戏状态管理
为了控制不同界面,我使用字符串保存当前游戏状态:
START
PLAYING
LOSE
LEVEL_CLEAR
ALL_CLEAR
例如:
game_state = "START"
表示开始界面。
玩家点击开始游戏后:
game_state = "PLAYING"
清空当前关卡:
game_state = "LEVEL_CLEAR"
失误次数耗尽:
game_state = "LOSE"
完成第三关:
game_state = "ALL_CLEAR"
主循环根据不同的 game_state 绘制不同界面。
4.8 提示功能
完成基础功能后,我增加了一个提示功能。
点击“提示”按钮后,程序遍历整个棋盘:
for row in range(ROWS):
for col in range(COLS):
如果当前位置存在箭头,并且:
is_path_clear(row, col)
返回 True,则记录该箭头的位置。
程序随后将这个箭头绿色闪烁一段时间,提示玩家可以优先点击它。
这个功能复用了原有的路径检测函数,没有重新编写一套判断逻辑,也提高了代码复用性。
五、AIGC 使用过程
本项目开发过程中主要使用 ChatGPT 辅助进行需求分析、代码设计、Bug 排查以及功能完善。
以下记录均来自本次实际开发过程。
AIGC 使用过程一:游戏整体结构设计
| 内容 | 说明 |
|---|---|
| 子任务 | 游戏总体设计 |
| 使用工具 | ChatGPT |
| 我的要求 | 根据作业要求分析游戏应该包含哪些模块,并给出适合初学者的实现方案 |
| AI 提供的内容 | 建议使用 Python + Pygame,并设计开始、游戏、通关、失败等游戏状态,同时使用二维列表保存关卡 |
| 实际效果 | 帮助我快速确定了整体开发结构 |
| 人工修改 | 为降低项目复杂度,没有一开始拆分成多个 Python 文件,而是先集中在 main.py 中完成 |
通过这次 AIGC 使用,我首先确定了:
开始界面
→ 游戏界面
→ 路径检测
→ 失误机制
→ 通关/失败
→ 多关卡
这一基本开发顺序。
AIGC 使用过程二:解决 Pygame 字体报错
最初代码使用:
pygame.font.SysFont("Microsoft YaHei", 64)
但是运行后出现:
TypeError: expected str, bytes or os.PathLike object, not int
我将完整报错信息提供给 ChatGPT。
| 内容 | 说明 |
|---|---|
| 子任务 | 中文字体显示 |
| 使用工具 | ChatGPT |
| 遇到问题 | pygame.font.SysFont() 在当前 Python/Pygame 环境中报错 |
| AI 提供的方案 | 不再使用系统字体扫描,而是直接加载 Windows 字体文件 |
| 修改代码 | pygame.font.Font("C:/Windows/Fonts/msyh.ttc", 64) |
| 实际效果 | 中文正常显示,程序可以继续运行 |
| 人工修改 | 保留固定字体路径,并测试标题、按钮和说明文字均可正常显示 |
修改后使用:
font_path = "C:/Windows/Fonts/msyh.ttc"
title_font = pygame.font.Font(font_path, 64)
解决了字体初始化问题。
AIGC 使用过程三:发现并修复不可通关关卡
AI 最开始生成的第一关中存在:
→ · · ←
两个箭头相互阻挡。
实际分析后发现,这两个箭头都不能优先离开,可能导致关卡无法继续。
| 内容 | 说明 |
|---|---|
| 子任务 | 第一关设计 |
| 使用工具 | ChatGPT |
| AI 初始结果 | 生成一个包含多个箭头的 5×5 关卡 |
| 实际问题 | 部分箭头形成相互阻挡,存在无法通关风险 |
| 人工修改 | 调整箭头方向,并重新试玩验证 |
| 最终效果 | 第一关存在完整的正常通关顺序 |
这次过程让我意识到,AIGC 生成的关卡数据不能直接使用,需要结合游戏规则进行实际验证。
AIGC 使用过程四:提示功能设计
基础游戏完成后,我希望增加一个附加功能。
我向 ChatGPT 提出,希望在不重新编写复杂算法的情况下实现一个提示按钮。
AI 建议直接复用:
is_path_clear()
遍历所有箭头并寻找第一个当前可以飞出的箭头。
| 内容 | 说明 |
|---|---|
| 子任务 | 提示功能 |
| 使用工具 | ChatGPT |
| 我的要求 | 点击按钮后提示当前一个可安全消除的箭头 |
| AI 提供方案 | 遍历棋盘并复用路径检测函数 |
| 实际效果 | 点击“提示”后,可消除箭头绿色闪烁 |
| 人工修改 | 调整了提示持续时间和按钮位置,使其与重新开始按钮并列显示 |
这个功能最终作为项目的一个附加功能保留。
六、测试结果
项目完成后,我按照作业要求进行了手工测试。
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出棋盘并消失 | 箭头正常飞出并消失 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,失误次数减 1 | 箭头红色晃动,失误次数减 1 | 通过 |
| T03 | 点击位于边缘且朝向棋盘外的箭头 | 正常消失,不发生越界 | 正常飞出,无越界错误 | 通过 |
| T04 | 消除本关全部箭头 | 显示通关并进入下一关 | 正常显示挑战成功界面 | 通过 |
| T05 | 失误次数耗尽 | 显示失败并允许重新开始 | 正常进入失败界面,可重新挑战 | 通过 |
| T06 | 游戏进行中重新开始 | 箭头布局和失误次数恢复 | 当前关卡恢复初始状态 | 通过 |
| T07 | 连续完成三个关卡 | 显示全部通关界面 | 正常显示全部通关 | 通过 |
| T08 | 点击提示按钮 | 高亮一个当前可消除箭头 | 可消除箭头绿色闪烁 | 通过 |
项目中同时提供了:
TESTING.md
用于保存测试记录。
七、GitHub 开发过程
项目使用 Git 进行版本管理,并上传到 GitHub。
GitHub 地址:
https://github.com/Hyaliiin/OneArrowAgain
开发过程中进行了多次有意义的 Commit,例如:
feat: implement core arrow puzzle gameplay
docs: add game screenshots and improve README
test: add gameplay test records
feat: add playable arrow hint feature
docs: document hint feature
在 GitHub 上传过程中,我还学习了 Git 的基本操作,包括:
git init
git add .
git commit
git remote
git push
由于本机 HTTPS 连接 GitHub 时出现连接重置,后续使用 SSH Key 并通过 GitHub SSH 443 端口完成了代码上传。
八、PSP 表格
下面这个时间表可以先作为草稿。实际提交时建议根据你自己的真实耗时再微调。
| 任务 | 预估耗时(小时) | 实际耗时(小时) | 差异(小时) |
|---|---|---|---|
| 需求分析与游戏设计 | 1.0 | 1.0 | 0 |
| Python 与 Pygame 学习 | 1.5 | 1.5 | 0 |
| 游戏界面实现 | 2.0 | 2.0 | 0 |
| 路径与碰撞逻辑实现 | 2.0 | 2.5 | +0.5 |
| 关卡设计 | 1.0 | 1.0 | 0 |
| AIGC 辅助开发 | 1.0 | 1.5 | +0.5 |
| 测试与修改 | 1.5 | 2.0 | +0.5 |
| GitHub、README 与博客撰写 | 1.5 | 2.5 | +1.0 |
| 合计 | 11.5 | 14.0 | +2.5 |
实际耗时比预估时间略长,主要时间消耗在字体兼容问题、关卡检查以及 GitHub 上传环境配置上。
九、心得体会
这次作业是我第一次比较完整地使用 Python 和 Pygame 实现一个具有图形界面、状态管理和游戏逻辑的小型程序。
相比单纯完成一个算法题,这次开发过程包含了界面设计、鼠标事件处理、二维坐标转换、路径检测、动画、状态切换、测试以及 Git 版本管理等多个环节,让我对一个小型软件项目从需求到实现的过程有了更完整的认识。
AIGC 在本次开发中带来了比较明显的帮助。尤其是在一开始不熟悉 Pygame 的情况下,AI 可以快速给出程序结构和代码示例,大幅降低了查找资料和搭建基础框架的时间。在出现字体报错、关卡设计问题以及 GitHub 网络问题时,AIGC 也可以根据实际报错继续分析原因和给出修改建议。
但在实际使用过程中,我也发现 AI 给出的内容并不一定可以直接使用。例如最初生成的关卡存在相互阻挡的问题,如果不自己检查,很可能提交一个实际上无法通关的关卡。因此这次作业让我更加认识到,使用 AIGC 并不是简单地复制生成的代码,而是需要自己运行、测试、理解和修改。
另外,在实现提示功能时,我发现已经编写好的路径检测函数不仅可以用于判断玩家点击是否正确,还可以进一步复用于提示系统。这让我对代码复用和函数设计有了更直观的理解。
通过本次作业,我不仅完成了一个可以实际运行的小游戏,也初步掌握了 Pygame、Git 和 GitHub 的基本使用方法,并进一步熟悉了如何将 AIGC 作为辅助开发工具,而不是完全依赖 AIGC 完成代码。
十、项目地址
GitHub:
https://github.com/Hyaliiin/OneArrowAgain
项目主要文件包括:
main.py
README.md
TESTING.md
requirements.txt
screenshots/
浙公网安备 33010602011771号