做过地图生成的人多半遇到过这样的一局:出生点被两堵墙夹住,最近的水源在地图另一侧,或者相反,出门三步就是一整箱高级装备。生成器没有错,它按规则完成了任务,错的是设计者默认“随机”会自然产生好体验。

先分清两种随机

讨论“每局都不同”时,有一个常被混在一起的区别。输入随机是指进入系统的原料被打乱:宝箱放在哪,敌人从哪个门出现,下一张牌是什么。输出随机是指玩家最终感受到的结果本身难以预期:这局到底会赢还是会输,难度是轻松还是残酷。

很多好游戏的输入随机很大,输出却相当稳定:无论怎么洗牌,一个有经验的玩家大体上都能把局面打成“有惊无险”。这样的游戏里,随机提供变化,技巧决定结果。如果输出也随机,玩家就会把失败归因于运气,进而不再相信自己的决策有价值。

顶部一排骰子下方是虚线分区的地图,五个格子用钉子图标固定为锚点,其余紫色格子由随机生成填充。
每局都不同不等于好玩,好的程序化生成会先钉住固定锚点,再让其余区域随机变化。

骰子与地图:均匀分布不等于好分布

骰子给出的是均匀分布,每一面机会相等。放在地图生成里,这意味着资源点、障碍、敌人在空间上都是独立抽样,于是偶尔会出现聚团、空洞与死路。玩家感受到的“不公平”,有相当一部分是这种聚团造成的。

好的生成器给出的是可被设计的分布。举个示例:设计师规定每张地图的资源密度在“每百格3到5处”之间,出生点半径十格内必须有一处水源,且任何两个重要资源点之间的路径长度不得低于某个下限。这些规则并不排除变化,只是把变化限制在有意义的区间里。

约束、生成、筛选

把程序化生成拆成三步,有助于知道问题出在哪一步。

constraints:      # 约束:合法空间
  connected: true
  spawn_supply_radius: 10
  difficulty_floor: 0.35
  difficulty_ceiling: 0.80
generate(seed):   # 生成:在约束内采样
  layout = sample_layout(seed)
  events = sample_events(layout)
filter(candidate): # 筛选:不合格就重抽
  solvable(candidate)
  pacing_ok(candidate)
  not_too_similar(candidate, recent_runs)

约束回答“什么是合法的”;生成回答“合法空间里选哪一个”;筛选回答“这一个值不值得让玩家玩”。三步里最容易被省略的是筛选,很多游戏靠“运气好”发现不了一个无解的局面,直到玩家反馈。筛选还包括与最近几局的相似度检查,避免同一个开局连续出现三次。

划定约束采样生成可解性筛选锚点校验记录并调分布
文中的三步流程加一个反馈环:约束、生成、筛选之后,用结果回头调整分布。

设计师应该保留的锚点

  • 叙事拍点:一场游戏里必须发生的几件事,比如第一次真正的危机、一次道德选择、一次告别。它们出现的位置可以浮动,但不能缺席。
  • 难度上下限:下限保证不会无聊,上限保证不会被系统碾压。
  • 可解性:无论怎么生成,至少存在一条不依赖运气的通关路径。
  • 节奏锚:高压与恢复的比例,参考恐怖游戏里的张力节奏,紧张要靠留白托起来。

没有锚点的生成,像一个没有主题的即兴演奏。有锚点的生成,则像爵士乐:和弦走向固定,旋律可以每次不同。

纯随机的叙事者会出什么问题

《环世界》里三位叙事者的设定很有代表性。据社区维基的整理,Cassandra Classic按递增的挑战曲线安排事件并给出喘息期,Phoebe Chillax灾难间隔更长、更温和,而Randy Random完全随机,可能给出极不公平的事件组合。三种选择同时存在,说明玩家其实并不想要“绝对随机”,多数时候需要的是有意图的起伏。

另一个方向是《矮人要塞》:世界、历史与角色都由程序化生成,故事来自模拟系统内部的相互作用。它之所以成立,是因为底层模拟的规则足够细、足够稳定,涌现出来的故事才耐读,这个结论与本栏目在生成内容与游戏规则一文里的判断是一致的。

AI在其中的位置:调分布,不取代设计

把AI放进这条链路,最合适的位置并不是“替设计师决定一切”,而是根据观察结果调整分布参数。比如系统发现某位玩家连续三局都在中段被资源短缺压垮,就可以把资源事件的权重调高一点,或把下一个危机的出现时间延后;反过来,如果玩家总是轻松通关,就把危机强度的分布上移。这也是PA真人AI在难度与事件调度上的基本取向,与生存危机按玩家策略生成所讨论的思路是同一类:观察行为,改分布,而不是改规则。

示例

示例参数:危机强度基线0.5,标准差0.15;连续两局通关时间低于设计目标的70%时,均值上调0.05;连续两局失败时下调0.05;无论如何调整,均值都被限制在0.35到0.80之间。这些数值只是说明“调分布并设上下限”的形式,并非某款游戏的实测数据。

这里有两个保留。其一,动态调整若不透明,玩家可能觉得系统在暗中放水或加压,所以调整幅度要小,并且要有回看的机制。其二,模型很容易学到“让玩家满意”的捷径,比如一味降低难度,因此锚点里的下限必须写死,不交给模型判断。

落地时的几条顺序建议

先决定哪些必须固定,再决定哪些可以随机;先写筛选条件,再写生成算法;先设难度的上下限,再让AI去调中间的值。PA真人游戏世界智能研究组在评估原型时,会同时记录同一份种子下的多次表现,用来判断差异到底来自玩家决策,还是来自生成运气。资源与生态类的具体做法,可以参考生存资源生态设计,更多同类观察见PA真人AI生存游戏栏目。