软工第二次作业
# 2026 秋软件工程个人作业(第二次):一箭又一箭
| 项目 | 内容 |
|---|---|
| 这个作业属于哪个课程 | 202601 软件工程班级博客 |
| 这个作业要求在哪里 | 第二次个人作业要求 |
| 这个作业的目标 | 使用 Python 和 AIGC 完成“一箭又一箭”小游戏 |
| 学号 | 102401225 |
| GitHub 仓库 | Arrow Game |
一、项目展示
本项目使用 Python 标准库 Tkinter 完成,不需要额外安装 pygame。窗口为 920 × 760,采用深蓝暗色主题,包含开始界面、游戏界面、通关界面和失败界面。
1. 开始界面

2. 游戏界面

3. 碰撞反馈

4. 通关界面

5. 失败界面

6. 整体流程演示

以上截图和 GIF 均来自本项目的实际运行记录。
二、项目介绍
2.1 游戏规则
“一箭又一箭”是一个点击式箭头解谜游戏。棋盘上有 5 × 5 个网格,箭头分为上、下、左、右四个方向。玩家点击箭头后,程序会沿着箭头所指方向检查它与棋盘边界之间是否存在其他箭头:
- 如果前方没有其他箭头,当前箭头会飞出棋盘并消失。
- 如果前方有箭头阻挡,当前箭头不会消失,会向前冲一下再弹回,并变色提示碰撞。
- 点击被阻挡的箭头会扣除 1 点生命,生命值耗尽则本关失败。
- 清空当前关卡全部箭头后即可进入下一关。
2.2 界面设计
游戏界面分为几个区域:
- 顶部状态卡片:显示当前关卡、关卡名称、得分、连击、剩余箭头和生命值。
- 中部棋盘:显示 5 × 5 圆角网格和方向箭头。
- 右侧按钮:提供“重新开始”和“提示”操作。
- 结果界面:显示本关得分、当前总分,以及下一关、重新挑战或返回开始界面的按钮。
界面采用深蓝渐变背景、圆角卡片和柔和投影。按钮有悬停高亮,箭头在鼠标移入时也会高亮边框,便于玩家确认当前可操作对象。
2.3 主要功能与特色
- 基础单格箭头玩法,方向判断仅依赖同一行或同一列。
- 箭头飞出动画、碰撞晃动与变色反馈。
- 得分与连击机制:连续正确消除会提高单次得分。
- 生命值系统:使用红心显示,生命耗尽会失败。
- 每关 2 次提示功能,会高亮一个当前可以点击的箭头。
- 共 10 个关卡,全部通过可通关性验证。
- 内置
--selftest命令,可自动检查所有关卡是否存在可通关顺序。
三、实现思路
3.1 方向如何表示
方向使用字典保存为行列增量,这样可以把方向判断统一转化为“在网格上一步一步移动”。
DIRECTION_VECTORS = {
"up": (-1, 0),
"down": (1, 0),
"left": (0, -1),
"right": (0, 1),
}
例如“向右”对应行不变、列加 1,即 (0, 1)。
3.2 箭头和关卡如何表示
每个箭头在逻辑上用 (row, col, direction) 表示。一个关卡包含关卡名称、初始生命值和一组箭头:
Level(
"第一关 · 初试身手",
3,
(
(0, 0, "right"),
(0, 3, "right"),
(0, 4, "up"),
(4, 0, "left"),
(4, 4, "down"),
),
)
界面上的每个箭头再由 ArrowSprite 保存其网格坐标、方向、Canvas 标签和绘制的图形元素。
3.3 路径检测方法
路径检测是本题的核心。程序从当前箭头的下一格开始,按照方向增量逐格移动,只要在到达棋盘边界前遇到任何一个已占用格,就认为前方有阻挡。
def position_is_blocked(row, col, direction, occupied):
dr, dc = DIRECTION_VECTORS[direction]
r, c = row + dr, col + dc
while 0 <= r < ROWS and 0 <= c < COLS:
if (r, c) in occupied:
return True
r += dr
c += dc
return False
这里 occupied 是当前棋盘上所有箭头的坐标集合。为什么从下一格开始检查,而不是从自身开始?因为箭头自身的位置不属于它前进方向上的阻挡物,如果从自身开始,会错误地认为所有箭头都撞到自己。
3.4 点击后的状态更新
点击箭头后,程序根据路径检测结果更新不同状态:
if not blocked:
self.combo += 1
points = 100 + min(self.combo - 1, 4) * 25
self.score += points
self.arrows.remove(sprite)
self.animate_fly_out(sprite, points)
else:
self.combo = 0
self.health -= 1
self.score = max(self.level_start_score, self.score - 20)
self.animate_collision(sprite, 20)
清除成功会增加连击和得分,并触发飞出动画;碰撞会重置连击、扣除生命,并触发向前冲再弹回的碰撞动画。
3.5 关卡可解性验证
本项目没有只凭感觉设计关卡,而是写了一个回溯验证函数:每一步扫描所有当前前方无阻挡的箭头,尝试移除它并递归检查剩余箭头是否能全部清除。
def level_has_solution(level):
def search(remaining):
if not remaining:
return True
for arrow in clear_arrows(remaining):
rest = tuple(item for item in remaining if item != arrow)
if search(rest):
return True
return False
return search(level.arrows)
运行 python arrow_game.py --selftest 时,程序会依次检查全部 10 个关卡是否都存在至少一种可通关顺序。
四、AIGC 使用过程
本次开发主要使用 Codex 作为 AIGC 辅助工具。下面记录几次有代表性的协作过程。
| 子任务 | 借助何种 AIGC 技术 | AIGC 提供了什么 | 我的判断与修改 |
|---|---|---|---|
| 基础框架与路径检测 | Codex | 提供了 Tkinter 单文件结构、方向字典、阻挡检测和动画思路 | 我确认 pygame 未安装后,同意使用标准库 Tkinter;运行后检查四个方向、边界和碰撞逻辑,补充关卡验证 |
| 得分、生命、连击和提示 | Codex | 根据“剩余次数换成血量”“交互性更强”的要求,加入生命、红心、得分、连击、飘分和提示功能 | 我实际运行后发现生命值文字与右侧按钮重叠,要求把生命值移到中间并调整 HUD 布局 |
| 增加关卡 | Codex | 使用“反向构造”方式生成多组可解关卡,并加入 10 关 | 我运行 --selftest 验证 10 个关卡均可通关,并根据命名和难度整理关卡顺序 |
| 界面美化 | Codex | 参考休闲游戏 UI 设计原则,加入圆角卡片、柔和投影、按钮和箭头悬停效果 | 我先后试了浅色、淡蓝色和暗色主题,最终根据实际阅读效果选择暗色系,并简化开始界面 |
| 博客素材生成 | Codex | 生成本博客草稿、截图和演示 GIF | 我补充真实运行记录,并整理成博客园可发布的结构 |
通过这些协作,我体会到 AI 更适合快速生成可运行版本和提供结构建议,而规则是否准确、界面是否重叠、关卡是否真的可通关,仍然需要自己运行和判断。
五、测试结果
5.1 自动化检查
项目提供两个可重复执行的检查:
python arrow_game.py --selftest
用于检查 10 个关卡是否全部存在至少一种可通关顺序。
python -m py_compile arrow_game.py
用于检查 Python 语法是否正确。
5.2 主要测试项
| 编号 | 测试内容 | 预期结果 | 实际结果 | 是否通过 |
|---|---|---|---|---|
| T01 | 点击前方无阻挡的箭头 | 箭头飞出并消失,剩余箭头减 1 | 箭头被移除,飞出动画正常 | 通过 |
| T02 | 点击前方有阻挡的箭头 | 箭头不消失,生命减 1 | 箭头弹回并变色,生命减 1 | 通过 |
| T03 | 四个方向的边界检测 | 上、下、左、右都能正确判断 | 四个方向路径检测正确 | 通过 |
| T04 | 清空当前关卡全部箭头 | 显示通关界面并进入下一关 | 最后一支箭头飞出后进入通关状态 | 通过 |
| T05 | 生命值耗尽 | 显示失败界面 | 第三次碰撞后进入失败状态 | 通过 |
| T06 | 重新开始 | 棋盘、生命、连击和提示次数恢复 | 当前关卡状态恢复 | 通过 |
| T07 | 得分和连击 | 正确消除加分,连击提高单次得分;碰撞重置连击 | 分数和连击变化符合设计 | 通过 |
| T08 | 提示功能 | 高亮一个当前可点击箭头,提示次数减 1 | 高亮和次数更新正常 | 通过 |
| T09 | 10 个关卡可解性 | 每个关卡都存在可通关顺序 | --selftest 全部通过 |
通过 |
| T10 | 开始、游戏、通关、失败界面 | 四个页面均能正常显示和切换 | GUI 冒烟测试通过 | 通过 |
5.3 人工试玩
我实际运行了游戏,逐个测试 10 个关卡,观察箭头的阻挡关系并按正确顺序点击。碰撞、生命扣除、连击、提示、通关、失败和重新开始流程均正常,没有出现无法通关、越界或文字重叠的问题。
六、PSP 表格
下面是示例数据,请根据自己的实际开发时间调整。
| 阶段 | 预估耗时(小时) | 实际耗时(小时) |
|---|---|---|
| 需求分析与游戏规则整理 | 0.5 | 0.2 |
| Python / Tkinter 学习 | 1.5 | 1.0 |
| 基础界面与状态切换 | 0.5 | 0.3 |
| 路径检测与碰撞逻辑 | 1.0 | 0.8 |
| 得分、生命、连击和提示 | 0.1 | 0.1 |
| 关卡设计与可解性验证 | 0.2 | 0.2 |
| 界面美化和主题调整 | 0.5 | 0.2 |
| AIGC 协作与代码修改 | 0.5 | 0.1 |
| 测试与问题修复 | 0.2 | 0.1 |
| README 与博客撰写 | 1.0 | 1.0 |
| 合计 | 6.0 | 4.0 |
七、心得体会
本次作业让我第一次完整经历了一个小游戏从需求分析、界面设计、核心逻辑、关卡设计、测试到博客总结的过程。
AI 给我的帮助主要在三个方面:
- 快速搭起一个可以运行的 Tkinter 游戏框架,减少了我从零开始熟悉图形界面的时间。
- 帮助我把“路径检测”从自然语言描述转换为逐格移动的判断逻辑,让我更容易理解方向增量、边界条件和占用集合。
- 在增加得分、生命、连击、提示和关卡时,提供了一些我原本没有考虑到的交互细节,例如飘分反馈和提示高亮。
开发过程中也出现了一些问题。比如一开始生命值放在右侧会和按钮重叠,后来通过实际运行发现问题并调整了 HUD 布局。又如关卡不能只靠随机摆放,必须先确保每一关都至少存在一种可通关顺序,否则玩家可能陷入死局。最后我加入了 level_has_solution 和 --selftest,让关卡可解性可以自动验证。
通过这次作业,我更清楚地认识到:AI 可以生成代码,但不能替我做“运行、试玩和判断”。规则是否准确、动画是否自然、界面是否清晰、关卡是否能通关,这些都需要自己实际操作后决定。我也更熟悉了 Tkinter 的事件处理、Canvas 绘图、after 动画调度,以及用回溯法验证关卡可解性的思路。
浙公网安备 33010602011771号