21 · 程序化生成系统设计
21 · 程序化生成系统设计
独立游戏买不起内容量,PCG 是唯一负担得起的规模化手段。 但 PCG 的成本曲线是前重后轻:前期投入大,后期边际成本近零——选它之前先确认你付得起前期。 渲染/管线实现见
game-tech-art/domains/05-procedural-generation.md;本文件管设计侧:生成什么、怎么控制、怎么验证。
1. 先决策:该不该用 PCG
| 维度 | 手工内容 | 程序生成 |
|---|---|---|
| 成本曲线 | 线性(每关都是钱) | 前重后轻 |
| 质量上限 | 高(可精雕) | 中(但可通过约束逼近) |
| 多样性 | 低(设计师产能上限) | 高 |
| 可读性 | 高 | 风险点 |
| 节奏控制 | 精确 | 需额外机制 |
| 适合 | 叙事、解谜、银河城 | Roguelike、生存、沙盒、自动生成关卡 |
决策三问:
- 我需要的内容量是否远超团队手工产能?(例如 500 个关卡)
- 我的核心循环是否依赖每次不同?(重复感是致命的)
- 我能否接受"生成的每一局不是最好的那一局"?
三个"是" → 用 PCG。任一"否" → 手工内容质量更高。
混合策略(最实用):手工做骨架(关键关卡、Boss、教学),PCG 做填充与变奏。 例:手工设计 5 个房间模板 → PCG 组合与参数化 → 手工挑选最优的 20 个变体入库。
2. 生成的三个层次
| 层 | 生成什么 | 例子 | 难度 |
|---|---|---|---|
| L1 布局生成 | 空间、地形、物件位置 | 地牢房间布局、平台跳跃段落 | 中 |
| L2 内容生成 | 数值、词缀、掉落、敌人组合 | 词缀装备、随机词条、敌人波次 | 低(最推荐) |
| L3 规则生成 | 规则本身、系统参数 | 每局不同规则的修饰器、Balatro 的随机小丑池 | 高(深度最高) |
独立游戏建议:L2 是性价比最高的层——成本低、玩家感知强、易于平衡。 L1 需要空间设计能力,容易做出"能走但不好玩"的地图。 L3 是 Balatro / StS 式深度的来源,但需要极强的约束设计。
3. 生成语法(Grammar):从约束到输出
核心思路:不要写"生成器",要写"语法"。 语法定义合法的组合规则,生成器只是语法的执行器。
[语法]
S → 章节
章节 → 引入段 + 变奏段×2~3 + 考试段
引入段 → 1 个新机制 + 安全练习场
变奏段 → 已教机制的组合 + 递增强度
考试段 → 综合考验 + 奖励
[约束]
- 引入段必须出现在任何变奏段之前
- 新机制在考试段前至少出现 2 次
- 连续两个变奏段不能使用同一机制组
- 章节末必须有一次释放段
语法的三个好处:
- 可控:约束保证生成结果符合设计意图
- 可验证:可以检查生成结果是否满足约束
- 可迭代:改语法而非改生成器代码
语法设计步骤:
- 手写 3–5 个"理想样例",找它们的共同结构
- 把这个结构抽象成产生式规则
- 列出"绝对不能出现"的情况 → 约束
- 写生成器
- 跑 1000 次,人工抽查 20 个,统计约束违反率
4. 可控随机的四种技术
| 技术 | 做法 | 用途 |
|---|---|---|
| 种子(Seed) | 一切随机源自一个种子 | 可复现、可分享、可 debug、社区可玩"每日种子" |
| 权重曲线 | 不平均随机,按权重抽取(前期小怪多,后期精英多) | 控制难度曲线与节奏 |
| 约束求解 | 生成后检查约束,不满足则重新生成或修补 | 保证可解性与设计意图 |
| 后处理修正 | 生成后做一次"设计师之手"的修正(补关键路径、加引导) | 提升可读性与体验 |
必须用种子的三个理由:
- Bug 复现:玩家报告"第 3 关过不去"时,有种子就能复现
- 平衡测试:固定种子跑 1000 次,对比不同版本的数值
- 社区长尾:每日种子/种子分享 = 零成本的社区内容
约束求解的成本控制:拒绝采样(重新生成)最便宜,但约束多时成功率骤降。 经验阈值:单次生成成功率 < 20% 时,改用修补式生成(生成后局部修正)而非重试。
5. 生成质量验证(五道检查)
生成的每一份内容都必须过这五关,否则它是"能玩但不好玩"的。
| # | 检查 | 判据 | 失败后果 |
|---|---|---|---|
| 1 | 可解性 | 存在至少一条通关路径 | 卡死(最严重的 bug) |
| 2 | 可读性 | 关键路径可辨认,无死胡同无回报 | 迷路、挫败 |
| 3 | 节奏 | 强度曲线符合目标模板(见 principles/02 §5) |
忽难忽易 |
| 4 | 多样性 | 连续 N 局的相似度低于阈值 | 重复感 |
| 5 | 公平性 | 无"必死局"、无"资源荒漠" | 不可归因的失败 |
自动化验证:
- 可解性 → 用寻路/求解器自动验证(必须自动化,人工抽查不够)
- 节奏 → 计算生成结果的强度序列,与目标模板做距离比较
- 多样性 → 计算特征向量(房间数、敌人构成、资源分布),看分布是否过窄
- 公平性 → 模拟机器人跑通,记录死亡率与死因
多样性指标参考:
| 指标 | 健康值 |
|---|---|
| 连续 10 局的特征向量平均距离 | > 阈值(因游戏而异,先测基线) |
| 出现率最高的模板占比 | < 30% |
| 从未出现的合法组合 | 接近 0 |
6. 用生成器产生难度曲线
PCG 最大的诱惑是"完全随机",但玩家需要可学习的节奏。
| 手法 | 做法 |
|---|---|
| 难度作为生成参数 | 把"目标强度"作为输入,生成器按强度选元素 |
| 阶段化语法 | 前 1/3 只生成已教元素,中 1/3 生成组合,后 1/3 生成高压 |
| 保底机制 | 连续 N 次生成"太简单"→ 强制提升强度;反之亦然 |
| 手工锚点 | 关键节点(第 1 关、Boss 前、结局前)用手工内容锚定 |
反模式:纯随机难度 → 玩家无法建立模型 → "这游戏靠运气"。
7. 独立游戏实操
| 项 | 建议 |
|---|---|
| 工具 | 优先用引擎自带(Unity Tilemap + 自定义规则、Godot 的生成节点);不要自研通用生成框架 |
| 可视化调试 | 必须做:能一键显示生成过程、约束检查结果、种子、重生成 |
| 批量预览 | 做一个"生成 100 个并平铺预览"的工具,人工挑选质量基准 |
| 版本快照 | 记录"哪个种子 + 哪个生成器版本 = 哪个结果",否则无法复现 |
| 生成时间预算 | 单次生成 < 100ms(否则玩家等);大世界可做异步/分块 |
| 内容入库 | 生成结果好的,人工标记入库,作为后续生成的模板 |
成本警示:PCG 的调试成本常被低估。一个"看起来对"的生成器,可能需要 2–3 倍于预期的时间来调好可读性与节奏。
8. 与手工内容的边界
| 内容 | 手工 | 生成 |
|---|---|---|
| 教学关 | ✅ 必须手工 | ❌ |
| Boss | ✅ 手工 | ❌ |
| 关键剧情节点 | ✅ 手工 | ❌ |
| 常规关卡布局 | ⚠️ 骨架 | ✅ 填充与变奏 |
| 敌人组合/波次 | ⚠️ 规则 | ✅ 执行 |
| 数值/词缀/掉落 | ⚠️ 曲线 | ✅ 抽取 |
| 秘密与彩蛋 | ✅ 手工 | ⚠️ 可用生成器"藏" |
铁律:第一印象必须手工。 前 10 分钟、第一个 Boss、第一次转折——这些决定玩家是否留下,不能交给生成器。
9. 反模式
| 症状 | 修法 |
|---|---|
| 生成的关卡"能走但不好玩" | 补后处理修正 + 可读性检查 |
| 玩家报告卡死无法复现 | 必须用种子 |
| 连续几局感觉一样 | 补多样性指标与约束 |
| 难度忽难忽易 | 把难度作为生成参数 + 保底机制 |
| 生成成功率 < 20% | 改修补式生成,别硬重试 |
| 自研通用生成框架 | 用引擎自带,把时间花在语法上 |
| 完全没有手工锚点 | 教学关/Boss/前 10 分钟必须手工 |
| 单次生成 > 100ms | 分块/异步/预生成 |
| 无批量预览工具 | 做"生成 100 个平铺"工具 |
| 只做 L1 布局生成 | L2 内容生成性价比更高 |
| 生成器版本与结果无关联 | 记录"种子 + 生成器版本" |
10. 交付物
- 生成语法文档:产生式规则 + 约束清单
- 五道检查的自动化验证脚本(可解性必须自动)
- 种子系统规格(含每日种子/分享机制)
- 批量预览报告:100 个生成样本 + 质量分布
- 手工/生成边界表
11. 参考
game-tech-art/domains/05-procedural-generation.md(实现侧)- Kate Compton, GDC《Practical Procedural Generation for Everyone》——生成空间与可控性
- 案例:Noita(规则生成)、Balatro(小丑池 L3)、StS(地图生成 L1)、Rimworld(AI 叙事者 + 事件生成)