软件工程课程第二次个人作业

项目 内容
这个作业属于哪个课程 H202601软件工程与软件工程实践
这个作业要求在哪里 作业链接
这个作业的目标 使用 Python 和 AIGC 完成“一箭又一箭”小游戏
学号 102402137
GitHub 仓库 仓库链接

一、项目展示

1.游戏开始界面

屏幕截图 2026-09-16 165000

2.游戏过程界面

屏幕截图 2026-09-16 165044

3.游戏通关界面

屏幕截图 2026-09-16 165029

4.游戏失败界面

屏幕截图 2026-09-16 165054

GIF演示

2026-09-19095521-ezgif.com-video-to-gif-converter

二、项目介绍:

1.游戏规则

棋盘上散布着若干带方向的箭头,方向只有上、下、左、右四种。点击某个箭头后,程序检查它前进方向上、到棋盘边界之间有没有别的箭头:

情况 结果
前方没有其他箭头 箭头沿自己的方向飞出棋盘,被消除
前方有其他箭头阻挡 飞不出去,消耗一次失误机会,并给出碰撞反馈
  • 清空本关全部箭头 → 通关
  • 失误次数耗尽 → 本关失败,可重新开始
  • 点击空格子或棋盘外不扣失误

判定只考虑同行 / 同列、箭头与边界之间的直线路径,不考虑拐弯或连锁反应。

2.界面设计

整体是深色科技风,用渐变和光晕做层次,避免大面积纯色块带来的廉价感。

四个界面状态

界面 内容
开始界面 游戏标题、玩法说明面板、开始 / 继续 / 新游戏 / 选择关卡 / 退出按钮、右上角音效开关
游戏界面 顶部信息栏、自适应棋盘、底部操作栏
选关界面 12 张关卡卡片(4×3 网格)
结算浮层 半透明遮罩 + 结果面板(通关 / 失败)

游戏界面的三段式布局

  • 顶部信息栏:做成一张浮起的圆角卡片而不是通栏色块。左侧是关卡编号与关卡名(带强调竖线),中间是三个状态胶囊——剩余箭头(蓝)、剩余失误(按剩余量在绿/橙/红之间切换)、用时(紫,超过目标用时会转橙,提示已经没有速度奖励),右侧是「重新开始」「选择关卡」。
  • 棋盘:外框用渐变 + 内凹的格子井,格子做成有顶部高光和底部暗边的"键帽"质感。棋盘尺寸会按关卡自动计算格子边长并居中,4×4 到 7×7 都不用手工调。
  • 底部操作栏:左侧是操作提示(被临时消息占用时会让位),右侧是「音效」「撤销 ×3」「提示 ×3」三个按钮。

视觉细节

  • 箭头按方向用四种颜色区分(上蓝、下橙、左绿、右红),带柔和外发光、渐变主体和落地投影
  • 背景是渐变 + 顶部冷色光晕 + 46 个缓慢上浮的粒子 + 四角暗角
  • 结算面板顶部有圆形徽章(通关是对勾、失败是叉),背后一圈同色光晕

动画与音效

  • 悬停:格子高亮和箭头放大都是平滑过渡(指数逼近),移开时淡出而不是硬切
  • 入场:进入关卡时箭头按对角线顺序逐个弹出,带轻微过冲回弹
  • 飞出:箭头逐渐加速飞出,身后拖一条随速度拉长的渐隐轨迹
  • 碰撞:朝阻挡方向冲一下 → 带回弹地退回 → 左右晃动 → 闪白,同时格子扩散一圈红色光环
  • 切界面:从黑场淡入,不硬切
  • 音效:7 个音效(飞出、被挡住、提示、撤销、点击、通关、失败)

3.主要功能和特色

功能 说明
关卡系统 12 关,分入门 / 进阶 / 挑战三档(各 4 关),棋盘从 4×4 到 7×7,失误上限 3~5 次
关卡选择 卡片式选关,显示棋盘尺寸、箭头数、难度档,通关后显示最高分与最快用时
进度解锁 通关前一关才开放下一关(可在配置里一键改为全部开放)
计时 实时计时,本关结束时停表;超过目标用时胶囊变色提示
计分 基础分 + 速度奖励 + 失误奖励 − 提示扣分 − 撤销扣分,结算面板逐项列出
成绩记录 每关独立保留最高分与最快用时,主菜单与选关界面显示总分
提示 每关 3 次,用金色脉冲光环标出一个当前就能消掉的箭头
撤销 每关 3 次,可退掉一次消除或一次误点(含退回失误)
自动存档 长期成绩与当前这一局分开存两个文件,随时关窗口都能接着玩
音效开关 三个界面都有「音效:开 / 关」按钮,实时显示当前状态

三、实现思路:

1.箭头与方向怎么表示

方向用字符串"up" / "down" / "left" / "right"
方向统一转成位移向量

# 屏幕坐标:行号向下增大,列号向右增大
DIRECTION_VECTORS = {
    "up":    (-1,  0),
    "down":  ( 1,  0),
    "left":  ( 0, -1),
    "right": ( 0,  1),
}

"沿箭头方向前进一格"就统一成 (row + dr, col + dc),判断路径、算到边界的距离、算到阻挡者的距离,全都共用同一套向量,不需要为四个方向各写一个分支

棋盘上的箭头用字典存

arrows = {(0, 3): "down", (2, 4): "right", ...}   # (行, 列) -> 方向

键是格子坐标,值是方向。选字典而不是二维数组,原因有三个:

  • 棋盘大部分格子是空的,字典只存有箭头的格子,省空间也省遍历
  • 判断"某格有没有箭头"是 O(1),路径检测要反复做这个判断
  • 消掉箭头就是 pop,撤销就是重新赋值,不需要维护额外的状态

箭头图形的画法:只用一份归一化坐标描述"向上"的轮廓,其它方向靠绕中心旋转 90° 的整数倍得到。

_ARROW_SHAPE = (
    (0.00, -0.34),   # 箭尖
    (0.22, -0.06),   # 箭头右角
    (0.09, -0.06),   # 箭杆右上
    (0.09,  0.32),   # 箭杆右下
    (-0.09, 0.32),   # 箭杆左下
    (-0.09, -0.06),  # 箭杆左上
    (-0.22, -0.06),  # 箭头左角
)
_DIR_TURNS = {"up": 0, "right": 1, "down": 2, "left": 3}

旋转用的是屏幕坐标系下的 90° 顺时针公式:

x, y = -y, x

朝上时箭尖在 (0, -0.34);转一次得到 (0.34, 0),正好朝右。这样只需要维护一份轮廓数据,四个方向共用,改箭头造型时也只改一处。

2.关卡怎么表示

用 ASCII 图写布局. 是空格子,^ v < > 是四个方向的箭头:

_level("初次搭箭", "入门", 17, 3, """
    ....
    .<.v
    ..>.
    .^..
"""),

五个参数依次是关卡名、难度档、难度分、失误上限、布局。

解析过程:先用 textwrap.dedent 去掉源码缩进,再逐行逐字符查表映射,把每一个箭头收集成 (行, 列, 方向)

CHAR_TO_DIR = {"^": "up", "v": "down", "<": "left", ">": "right"}

lines = [line.rstrip() for line in textwrap.dedent(art).strip("\n").split("\n")]
for row, line in enumerate(lines):
    for col, char in enumerate(line):
        direction = CHAR_TO_DIR.get(char)
        if direction is not None:
            arrows.append((row, col, direction))

最后装进一个 frozen dataclass:

@dataclass(frozen=True)
class Level:
    name: str
    tier: str
    difficulty: int
    rows: int
    cols: int
    max_mistakes: int
    arrows: tuple

难度分用三个可量化的指标算出来:

难度分 = 箭头数 × 3 + 最长依赖链 × 2 + 被挡住的箭头数

3.路径检测

基本思路

因为作业统一成"单格箭头 + 同行同列直线判定",所以判定退化成一件很简单的事:从箭头所在格子出发,沿着方向向量一格一格往前走,看会不会撞到别的箭头。

def _blocker_on(board, rows, cols, cell):
    """在给定的棋盘上,沿箭头方向找第一个挡住它的箭头。"""
    direction = board.get(cell)
    if direction is None:
        return None
    dr, dc = DIRECTION_VECTORS[direction]
    r, c = cell[0] + dr, cell[1] + dc        # 从箭头前方一格开始
    while 0 <= r < rows and 0 <= c < cols:   # 一直走到棋盘外
        if (r, c) in board:
            return (r, c)                    # 撞到了,它就是阻挡者
        r += dr
        c += dc
    return None                              # 一路畅通,可以飞出

这个函数实现射线探测功能,用来查找当前箭头视线中第一个阻挡它的箭头。输入包含存储箭头位置与方向的棋盘字典、棋盘行列数和当前箭头坐标。棋盘字典只保存放置了箭头的格子,空白格子不会记录在内。
程序先读取当前格子箭头的方向,若该位置不存在箭头,直接返回空值。随后取出箭头对应的移动向量,从箭头前方相邻格子开始扫描,不会把箭头自身当作障碍物。
循环会沿着箭头方向不断移动坐标,只要坐标没有超出棋盘边界就持续探测。每检查一格,就判断该位置是否存在箭头;一旦遇到箭头,立刻返回这个阻挡箭头的坐标,终止探测。如果一路扫描直到走出棋盘都没有发现其他箭头,函数最终返回 None,代表这条视线没有任何遮挡。
返回 None 就表示"前方到边界之间没有别的箭头",也就是这个箭头能飞出棋盘。

direction = board.get(cell)
if direction is None: return None

读取当前格子箭头方向,无箭头直接返回空。

dr, dc = DIRECTION_VECTORS[direction]
r, c = cell[0] + dr, cell[1] + dc

获取方向步长,从箭头前方一格开始探测。

while 0 <= r < rows and 0 <= c < cols:

在棋盘范围内持续向前遍历。

if (r, c) in board: return (r, c)
r += dr; c += dc

遇到第一个箭头就返回它的坐标,否则继续前进。

return None

走出棋盘仍未碰到箭头,说明无障碍物。

四、AIGC 使用过程

首先,我先把一箭又一箭游戏制作的任务要求发给AI
屏幕截图 2026-09-16 203008
然后,我将任务分解为多个不同的部分,例如,我首先先让AI帮我制作游戏界面
屏幕截图 2026-09-16 203033
在任务过程中,我也会对已完成的部分进行一点优化
屏幕截图 2026-09-16 203048

子任务 借助何种 AIGC 技术 AI 实现或提供了什么 效果如何 人工修改
分析游戏任务 DeepSeek 了解任务的需求 能完成任务并列出任务的要求
制作游戏界面 DeepSeek 完成了游戏的主界面、游戏界面等 基本可用 删去了多余的按键
完善关卡部分 DeekSeek 增加关卡数量与关卡选择功能 基本可用 对关卡中箭头位置进行调整
添加游戏音效 DeepSeek 添加了游戏点击、通关时等音效 不错
增加额外功能 DeepSeek 添加了提示、撤回等功能 基本可用 调整按键位置

五、测试结果

编号 测试内容 预期结果 实际结果 实际结果与预期是否相同
T01 点击前方无阻挡的箭头 箭头飞出棋盘并消失 点击后箭头飞出棋盘并消失
T02 点击前方有阻挡的箭头 箭头不消失,失误次数减 1 发出错误提示,失误次数减 1
T03 点击位于边缘且朝向棋盘外的箭头 箭头正常消失,不发生越界错误 箭头消失
T04 消除本关全部箭头 显示通关并进入下一关 显示通关并进入下一关的界面
T05 失误次数耗尽 显示失败并允许重新开始 显示失败与重新开始的界面
T06 游戏进行中重新开始 箭头布局和失误次数恢复 恢复关卡的箭头、失误次数、提示次数等
T07 静音按键是否有用 按键能关闭/打开声音 按键能开关声音
T08 点击新游戏按钮 清除先前所有游戏记录 清除记录并重新开始
T09 提示按键是否有用 选出能消除的箭头 显示出可消除的箭头
T10 退出游戏后是否能保存游戏进度 退出后可以保存游戏进度 退出后可以保存游戏进度

六、PSP 表格: 填写各阶段预计耗时和实际耗时;

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

七、心得体会

AI把想法变成可运行代码的速度,是手写完全比不了的,从空目录到一个能玩、能存档、有音效的完整游戏,整个过程我基本没有卡在"这个 API 怎么写"上。界面布局、事件循环、状态机、存档序列化这些模板化的部分,AI 一次就能给出能跑的版本。
AI承担了大量机械性、重复性工作,能显著提高工作效率,12 个关卡的布局、配色方案、样式微调、参数调整,这些活写起来不复杂但极其琐碎。尤其是关卡布局,我需要反复调整二十多轮,每次都要重新验证。
AI有时候做的快捷键是没有效果的,要自己测试时才能检查出来
有些事 AI 判断不了,例如"好不好看"这种主观标准:AI 能画出来,但"够不够好看"得靠你反复看截图、提意见才能解决。

posted @ 2026-09-19 10:29  WQWa  阅读(13)  评论(0)    收藏  举报