软件工程第二次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/202601SofwareEngineering/homework/16717
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102401222
GitHub 仓库 https://github.com/LeonOrLi219/arrow-game

一、项目展示:

gif展示:

屏幕录制 2026-09-21 170547

二、项目介绍

2.1 游戏规则

《一箭又一箭》是一款基于网格棋盘的简单箭头消除游戏。

游戏开始后,棋盘上会随机/预设分布多个不同方向的箭头。玩家通过鼠标点击箭头,程序检查该箭头沿自身方向前进时是否存在其他箭头。

游戏规则如下:

  1. 每个箭头占据棋盘中的一个格子;
  2. 箭头具有上、下、左、右四个方向;
  3. 玩家使用鼠标点击箭头;
  4. 程序检查箭头前进方向上的所有格子;
  5. 如果箭头与棋盘边界之间没有其他箭头,则该箭头可以飞出棋盘;
  6. 箭头飞出以后从棋盘中消失;
  7. 如果箭头前方存在其他箭头,则无法飞出;
  8. 被阻挡的箭头会产生碰撞动画,同时消耗一次失误机会;
  9. 失误次数耗尽以后,本关失败;
  10. 如果棋盘上的箭头全部消失,则本关通关;
  11. 本项目共设计 3 个基础关卡。

2.2 界面设计

本项目采用 Tkinter 实现图形界面,整体采用深色背景,使棋盘和箭头更加突出。

界面主要分为三个部分:

开始界面

负责介绍游戏名称和基本规则,并提供开始游戏按钮。

游戏界面

游戏界面是整个项目的核心,采用:

顶部信息区 + 中间棋盘区

的布局方式。

顶部实时显示游戏状态,棋盘负责显示和操作箭头。

结果界面

根据游戏状态显示:

  • 通关;
  • 最终完成;
  • 失败。

不同状态使用不同的文字颜色进行区分,使玩家可以快速判断当前游戏结果。


三、主要功能与特色

3.1 鼠标点击操作

通过 Tkinter Canvas 的鼠标事件实现箭头选择。

程序首先根据鼠标点击位置计算棋盘中的行号和列号,然后判断该位置是否存在箭头。

核心计算方式为:

c = int((event.x - BOARD_X) // CELL)
r = int((event.y - BOARD_Y) // CELL)

这样就可以把鼠标的像素坐标转换成棋盘的网格坐标。


3.2 四种箭头方向

程序使用字符表示箭头方向:

SYMBOLS = {
    "U": "↑",
    "D": "↓",
    "L": "←",
    "R": "→"
}

其中:

  • U 表示上;
  • D 表示下;
  • L 表示左;
  • R 表示右。

同时使用方向增量描述箭头每一步移动的方向:

DIRS = {
    "U": (-1, 0),
    "D": (1, 0),
    "L": (0, -1),
    "R": (0, 1)
}

例如:

U → 行号 -1,列号不变
D → 行号 +1,列号不变
L → 行号不变,列号 -1
R → 行号不变,列号 +1

3.3 箭头飞出动画

如果检测到箭头前方没有阻挡,程序会从棋盘数据中删除箭头,然后通过 after() 函数逐帧绘制箭头向棋盘外移动。

核心思想是:

self.root.after(35, lambda: frame(i + 1))

通过连续执行多个动画帧,使箭头产生“飞出棋盘”的视觉效果,而不是直接消失。


3.4 碰撞动画

如果箭头前方存在其他箭头,则不会删除该箭头。

程序会:

  1. 将箭头颜色变成红色;
  2. 向前轻微移动;
  3. 向后弹回;
  4. 再次轻微晃动;
  5. 恢复正常颜色;
  6. 失误次数减 1。

这样可以让玩家明显知道自己的点击没有成功。


四、实现思路

4.1 棋盘表示

游戏棋盘采用 6×6 网格。

可以把棋盘看作二维坐标:

(0,0) (0,1) (0,2) ... (0,5)
(1,0) (1,1) (1,2) ... (1,5)
...
(5,0) (5,1) (5,2) ... (5,5)

箭头使用字典保存:

self.arrows = {
    (行, 列): {"dir": 方向}
}

例如:

(2, 3): {"dir": "U"}

表示第 2 行、第 3 列存在一个向上的箭头。

这种表示方式的优点是可以通过:

if (r, c) in self.arrows:

快速判断某个棋盘位置是否有箭头。


4.2 关卡表示

每个关卡使用列表保存。

例如:

[
    (0, 0, "R"),
    (0, 3, "U"),
    (1, 1, "D"),
    (1, 5, "L")
]

每个元素由三个数据组成:

(行号, 列号, 方向)

程序预设了 3 个关卡:

LEVELS = [
    [...],
    [...],
    [...]
]

通过:

self.level_index

记录当前关卡编号。

通关后:

self.level_index += 1

即可进入下一关。


五、重点:路径检测方法

路径检测是本游戏最核心的程序逻辑。

由于基础版规定:

箭头只能在同一行或同一列向棋盘边界飞出。

因此不需要进行复杂的碰撞检测,只需要沿箭头方向逐格检查。


5.1 检测思路

假设当前箭头位于:

第 r 行,第 c 列

首先获取箭头方向:

direction = self.arrows[pos]["dir"]

再获得方向增量:

dr, dc = DIRS[direction]

然后从箭头相邻的下一格开始检查:

rr, cc = r + dr, c + dc

只要坐标还没有超出棋盘,就继续检查:

while 0 <= rr < ROWS and 0 <= cc < COLS:

如果发现:

(rr, cc) in self.arrows

就说明前方存在其他箭头,因此该箭头被阻挡。


5.2 核心代码

def path_is_clear(self, pos):
    r, c = pos
    direction = self.arrows[pos]["dir"]
    dr, dc = DIRS[direction]

    rr, cc = r + dr, c + dc

    while 0 <= rr < ROWS and 0 <= cc < COLS:
        if (rr, cc) in self.arrows:
            return False

        rr += dr
        cc += dc

    return True

该函数最终只返回两个结果:

True  → 前方没有阻挡,可以飞出
False → 前方存在箭头,发生碰撞

5.3 示例

例如棋盘:

→  ·  ·  ↑  ·

第一个箭头向右。

程序从第一个箭头右侧第一格开始:

· → · ↑ ·

继续检查:

· · → ↑ ·

最终发现右侧存在箭头,因此:

path_is_clear(...) == False

所以第一个箭头不能消除。

反过来,如果:

↑  ·  ·  ·  →

最后一个箭头向右,它右边已经没有棋盘格。

程序检查到棋盘边界后没有发现其他箭头,因此:

path_is_clear(...) == True

箭头可以飞出。


5.4 算法特点

本项目采用的路径检测算法非常直接,符合基础版游戏的要求。

对于一个箭头,最多检查它到棋盘边界之间的若干个格子。

由于棋盘只有 6×6,因此每次点击的检测成本非常低。

其时间复杂度可以表示为:

O(n)

其中 n 为当前箭头到棋盘边界之间需要检查的格子数量。


六、AIGC 使用过程

本项目在开发过程中使用 AI 作为辅助开发工具。AI 主要用于需求分析、代码设计、逻辑实现、测试思路整理以及项目报告整理。


子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
游戏界面实现 ChatGPT 生成 Tkinter 界面框架、Canvas 棋盘、信息栏和按钮代码 基本能够正常显示,但初始布局需要调整 手工调整棋盘大小、控件间距、字体和颜色,使界面更加合理
路径检测 ChatGPT 生成四个方向的路径检测代码,并使用方向向量统一处理上、下、左、右 基本实现路径判断,部分边界条件需要进一步检查 检查并修改边界条件,确保箭头到达棋盘边缘时能够正确判断
碰撞动画 ChatGPT 提供箭头被阻挡时的移动、晃动、变色反馈思路及代码 基本能够实现碰撞反馈,但动画速度和幅度不够合适 调整动画帧数、移动距离和 after() 延迟时间,使反馈更加明显
飞出动画 ChatGPT 提供箭头逐帧向棋盘外移动的动画实现思路 可以实现箭头飞出效果 根据实际运行效果调整动画步数和移动速度
测试与调试 ChatGPT 根据游戏功能提出测试项目,包括四方向检测、失误次数、通关、失败和重新开始等 能够帮助发现测试遗漏 实际运行程序进行人工测试,并根据运行结果修改代码

在使用 AI 生成代码后,我对代码进行了理解、检查和调整,并根据实际游戏需求进行了修改。


七、测试结果

项目完成后,对游戏的主要功能进行了测试。

测试编号 测试项目 预期结果 实际结果 是否通过
T01 启动程序 正常显示开始界面 正常显示开始界面 通过
T02 点击开始游戏 进入第 1 关 正常进入第 1 关 通过
T03 点击向上箭头 正确检测上方路径 正确检测 通过
T04 点击向下箭头 正确检测下方路径 正确检测 通过
T05 点击向左箭头 正确检测左侧路径 正确检测 通过
T06 点击向右箭头 正确检测右侧路径 正确检测 通过
T07 无阻挡箭头 箭头飞出并消失 箭头执行飞出动画并消失 通过
T08 有阻挡箭头 箭头不能消失 箭头红色晃动并保留 通过
T09 点击被阻挡箭头 失误次数 -1 失误次数正确减少 通过
T10 剩余失误为 0 显示失败界面 正常进入失败界面 通过
T11 清空棋盘 显示通关结果 正常显示通关界面 通过
T12 点击下一关 进入下一关 正常进入下一关 通过
T13 重新开始 当前关恢复初始状态 箭头和失误次数恢复 通过
T14 完成全部 3 关 显示最终完成结果 正常完成 通过
T15 点击棋盘空白位置 不产生错误操作 无异常 通过
T16 动画期间重复点击 不应造成数据错误 程序限制动画期间操作 通过

八、PSP 项目计划与实际耗时

PSP(Personal Software Process)用于记录软件开发过程中不同阶段的时间投入,从而比较计划与实际情况。

本项目的时间记录如下:

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

PSP 分析

从 PSP 数据可以看出,本项目实际耗时比预计耗时增加约 1 小时。

主要增加的时间集中在:

游戏界面实现和测试与修改两个阶段。

界面实现阶段需要处理:

  • Tkinter 控件布局;
  • Canvas 棋盘绘制;
  • 箭头显示;
  • 信息栏;
  • 按钮;
  • 不同状态界面。

测试阶段则需要反复检查:

  • 四种方向是否都能够正确判断;
  • 箭头消失后数据是否正确更新;
  • 失误次数是否正确减少;
  • 通关与失败状态是否能够正确切换;
  • 重新开始是否真正恢复初始状态。

因此实际开发时间略高于最初估计。


九、项目特色

虽然本项目只实现基础玩法,但仍具有以下特点。

9.1 规则简单

玩家只需要判断箭头前方有没有其他箭头,不需要学习复杂操作。

9.2 四方向统一处理

通过方向向量统一实现上下左右四种情况,减少了重复代码。

9.3 数据与显示分离

程序使用 self.arrows 保存实际游戏数据,再通过绘制函数将数据转换成界面显示。

这样可以降低游戏逻辑与界面的耦合程度。

9.4 有基本动画效果

项目没有直接让箭头瞬间消失,而是增加了:

  • 飞出动画;
  • 碰撞晃动;
  • 红色反馈;
  • 状态文字。

提高了游戏的操作反馈效果。

9.5 不依赖第三方库

整个游戏使用 Python 自带的 Tkinter 完成,方便在普通 Python 环境下运行和提交。


十、心得体会

通过本次《一箭又一箭》小游戏的开发,我对 Python 图形界面编程、二维网格数据结构以及简单游戏逻辑有了更加直观的认识。

首先,AIGC 对项目开发提供了比较明显的帮助。在需求分析阶段,AI 可以帮助我快速把比较长的作业要求拆分成具体功能。例如将整个游戏划分成开始界面、游戏界面、结果界面、箭头数据、路径检测、动画和关卡管理等模块,使开发思路更加清晰。

其次,在核心算法实现方面,AI 提供的方向向量思路比较实用。原本如果分别处理上、下、左、右四个方向,需要编写多套类似的判断代码,而使用:

DIRS = {
    "U": (-1, 0),
    "D": (1, 0),
    "L": (0, -1),
    "R": (0, 1)
}

以后,只需要根据方向获得行列变化量,就可以使用同一个路径检测函数处理四种情况。这让我认识到,在程序设计中,将相似的问题抽象成统一的数据结构和算法,可以明显减少重复代码。

不过,AIGC 生成的代码也不能完全不加检查地使用。实际开发过程中,需要自己理解代码逻辑,并检查变量、界面状态、动画执行顺序等问题。如果只复制 AI 给出的代码而不了解其原理,遇到运行问题时就很难定位原因。

本次项目也让我认识到,游戏程序虽然规则简单,但“能运行”和“体验完整”之间还有一定差距。例如一个箭头成功消失只是实现了基本功能,而加入飞出动画以后,玩家可以更加直观地理解“箭头离开棋盘”的过程。同样,被阻挡时增加红色晃动和文字提示,也比单纯不发生变化更加容易让玩家理解。

通过这次项目,我主要获得了以下几方面的收获:

  1. 学会了使用 Tkinter 创建基本图形化界面;
  2. 理解了 Canvas 在简单游戏开发中的作用;
  3. 掌握了二维网格坐标和方向向量的基本使用方法;
  4. 理解了如何设计简单的路径检测算法;
  5. 学会了使用状态变量管理开始、游戏、通关和失败等不同界面;
  6. 对游戏动画的基本实现方式有了初步认识;
  7. 认识到 AIGC 更适合作为程序开发中的辅助工具,而不是完全替代自己的思考和测试。

总体来说,本次项目规模不大,但完整经历了从需求分析 → 程序设计 → 编码实现 → 测试修改 → 项目总结的过程,对我理解 Python 小游戏开发和软件开发流程都有一定帮助。


十一、项目总结

本项目完成了题目要求的基础“一箭又一箭”玩法,实现了:

  • 图形化开始界面;
  • 6×6 游戏棋盘;
  • 上、下、左、右四种方向箭头;
  • 鼠标点击操作;
  • 箭头路径检测;
  • 无阻挡飞出动画;
  • 有阻挡碰撞反馈;
  • 失误次数系统;
  • 3 个可正常通关的关卡;
  • 通关界面;
  • 失败界面;
  • 下一关功能;
  • 重新开始功能。

项目最终形成了一个结构较为完整、规则清晰、可以独立运行的 Python 图形化小游戏。

posted @ 2026-09-21 18:29  LeonOrLi  阅读(18)  评论(0)    收藏  举报