Files
gplan-2/design/gdd/systems/冒险循环/关卡节点图生成.md
T
DKChan 7aee5eb71a docs(流程文档迁出GDD批): 待办清单与体验验证清单移到仓库根并去掉编号前缀
两文件是流水线流程件而非游戏描述件,此前住在 design/gdd/ 造成三处不适配:
gdd_lint 必须为它们逐条关掉体裁规则、格式权威却写在 doc-conventions §12、
与同族的 roadmap(在仓库根)分居两处。迁到根后按 roadmap.md 的无编号风格改名。

- 迁出:design/gdd/06-待办清单.md → 待办清单.md;07-体验验证清单.md → 体验验证清单.md
- 指向改写 53 个文件:GDD 各系统文档指路存根、四份规约、02 根索引、README/roadmap/AGENTS
- 两份清单自身 74 处出站链接按新基址重指(../art → design/art、systems → design/gdd/systems)
- gdd_lint:待办/体验验证两文件的 R1/R3/R5/R7 豁免行随迁删除(已脱离扫描面),后门表清零
- pipeline_gate 默认路径、log_analysis/render_gate 称谓、repo_structure_audit 根文件白名单同步
- 保护面补写:两份清单列入实现批禁写清单(AGENTS 两类批条 / process-conventions §12 / 架构文档域表),
  条目状态只由流水线各段推进
- 范围外未动(用户令「全不碰」):reports/ 与 design/research/ 的 22 处历史指向、game/ 两处注释
2026-10-21 00:09:40 +08:00

21 KiB
Raw Blame History

关卡节点图生成

一句话:单关节点图怎么从固定配置变成逐局随机——图模板池、抽签与实例化 状态:v0.5 台阶一已实施(迭代 5 T5,2026-09-28 落 master 前挂 worktree m3-iter5-20260928——15 张骨架+node_map 扩签+首次冒险固定脚本+池内全模板校验+MC 分层出数,冒烟 576/0;文档本节规则与实现一致性以本批落地为准,台阶二/三仍后置) 旧版参考:无(旧体系未单独成文;事项自 2026-09-20 立项,池重生成已落地〔2026-09-29 返工批,二轮目检 15/15 过〕,原待办清单条目已完成移除)

设计目的

现行每关的节点图是关卡表里写死的一行行集——玩家每一局走的是完全相同的图。对照参照游戏:杀戮尖塔每层抽一张新地图,哈迪斯的房间编排逐局变化——布局变化本身就是"再来一局"的驱动力的一部分,而本作这块目前是零。

本文立项把单关节点图从固定配置升级为逐局随机。边界先说死:本文只管图从哪里来;图怎么走、走到每个节点发生什么、图合法性怎么校验,全部仍是关卡节点地图的现行规则,本设计对它们零改动——生成侧的职责止于"生产一张合法的图",生产出来的图进的是既有校验、既有行进、既有兑付。

系统范围

边界这样划:图模板与模板池是内容资产(与敌人表行、棋盘参数同级的配置内容),抽签是玩法随机(消费主种子派生流),实例化的产物就是关卡表行集——行集内容的责任方仍是冒险结构,本文管的是行集怎么被生产出来。

负责:

负责 说明
图模板的结构定义 一张模板有哪些组成部分、满足什么条件才算一张合法模板
模板池与关卡表接线 每关从哪个池抽、池怎么随关卡表配置
抽签时机与随机流 什么时候抽、消费哪条封闭流、可复现域怎么覆盖
实例化与校验交接 模板落成行集,交给既有的图合法性校验
台阶路线与测量对账 三级台阶的推进条件;模拟读数不被随机污染的口径

不负责:

不负责 归谁
节点图怎么走、选路、兑付触发、收束点 关卡节点地图(现行规则零改动)
图合法性校验的检查项与算法 关卡节点地图(LevelTable.validate 现行——生成侧只是它的上游供给方)
池里放几张模板、每张模板里放什么遭遇数值 冒险结构(行集内容责任方)与难度曲线与Boss(数值所有权)
战斗节点内部的敌人配置与初始化 战斗循环(节点编号寻址口径零改动)
节点图的画面呈现 HUD框架(节点态照旧读图,零新呈现语义)

在核心循环中的位置

冒险结构 ──开始关卡──▶ 关卡节点图生成(抽模板 → 实例化行集)──行集──▶ 关卡节点地图(校验 → 选路行进)

核心循环里"关卡:节点链逐节点推进"这一段之前,多了一步"这一关的图是哪张"的抽签——本系统就站在这一步。它向上接冒险结构的开始关卡请求,向下把实例化好的行集交给关卡节点地图;生成之后的一切(校验、行进、兑付、收束)与本系统无关。

核心规则

概念三件套:图模板、模板池、图模板抽签

人话阶段:本系统只有三个概念,弄清它们谁包含谁,整个系统就读懂了。

图模板(本文含义:一张手工编写的合法节点图骨架——一个节点集合〔每个节点带类型标注与关卡内唯一编号〕加一个连线集合)是内容资产,不是运行期生成物。实例化(本文含义:把模板原样照抄落成该关的行集——节点集合与连线进关卡表行,零变换)之后,它就是关卡节点地图要加载的那张图。

概念 一句话定义 归谁
图模板 手工编写的合法节点图骨架;实例化即行集 本文(结构规则);内容归冒险结构
模板池 关卡表逐关行配置的同关可抽模板集合,池大小 N(N≥1) 本文(规则);配置承载归数据配置
图模板抽签 关卡开始时从池中均匀抽一张 本文(时机与流);流基础设施归数据配置

模板池挂在关卡表逐关行上:行集从"单一节点集合"扩为"模板池"。N=1 的池里只有现行那张图,逐局抽签退化回固定图——这是回滚档(本文含义:任何一关把池缩回一张模板,该关行为就与今日固定配置逐位等价的保险形态)。整个设计因此可增量落地:先全关 N=1,再逐关扩池。

抽签消费主种子派生的统一随机流,走扩签通道新立用途标签 node_map(统一流口径已定——2026-09-27 两轮复裁落地;标签不参与派生、只进事件日志)。

出度上限与层宽(2026-10-01 用户拍板 T17 目检):单节点出边数(出度)最大为 2——加载校验第七检(fanout_violation 加载致命)。规则连带(数学约束):出度 ≤2 + 入口唯一下,BFS 层宽上限 = 4(层宽序列上限 1,2,4;2026-09-29 旧规则「层宽上限 5」与出度约束不相容,随本拍板废止)。现行池 = tools/t17_fanout2_rebuild.py 按两规则重建(五骨架:宽廊双干〔现行〕/三干中廊/宽廊斜岔/三干宽门/窄廊短支——层宽序列 1-2-4-1-1 / 1-2-3-2-1 / 1-2-2-2-1,最大层宽 4 应用足)。

内容纪律:每张新模板等于一个小内容批——模板里每个战斗与 Boss 节点都必须在敌人与棋盘生成的数值表里有精确行,义务从冒险结构加关纪律的"每关一行集"细化到"每模板一行集";冒烟覆盖义务同批扩为遍历池内全部模板校验,不只抽中的那张。

抽签时机与可复现

人话阶段:什么时候抽、抽完怎么保证复盘对得上,是本系统接入现有随机纪律的两件事。抽签时点 = 开始关卡处理内、加载节点图之前,逐关各抽一次(不是冒险开始一次抽齐三关)——抽签时机贴着"这一关的图要用"的时点,主种子的复现域天然覆盖。

冒险结构(开始关卡:关卡序号、当前生命、生效上限)
  → 关卡节点图生成:按关卡序号取模板池 → 抽一张(图模板抽签流,恰一 scope)
  → 实例化为行集 → 交图合法性校验(关卡节点地图现行,零改动)
  → 关卡节点地图加载行集 → 呈现选路停点(现行流程原样续跑)

可复现域沿用既有口径:主种子 + 全局取数计数器(2026-09-27 统一流;旧表述系并流前口径)(语义权威归冒险结构「失败重开与主种子」节,本文不复述)。抽签每次消费恰一个带编号的 scope,计数器随既有快照契约入档——存档序列化零新增域。同主种子同操作序列的两局,逐位同一张图。

教学位随骨架走:各骨架的"第一场战斗节点"沿用教学位纪律(首遇位固定数量不加骰)——教学位属性是骨架的内容标注,不跟节点编号走(拍板点①裁决后第一关也参与抽签,例外见下节)。

首次冒险的固定脚本(拍板点①裁决写入文档)

人话阶段:教学关不该第一局就随机——玩家第一次玩,地图必须是设计好的那一张。拍板点①裁决(2026-09-27):全部关卡都参与抽签,唯独玩家的第一次冒险全程走固定脚本。这也是参照游戏的通用做法(首次冒险特殊脚本)。

事项 规则
判定标志 存档域新增布尔位「首次冒险已进行」(owner=存档序列化,实施批落 schema)
判定时机 开始新冒险时读标志:false = 首次脚本模式;true = 正常抽签
脚本模式内容 全关零抽签——每关直接取池内的现行固定模板(即回滚档成员),逐位等价今日行为,无需新做脚本内容
置位时机 冒险收束点置位(完成/失败/放弃三结局同写)——存档级属性冒险期只读、写入只在收束挂点(既有纪律)

两条边界:首次冒险中途退出游戏(未到任何收束点)则标志未写,下次新冒险仍走脚本——教学重放,可接受;首次冒险内死亡或放弃即结算置位,第二次冒险起抽签。

测量口径:模拟试玩与数值验证夹具恒置标志为 true(永远走抽签路径)——首次脚本分支不进任何读数。

三级台阶路线

人话阶段:2026-09-21 呈报的三级台阶(图模板抽签 → 骨架固定+属性随机 → 全程序生成)随本批立项成文为正式路线。每一级都比上一级多一点随机,每一级都必须过同样两条不变量:①产物过图合法性校验(检查项口径归关卡节点地图,本文不复述);②商店房"每关恰 1、关底 Boss 前一位必经位"的编排约束在生成侧成立——冒烟断言照旧把关,校验零新增。

台阶 内容 前置条件
一:图模板抽签 每关模板池 N≥1,逐局从池中抽一张手工模板实例化 测量对账条款先行(见下节);每张新模板按内容纪律配齐数值行
二:骨架固定+属性随机 模板拓扑定型,节点类型在候选槽位(本文含义:模板给某个可变位列出的允许节点类型集合,实例化时从集合内均匀掷一个——例:某槽位允许{奖励,恢复},掷中哪个就是哪个)内掷定 台阶一完成;商店房所在位排除出候选槽位(保必经位)
三:全程序生成 读参数(深度、分支密度、节点类型配比)直接构造图,构造失败重掷(重掷预算同棋盘生成 max_gen_attempts 纪律) 台阶二完成;图合法性校验作最终守门

台阶二的随机量入账:候选槽位掷定消费同一条图模板抽签流的后续 scope,计数器域照旧覆盖,可复现性零损失。台阶三的参数取值域届时随本文修订登记,本草案不预设。

台阶一用一句话说:给每关手工做几张不同的地图骨架,每局开始时随机抽一张用(用户裁决路线确认:骨架不完全固定、多份随机调取)。玩家看到的是同一关每局长得不一样——这局岔路多、下局一条窄道——但每张都是人工画好、审过合法性的图,不是程序乱长。台阶一不做两件事:房间类型不掷骰(某房间是奖励房还是恢复房仍由骨架定死——那是台阶二),程序不算图(那是台阶三)。首版池规模 = 每关 5 张(拍板点④),其中 1 张 = 现行固定图。

测量对账:别让随机污染读数

人话阶段:2026-09-21 呈报暂缓的三理由之一是"污染 MC 读数"——模拟试玩与数值验证的通关率是按固定图测的,图一随机,读数波动就混进了布局差异。本节是消解条款,三条:

  1. 分层出数:模拟试玩与数值验证工具的读数按「关卡 × 图模板」分层记录;混合池的整体通关率 = 各模板条件通关率的加权平均(权重 = 抽中概率,均匀池即算术平均)。
  2. 基线可比:基线批(与基线数据逐项比对、重投)跑固定模板口径——把池临时缩到 N=1(回滚档)或固定抽签 scope,保证新旧基线在同一张图上对话。
  3. 实施门:随机量(扩池)上线排在难度曲线与Boss曲线调参批完成之后——现行行值 provisional 收带前叠加布局随机,归因会失真;抽签机制本身可先行落地(池保持 N=1 行为零变化,见拍板点③选项 C)。

另两条暂缓理由顺带消解:类型集未稳——五类节点封闭枚举已随商店房批定稿,扩类走文档修订的既有通道对模板同样适用(模板 schema 跟随枚举走);内容量不足——台阶一的模板就是内容批,按内容批节奏逐张走,不设批量生产目标。

拍板点(登记 待办清单,顺带更新条目)

# 拍板点 状态
① 第一关(教学关)是否参与抽签 已裁决(2026-09-27):参与——仅首次冒险走固定脚本,见「首次冒险的固定脚本」节
② node_map 随机流增流 已裁决(2026-09-27 两轮复裁):统一用一个流——全游戏 rng 架构批先行(评估书已交付,2026-09-27),本特性实施排队其后
③ 台阶一实施时点 已裁决(2026-09-27):机制先行骨架随后——特性内先落抽签机制(池暂 N=1 行为零变化)、骨架内容批随后扩池;整体仍排在架构批落地之后
④ 首版池规模 已裁决(2026-09-27):每关 5 张起步(调参表已投值)
⑤ 抽签时点 = 关卡开始逐关抽 已裁决(2026-09-27):确认

证据面 A:随机流与「增流」是什么(拍板点②的背景)

人话:本项目的随机数只有一个总入口(随机服务,代码名 rng_service),硬性红线禁止任何代码绕开它自己掷骰——"同一个种子+同样操作序列 = 逐位相同的一局"靠这条保证,调试复盘和模拟对账都依赖它。总入口内部按用途分账:每种用途占一栏,叫一条流(本文含义:随机服务内部按用途分开记账的一栏独立随机序列,各有各的编号,互不串账)。现行清单七条:雷图生成、奖励抽取、敌人数量掷骰、命中掷点、出招摇号、变异布置、GP 掉落——清单是封闭的,新用途必须在清单里开新栏。

图模板抽签是一笔新用途的随机账,要在清单里新开一栏(拟名 node_map)——「增流」就是这个动作:给封闭流清单加一条新流。它之所以要拍板:加流有固定成本(改代码 + 补一组校验用黄金向量 + 加冒烟断言,纪律规定的三件套),不是随手配置。

选项 内容 代价
A 增流(原荐) 清单加 node_map 栏,抽签独立记账 三件套成本;图的抽签可独立复现,与其它系统零耦合
B 借现有流 从某条现有流取号 省三件套;但这笔账和那个系统的账搅在一起——重放对方系统的随机序列会被抽签挤位,复现口径变含糊,不推荐

裁决注记(2026-09-27):用户两轮复裁后终选「统一用一个流」(全面执行),执行路径 = 全游戏 rng 架构批先行、本特性排队其后。评估书已交付(2026-09-27,git 历史可查)——核心发现:字面目标「单一随机源、逐位可复现」现行架构已满足(七条流系同一主种子的七个盐值分栏而非七个随机源);待裁决项 = 是否进一步并掉分栏计数器(方案甲维持分栏 / 乙物理并流 / 丙并流+全事件日志)。

证据面 B:台阶一详解与实施时点(拍板点③的背景)

台阶一(图模板抽签)落地后的样子:

  • 玩家看到什么:同一关,每局地图的房间连接方式不一样(这局岔路多、下局一条窄道),但每张都是人工画好、审过合法性的图——不是程序乱长。
  • 做三件事:①每关 5 张骨架(拍板点④,其中 1 张 = 现行固定图);②开始关卡时抽一张实例化;③首次冒险走固定脚本(拍板点①)。
  • 不做两件事:房间类型不掷骰(那是台阶二);程序不生成图(那是台阶三)。
  • 内容形态:一个内容批 = 15 张骨架(3 关 × 5)+ 池内全模板加载校验 + 冒烟断言。骨架里只有房间和连线,不新增敌人数值——遭遇表按节点编号共用:两张骨架若都在 3 号位开战,3 号位打的敌人是同一套(表键不含骨架维);骨架差异体现在拓扑与房型排布,不体现在"同编号打不同敌人"。要打破这条需给遭遇表键加骨架维,归实施批 schema 拍板。

实施时点三个选项:

选项 内容 后果
A 机制+骨架立即全上 现在做完整内容批(含扩池到 5 张) 曲线调参批未完成,数值基线在动;地图一随机,模拟读数的波动归因变难(数值动了还是图动了分不清)
B 全部等调参批完成(v0.1 原荐) 机制与内容都排在曲线调参批后 读数对账最干净;机制落地要等
C 机制先行、骨架随后(原荐) 先落抽签机制但每关池暂放 1 张现行图(行为零变化),骨架内容批画好后一次扩到 5 张——扩池时点守测量对账实施门 机制与内容解耦:扩池前读数零污染,扩池后分层出数条款接管;不用等调参批

依赖与输出

这张表就是删除任何一方时的影响面清单。

方向 系统 / 文档 接口要点
上游 冒险结构 开始关卡流程是抽签时点的宿主;主种子与派生流的语义权威;行集内容责任方(模板内容归它)
上游 数据配置 关卡表模板池列的承载与统一读取;node_map 统一流用途标签(扩签已落地 v0.5)与流种子派生公式的基础设施
上游 难度曲线与Boss 模板内遭遇数值的所有权;曲线调参批完成是台阶一的实施门
下游 关卡节点地图 实例化行集的供给方;其图合法性校验与全部行进规则零改动
下游 存档序列化 抽签 scope 计数器入既有快照契约(主种子 + 流计数器),零新增域;「首次冒险已进行」布尔位为唯一新增存档字段(实施批落 schema)
下游 HUD框架 零新语义——节点态照旧读图,模板差异对呈现层透明

P0 最小闭环(台阶一实施批)——✅ 已落地(v0.5,2026-09-28)

实施前置已解除:统一随机流批已落地(2026-09-27 两轮复裁——统一流+全事件日志);抽签接入形态 = 统一流扩签新用途标签 node_map(扩签通道 = 改代码 + 评审)。

  1. 关卡表逐关行扩模板池结构(承载归数据配置,schema 细节随实施批定)。
  2. 池内全部模板加载期预校验(违规致命,fail-fast 不变)。
  3. 存档域加「首次冒险已进行」布尔位:开始新冒险读标志(false = 首次脚本模式,全关零抽签取现行固定模板),冒险收束点置位(三结局同写,写入只在收束挂点)。
  4. 开始关卡处理内抽签实例化(node_map 流恰一 scope——拍板点②)。
  5. 既有图合法性校验照跑零改动;关卡节点地图与战斗侧全链零改动。
  6. 冒烟断言:抽签确定性(同种子逐位同图)、池内全模板校验、N=1 池与现行固定图逐位等价、首次脚本分支(标志 false = 固定图 / true = 抽签)。

P1 / P2 后置

优先级 内容 后置原因
P1 台阶二:骨架固定+属性随机(候选槽位掷定) 台阶一完成后另批立项;商店必经位的槽位排除规则顺带成文
P2 台阶三:全程序生成(参数化构造) 台阶二完成后另批立项;参数取值域与重掷预算顺带修订本文

调参表

本系统无已锁数值。台阶一实施后进表:

参数 域 现行值 说明
模板池大小 N int [1,+∞),关卡表逐关行 每关 5(2026-09-27 拍板点④;2026-09-28 台阶一实施批落地,3 关 × 5) N=1 = 回滚档;扩池 = 内容批
重掷预算(台阶三) 未立项不设值 — 台阶三立项时随本文修订登记

验收标准(草案——随拍板点裁决完成,实施批落地时按本节验收)

  • 池内全模板加载期通过图合法性校验,违规致命(校验面不只抽中的那张)。
  • 抽签确定性:同主种子同操作序列逐位同一张图;抽签 scope 可独立回放。
  • 回滚档成立:N=1 池的关卡与现行固定图逐位等价。
  • 首次冒险脚本:存档标志 false 时全程固定图(逐位等价现行行集),冒险收束点置位标志恰一次;标志 true 后每局抽签。
  • 商店房编排约束在每张模板上成立:每关恰 1 个商店房、关底 Boss 前一位必经位。
  • 零新面:关卡节点地图行进/兑付/收束断言与战斗侧寻址断言全绿,零改动。
  • 测量分层:模拟读数含「关卡 × 图模板」维度;基线批可固定模板复现。
  • 内容纪律:每张新模板的战斗与 Boss 节点在敌人与棋盘生成的数值表中有精确行(冒烟遍历池内全模板)。

待办

本系统无未决待办(结构随机生成池已落地);后续新增待办统一登记待办清单,本节不再逐条登记。