2026秋软件工程个人作业(第二次)

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

1.项目展示:

开始界面

image

游戏过程

屏幕录制 2026-09-18 152217

通关与失败界面

image
image

2.项目介绍

游戏规则

棋盘是 3×3 的格子,每格一个箭头,朝上、下、左、右四个方向之一。

  • 点击箭头,如果它指向的方向上没有其他箭头挡路,它就飞出去消失。
  • 如果前方有箭头挡着,它就晃动一下,失误 +1
  • 失误满 3 次,游戏失败。
  • 清空棋盘上所有箭头,就过关。通过 3 关,游戏胜利。

界面设计

  • 深色主题:深蓝背景、深灰格子、浅灰网格线,箭头是蓝色加白色描边,醒目护眼。
  • 三个界面:开始界面、游戏界面、结束界面(失败或通关)。
  • HUD 信息:左上角显示计时,中上显示关卡,右上显示失误次数,左下提示按 F1 重开。

主要功能

  • 3 个关卡:设计时保证每关都有解,不会卡死。
  • F1 重开本关:游戏中随时按 F1,当前关重置,失误清零,正在飞的箭头立即消失,但不回主菜单、不换关
  • 通关动画:清空箭头后先显示绿色大字 "Level Clear!",停 1 秒再进下一关。
  • 计时器:实时显示用时,结束时冻结,方便挑战更短时间。
  • 点击反馈:成功飞出并淡出,被阻挡则晃动。
  • 任意键重开:失败或通关后,按任意键从第 1 关重新开始。

游戏特色

  • 规则简单,但要动脑:需要规划点击顺序,一步步清出通道。
  • 不会死局:每关都验证过,每一步都至少有一个箭头能飞出去。
  • 视觉清晰:箭头方向一目了然,成功失败反馈明确。
  • 可竞速:计时器让玩家可以挑战更快通关。

操作

场景 操作
开始界面 按任意键开始
游戏中 鼠标左键点箭头
游戏中 按 F1 重开本关
失败或通关 按任意键重新开始

3.实现思路:

箭头表示

每个箭头是一个 Arrow 对象,存三个关键信息:

  • row、col:在 3×3 棋盘上的行号和列号。
  • direction:方向,用整数表示——UP=0、DOWN=1、LEFT=2、RIGHT=3。
class Arrow:
    def __init__(self, row, col, direction):
        self.row = row
        self.col = col
        self.direction = direction
        self.state = 'idle'      # idle / flying / shaking
        self.offset_x = 0        # 飞行动画位移
        self.offset_y = 0
        self.alpha = 255         # 淡出透明度

箭头分两个列表存放:

  • self.arrows:还在棋盘上的。
  • self.flying_arrows:已经飞出、正在播放动画的。

方向表示

方向映射成行、列的步进量 (dr, dc):

DIR_VECTORS = {
    UP:    (-1, 0),   # 行号减 1
    DOWN:  (1, 0),    # 行号加 1
    LEFT:  (0, -1),   # 列号减 1
    RIGHT: (0, 1)     # 列号加 1
}

飞行动画和路径检测都用这个步进量:

dr, dc = DIR_VECTORS[self.direction]
self.offset_x += dc * self.fly_speed
self.offset_y += dr * self.fly_speed

绘制时不靠旋转,而是给四个方向各写一组多边形顶点,保证画出来的方向和逻辑方向一致:

if direction == UP:
    points = [(s, s*0.3), (s*1.6, s*1.5), (s, s*1.1), (s*0.4, s*1.5)]
elif direction == DOWN:
    points = [(s, s*1.7), (s*0.4, s*0.5), (s, s*0.9), (s*1.6, s*0.5)]
elif direction == LEFT:
    points = [(s*0.3, s), (s*1.5, s*0.4), (s*1.1, s), (s*1.5, s*1.6)]
elif direction == RIGHT:
    points = [(s*1.7, s), (s*0.5, s*0.4), (s*0.9, s), (s*0.5, s*1.6)]

三、关卡表示

每个关卡是一个 3×3 的二维列表,每个格子存一个方向常量:

self.level_data = [
    # 第 1 关
    [
        [UP,    UP,    UP],
        [LEFT,  UP,    RIGHT],
        [DOWN,  DOWN,  DOWN]
    ],
    # 第 2 关
    [
        [LEFT,  UP,    RIGHT],
        [UP,    DOWN,  UP],
        [LEFT,  DOWN,  LEFT]
    ],
    # 第 3 关
    [
        [UP,    UP,    UP],
        [LEFT,  DOWN,  RIGHT],
        [DOWN,  DOWN,  DOWN]
    ]
]

切换关卡时,reset_level 读取对应数据,遍历 9 个格子,给每格生成一个 Arrow 放进 self.arrows:

def reset_level(self, level):
    self.arrows.clear()
    self.flying_arrows.clear()
    data = self.level_data[level - 1]
    for r in range(GRID_SIZE):
        for c in range(GRID_SIZE):
            direction = data[r][c]
            if direction is not None:
                self.arrows.append(Arrow(r, c, direction))
    self.mistakes = 0

关卡设计保证每步都有箭头能飞出,不会卡死。

路径检测

核心是 is_path_clear 函数,思路是从箭头前方一格开始,沿它指向的方向一格一格往外走,直到走出棋盘。

def is_path_clear(self, arrow):
    # 1. 拿到方向步进量
    dr, dc = DIR_VECTORS[arrow.direction]

    # 2. 从箭头前方第一格开始
    r = arrow.row + dr
    c = arrow.col + dc

    # 3. 只要还在棋盘内,就一格一格走
    while 0 <= r < GRID_SIZE and 0 <= c < GRID_SIZE:
        # 检查这一格有没有其他箭头
        for other in self.arrows:
            if other is arrow:       # 跳过自己
                continue
            if other.row == r and other.col == c:
                return False         # 被阻挡
        # 没被阻挡,继续朝同方向走一步
        r += dr
        c += dc

    # 4. 走出棋盘都没碰到箭头 → 畅通
    return True
  • 朝上只查同一列上方;
  • 朝下只查同一列下方;
  • 朝左只查同一行左边;
  • 朝右只查同一行右边。

不会看反方向或垂直方向。

点击和过关

玩家点击时,check_click 找到点中的箭头,调用 is_path_clear:

def check_click(self, pos):
    if self.state != STATE_PLAYING:
        return
    if len(self.flying_arrows) > 0:      # 动画中禁止点击
        return

    for arrow in reversed(self.arrows):
        if not arrow.is_idle():
            continue
        cx, cy = arrow.get_center()
        rect = pygame.Rect(cx - 50, cy - 50, 100, 100)
        if rect.collidepoint(pos):
            if self.is_path_clear(arrow):
                # 可以飞出
                self.arrows.remove(arrow)
                arrow.start_fly()
                self.flying_arrows.append(arrow)
            else:
                # 被阻挡,晃动 + 失误
                arrow.start_shake()
                self.mistakes += 1
                if self.mistakes >= MAX_MISTAKES:
                    self.state = STATE_GAME_OVER
            return

过关判定放在动画之后:只有 self.arrow 为空且 self.flying_arrows 也为空时,才进入下一关:

def update(self):
    # 更新飞行动画,飞出屏幕的移除
    for arrow in self.flying_arrows[:]:
        if not arrow.update():
            self.flying_arrows.remove(arrow)

    # 更新棋盘上箭头的晃动动画
    for arrow in self.arrows:
        arrow.update()

    # 全部清空后才过关
    if self.state == STATE_PLAYING:
        if len(self.arrows) == 0 and len(self.flying_arrows) == 0:
            self.next_level()

这样最后一个箭头的飞行动画能完整播完。

4.AIGC 使用过程:

AIGC 使用过程记录

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
中文显示乱码 DeepSeek 建议将 pygame.font.Font(None, size) 改为 pygame.font.SysFont('simhei', size),并给出多种中文字体备选方案。 中文方块问题解决,但部分系统找不到指定字体,需要多字体回退。 增加字体缓存和多种字体名回退列表,并最终改用全英文界面。
路径检测逻辑 DeepSeek 生成基于 DIR_VECTORS 的逐格遍历代码,沿箭头方向检查是否有其他箭头阻挡。 初始版本混淆行/列与坐标,所有箭头都能飞出,完全失效。 重写 is_path_clear,严格用 row += dr、col += dc 遍历,并加 if other is arrow: continue 跳过自身。
关卡布局设计 DeepSeek 提供 3 个 3×3 的二维数组布局,声称“保证有解”。 AI 生成的第二关出现死锁,6 个箭头互相阻挡,玩到一半必定失败。 手工推演清空顺序,重新设计关卡布局,每步都有箭头能飞出。
箭头绘制方向错位 DeepSeek 使用旋转角度方式绘制四个方向的箭头。 由于 Pygame 屏幕 y 轴向下,旋转公式导致“逻辑朝上、画出来朝下”,视觉与逻辑脱节。 放弃旋转,改为给四个方向各写一组多边形顶点,确保视觉方向与逻辑方向 100% 一致。
通关动画与重开功能 DeepSeek 生成“Level Clear!”停留 1 秒的过渡状态、F1 重开本关、结束界面按任意键重开等逻辑。 动画基本可用,但重开时没有清空正在飞行的箭头,旧箭头仍在屏幕上飞。 在 restart_current_level 中补上 self.flying_arrows.clear(),并调整动画时长和晃动幅度。

5.测试结果

测试用例与结果

编号 测试内容 预期结果 实际结果 是否通过
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 箭头沿指向方向飞出并消失 通过
T02 点击前方有阻挡的箭头 箭头不消失,失误次数加 1 箭头原地晃动不消失,失误计数加1,HUD 右上角数字变红 通过
T03 点击位于边缘且朝向棋盘外的箭头 箭头正常消失,不发生越界错误 第一关边缘的朝外箭头点击后飞出,飞出过程中坐标超出棋盘范围且不报错 通过
T04 消除本关全部箭头 显示通关并进入下一关 最后一个箭头飞完后,显示绿字 "Level Clear!",停留约 1 秒后自动进入下一关,关卡数 +1 通过
T05 失误次数耗尽 显示失败并允许重新开始 第 3 次失误后,界面切换到 "GAME OVER",显示失败原因、用时和到达关卡;按任意键从第 1 关重新开始 通过
T06 游戏进行中重新开始 箭头布局和失误次数恢复 按 F1 后,当前关卡箭头全部恢复到初始布局,失误次数清零,关卡数不变 通过

6.PSP 表格

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

7.心得体会

在开发“一箭又一箭”游戏的过程中,AI 帮助我快速搭建了代码框架、提供了动画实现公式和多种问题解决方案,显著提升了开发效率,但也暴露了它在空间逻辑、关卡可解问题、路径检测方向混乱等问题都需要手工推演和实机测试来修正。这次经历让我深刻体会到,AI 是高效的助手而非可靠的替代品,核心逻辑必须自己把关,逐格遍历方式写路径检测、用顶点直接绘制替代旋转,这些经验比代码本身更有价值。

posted @ 2026-09-18 15:54  adcbau  阅读(0)  评论(0)    收藏  举报