消失的箭头:一种创作(无)分支剧情的新思路


3楼猫 发布时间:2022-07-31 09:53:00 作者:默颜 Language

引言

我们时常在以剧情为卖点的游戏的宣传中看到这样一句话:你的每个选择都会带来后果。可惜,在见到太多并未守住这个承诺的游戏后,这句话渐渐开始像“狼来了”一样,让人视若无睹。
有时并非开发者不想这样设计,只是分支剧情这个功能,一不留神就会以几何级放大剧本上的工作量;还一种观点认为,现在的玩家大多数甚至都不能通关游戏的第一周目,开发者即使完成了纷繁复杂的剧情树,也鲜有人能体验到,那还不如走个形式,把一本道稍微伪装一下就完事。
那么是否存在一种可能,既压缩编剧方面的成本,又能让玩家作出的选择切实地产生能被感知到的后果?在研究了一些叙事游戏的开发方式后,我发现了不少共通的设计与技巧,或许能解答这个谜题。

Storylet

首先需要引入一个叫做 storylet 的概念。let 作为后缀指“小”,如果要翻译成中文,可以是“故事片段”、“故事块”之类,顾名思义,它指的就是分成块的一个个小剧情片段。不过,这个词即使在英文环境下,也不存在官方的定义,它甚至不在词典里——游戏开发者们可能早已在开发时使用过这样的概念,即便没有听说过这个词。在这里引入它,只是因为方便上下文的指代,并且近几年来人们越来越多地使用这个词来描述这样形式的故事片段,所以它还可以作为一个有效的搜索关键词。
使用 storylet 编写剧本,有着与传统意义上的“分支剧情”完全不同的思路——这里没有分支(所以本文有了这个令人困惑的标题)。取而代之的,每一个 storylet 都有(至少)三个属性:触发条件、事件内容、结果。
那么,一个三选一、各自触发不同剧情的分支结构:
三选一的传统分支结构

三选一的传统分支结构

若用 storylet 等效表达,则是:
等效表达三选一的四个 storylet,注意消失的箭头

等效表达三选一的四个 storylet,注意消失的箭头

事实上,不管是多复杂的分支结构,都能用 storylet 替代(互动小说作家 Emily Short 在这篇博客中给出了更广泛的例子)。各种分支结构里连接各个节点的箭头们,全都消失了。当系统需要“往前推进”故事发展的时候,它不再跟着箭头寻找下一个事件,而是去遍历所有的 storylet,符合触发条件的,就是下一个要进入的 storylet;而事件完毕后,用“结果”中包含的指令来更新状态,紧接着继续寻找下一个事件。当不止一个事件同时符合时,可以选择条件最苛刻的那个,也可以为每个事件设置权重。
这样的过程就是一台不断运转的状态机,在抽象的同时,也为剧本编写带来新的思路。

E N I G M A

让我们用(我用首字母临时拼凑出来的)ENIGMA 框架(Evolving,N
uanced,Interlocked,Generalized,Modular,Adaptive)来讲述六个要点。

Modular / 模块化的

由于事件与事件之间不再由箭头带来“强关联性”,我们可以随心所欲地把任何一个突然进入脑海的故事片段记录为一个 storylet——先填上想到的事件内容,至于触发条件和结果,则可以慢慢想。
对于某一个事件的触发条件,大可以有多种不同的“因”一起促成。设想一个事件——获得进入古代遗迹的机会,触发条件有:
  • 位于古代遗迹门口
  • 门口的石板正在被太阳光照射
  • 主角的智力 > 10,能读懂石板上的指示
  • (若智力不够)主角身边有具备“博学”特性的队友
写完这样一个事件后,无需过早地操心主角是否有机会路过那片地方、天气变化是否足够 / 不够频繁、主角是否有机会把智力加到 10、有多少个队友有“博学”特性、主角有多大概率带着那样的队友……只要我们保证会在其它 storylet 中或多或少地改变这些状态,那么当 storylet 池足够丰富时,这些触发条件迟早能被同时满足。
模块化的另一个好处是,不管剧本写到了什么程度,往里添加新的 storylet 都是非常方便的,因为它通常不会破坏任何已有的 storylet,也没有密密麻麻的箭头需要整理,带来的只是某些状态下更多的剧情走向。正如 Inkle 的创始人之一 Jon Ingold 常说的,他必须“克制住自己在游戏发售前一晚往故事里添加新片段的欲望”,因为对他们的叙事引擎(ink,具体可参考这篇访谈)来说,那么做实在是太方便了。

Generalized / 兼容并包的

Storylet 的触发条件可以宽容、可以苛刻,事件规模可大可小,造成的结果亦可重可轻。有“最好、最可取”的那一档吗?
答案是:没有,全都要。
箭头固然已经消失,但故事的发展仍然需要一定的脉络。易触发的 storylet 适合存放不该被错过的主线事件,而反过来,像刚才例举的古代遗迹那种“看起来有点苛刻,也不知道多少人能撞上”的触发条件,用在锦上添花的支线或是隐藏成就上,就再合适不过了。
量变产生质变,当大大小小的 stoeylet 足够多以后,每个玩家经历的都将是不同的故事。那要如何保证每一个都连贯而又精彩?接下来的几个要点会着重探讨。

Interlocked / 连锁的

我们明明已经消除了各个事件之间的连接,怎么又要求它们互相连锁?其实,这里的连锁指的是“结果”与“触发条件”之间要有呼应、有化学反应。小范围内的强关联被切断了,大范围内的弱关联还是要有。
我们不想设计出完全脱离于大部队的 storylet,不然它就真的永远不会被触发了。时常回顾一遍当下所有被跟踪着的状态,思考是否能放进林林总总的触发条件中去。呼应越多,storylet 们就越乱中有序,逻辑上的连贯性就越好,故事也就越自然。
而对于必须发生的事,也可以采取“饱和式”触发——为了保证事件 Z 的发生,拥有不同且互补触发条件的事件 A、B、C,都将达成事件 Z 的触发条件,而一旦玩家完成了 A、B、C 中的任何一个,其余两个就被禁用,在这一周目中不会再被遇到。这样一来,由于玩家同时错过 A、B、C 的概率为零,事件 Z 的发生也就是必然的了,并且 Z 发生的原因也并不单调,可谓一石二鸟。一个类似的机制:独立游戏 A Short Hike 中,开局需要找到的那把玩具铲子其实很富余,分布在地图的各个角落,找到一把,其他的就会悄悄消失,这么做保证了不管玩家喜欢去哪儿逛,都能几乎无阻力地交差,推进剧情。

Nuanced / 细致入微的

一言以蔽之:什么状态都记。
是的,不管用得上用不上,即使是很微妙的状态,都先跟踪了再说。因为你永远不知道,在灵光乍现时会想把怎样的状态放进触发条件里去,而一旦放进去了,我们方才所寻求的化学反应就有了。回到古代遗迹的例子,假设我们在设计和队友的日常对话时突发奇想:何不把讨论这种古代文字也作为一个话题,可以在与博学队友的日常对话中被聊起?那么此时就可以加一个状态,叫做“和队友讨论过古代文字”。当智力 < 10,身边又没有博学队友时,如果“和队友讨论过古代文字”为“真”,就可以读懂石板上的文字。这合情合理,说不定还能给玩家惊喜。
如果我们积极地在 storylet 的结果中预先标记各种稀奇古怪的状态,那么在设计后续的触发条件时,就很容易头脑风暴出各种为那么做了的玩家量身定制的事件来。
《极乐迪斯科》的编剧 Justin Keenan 把叙事类游戏中的此类反馈叫做 Micro-reactivity(演讲链接:'Disco Elysium': Meaningless Choices and Impractical Advice)。他提出,对于犄角旮旯处难以触发的剧情或文字片段,就算每一个片段只有百分之一的玩家能见到、就算投入在每一个这样片段上的精力(编剧需要写,接着动画、配音等等全都需要跟上)性价比都极低,只要数量上去了,就会有相当的概率被玩家发现,成为他们回忆中的高光时刻,让他们与游戏中主人公建立牢不可破的精神链接,甚至让他们有兴趣开启二周目,寻找更多彩蛋。
Justin Keenan 在演讲中介绍橙色的那条“正常玩家”几乎不可能触发的“迂回”剧情线

Justin Keenan 在演讲中介绍橙色的那条“正常玩家”几乎不可能触发的“迂回”剧情线

Adaptive / 自适应的

其实这一点原本用词是 Parameterized / 参数化的,只是那样的话就组不成 ENIGMA 这个词了。不过仔细想想,Adaptive 或许更合适。
言归正传,要点在于,每条触发条件尽量不要“写死”。
小明是一个有“博学”特性的队友,小红也是。那么进入古代遗迹的那个条件,为什么要写成主角身边有具备博学特性的队友,而不是主角身边带着小明或小红呢?因为日后我们可能会设计更多的队友可供选择,写得宽泛一点,就为这些潜在的改变做好了“自适应”的准备。
同样道理,因为我刚才用的是“门口的石板正在被太阳光照射”,而不是“太阳光直射了石板”,我为“主角智力爆棚,用镜子把本来照不到这里的太阳光折射了过来”这个可能性留了一个后门。这样的宽限越多,游玩时的可操作空间就越大,对那些喜欢不走寻常路、寻找奇妙过关方式的玩家就越友好(虽然这一点听起来更像是沉浸模拟类游戏 gameplay 上的特色,但我认为放在剧情驱动的游戏中也很酷)。
自适应的另一层意思是,storylet 事件中的具体内容,完全可以参数化、与触发条件同步。在触发之前,队友名可以用 XX 替代,一旦触发,所有的 XX 都将被替换成“小明” / “小红”,总之就是那个拥有“博学”特性的队友名。《漫野奇谭》开发者在一次讲座(Youtube视频:“Nate Austin | Procgen in Wildermyth: Storytelling | EPC2021”)中介绍了他们的剧本生成系统,根据一系列前置条件和人物特性选择当下最合适的剧本与台词,思路和我们这里提到的非常像。如果你玩过并记得自己的几个主角如何在漫画里一格格演绎他们的专属故事,那么你或许已经明白这种“自适应”性想要达到的效果了。
《漫野奇谭》中的“剧本生成器”一瞥

《漫野奇谭》中的“剧本生成器”一瞥

Evolving / 自我进化的

这一点硬要算的话可以归入上一点中去,只是那样的话就组不成——啊,还是言归正传吧。
Storylet 内的具体内容是可以根据各种状态而自我调整的,不仅仅取决于触发条件中要求的状态,更应该取决于游戏世界中任意的状态,只要合情合理。
例如,主角说话提及某人时,如果已经认识该人,就可以用姓名来指代;否则,就可以说“那个带着帽子的高个儿”、“那个烟不离手的人”等,从实时的状态中挖掘出特点作为指代词。再比如,若主角曾经在沙漠 / 森林 / 遗迹中短暂地抛弃过队友小明,那么日后主角和小明发生口角时,小明就可以说“当时你在 XX 做的事,不要以为我忘记了”,根据记录过的状态,用沙漠 / 森林 / 遗迹来填入 XX。
一个现成的例子,是《陷阵之志》中由克里斯·阿瓦隆(Chris Avellone)负责的 bark 设计。
在这里插一段题外话:如果你对 bark 的概念感到陌生,不妨读一读我更早的一篇日志:合理巧妙地设计游戏中的 Bark 以帮助游戏叙事。虽然这里我们讨论的是 storylet 而非 bark,但是这两个概念、甚至包括各自的例子,都有着相当多的共通之处。这也是为什么如果你去看《黑帝斯》的对话设计(Youtube视频“The System Behind Hades' Astounding Dialogue”),《看火人》的对话设计(Youtube视频“Interactive Story Without Challenge Mechanics: The Design of Firewatch”),会发现提到的技巧皆与本文谈及的高度重合。从某种角度上看,将 bark 高度抽象化以后,就成为了 storylet。
回到《陷阵之志》,细心的玩家会发现,当我们战场上发生关键事件——如击杀虫子、切断蛛丝、time pod坠落——后,机师或是建筑物内的居民们会说一句话,巧妙就巧妙在这句“即兴”的发言每次都很应景,而个中原因,可以在这篇访谈中找到。简单概括,就是为每一句 bark 都设置细致入微的触发条件,并且活用占位符来指代各种变量
从访谈中的一个例子来看占位符的作用:
It’s the difference between: “Good shot, pilot 3!” vs. “Good shot, Jones. Doing Archive proud!” (Which would be written as “Good shot,
#self_last. Doing #corp proud!”)
“打得漂亮,3号机师!” 对比 “打得漂亮,琼斯!你可真是为 Archive 公司增光了”,哪句能给人更强的临场感,显而易见。
总之,storylet 中等待着被激活的故事片段,可以包含许多需要被填充、被前文慢慢渗透的部分。随着既定事实越来越多、被跟踪的状态越来越丰富,这段故事最终被激活时,就已经“进化”完毕、有血有肉、能够多点开花地呼应前文了。

更多的是自由

讲完 ENIGMA 框架,你可能注意到,虽然我们规定了一些 storylet 之间的呼应方式,并建议要把每个 storylet 里的事件做得灵活可塑,但自始至终都没有谈到这些所谓的“事件”到底要有怎样的结构、以怎样的方式存在。
其实这是有意被略去的一块,因为事件不需要有固定的结构。一个 storylet 中的事件,是完全自由的:它可以是三五行就完事的剧情片段,也可以是一幕,也可以以你一句我一句的对话体存在,甚至可以套一堆更小的 storylet 进去,还可以把传统的分支剧情放进来——实际上这可能是非常强大的一种组合。只要宏观上存在触发条件和结果,不影响大状态机的运作,那么这些处理方式全都可行!至于孰优孰劣,就完全取决于开发时对叙事的要求了。
所以从某种角度来讲,ENIGMA 这个词挺合适的——海量的 storylet 不远不近地共存着,近看很谜,远看很乱,但当大状态机的齿轮真正转动起来的时候,奇妙的秩序终于浮现。
不过,这一套创作方式,也存在着几个大的缺点 / 局限性:
  • 过于庞大的排列组合使得测试变得非常困难。Storylet 数量上去之后,就很难再人工遍历所有可能的故事走向了。
  • 本地化变得很棘手。在一种语言中写好了的、等待填充与“进化”的语料,可能并不是直接翻译就能放到另一种语言中去的。
  • 之前 Justin Keenan 指出的问题非常实际:成本不好控制。作家是可以天马行空地自由发挥了,今天灵感来了,加十个 storylet 都不觉得够;明天重新审视,删掉五个;后天继续随心所欲地创作,反正怎么写都搞不坏这个系统……这套框架非常适合剧本本身的高效产出,但配套的后续工作就很容易被打乱。考虑到这点,或许还是以文字为主要表现形式的游戏最能在这里吃到甜头。

选择的后果与可能性空间

Storylet 的思路配合 ENIGMA 框架,处处都留有让游戏剧本更有机、更能响应玩家选择的机会。而这里附带一些更加普适的建议,以补充回答如何让游戏显得更加“响应式”、如何让玩家发觉故事存在着另外的可能性:
  • 在事件触发时是否要将触发条件也告诉玩家,是值得思考的一个问题。联想游戏中的对话菜单,各家也都有不同的做派。
  • 《神界:原罪2》中因为角色特性而解锁的对话选项,会在左边的中括号内有专门的提示,这样起码玩家知道了这些特性正在以怎样的方式改变这段对话。
  • 《极乐迪斯科》中则有意隐藏了这样的提示,为了让玩家感觉更贴近现实生活中的对话。
  • 《看火人》看似简单干练的对话系统,背后有着复杂的机制来选取当下最有趣的话题,而开发者同样没有把任何凌驾于主人公所知之外的信息展示在 UI 上。结果就是,在游玩时我的确体验到了连贯通顺、代入感强的五小时“步行模拟”,但直到后来看开发者的讲座才知道,原来我的 Henry 与 Delilah 所聊过的,只是游戏准备了的内容的冰山一角。
  • 说到这里,又得提一提《史丹利的寓言》了。作为可能是最“响应式”的叙事游戏之一,试想,如果它从头到尾都有一块 UI 告诉你后台正在记录哪些状态,那么当评论员看似精准地评价你的行为的时候,你还会感到惊喜吗?(当真那么做的话,倒也不失为对电子游戏中所谓“玩家自主权”的一种奇妙解构——反正这多少也是《史丹利的寓言》本身已经在探讨的问题了)
《看火人》主创之一 Chris Remo 指出针对响应机制的处理方式的两种方向——隐藏以获取沉浸感、用 UI 时刻提示玩家

《看火人》主创之一 Chris Remo 指出针对响应机制的处理方式的两种方向——隐藏以获取沉浸感、用 UI 时刻提示玩家

  • 在事件完成后是否要将结果告诉玩家,亦有利有弊。《永恒之柱2》中,做出影响声望的对话选择后,UI 会直接告诉我们这一点。《奇异人生》中的关键分支选完后,屏幕角落会出现蝴蝶振翅的简短图标,暗示这个选择的分量。这的确能让玩家心里“咯噔”一下,期待后续的发展,但是最好不要在这里玩“狼来了”的骗局。
  • 在事件完成后,可以不借助 UI,间接展示其它的可能性,以保护沉浸感。例如:让主人公自言自语“我刚才本可以 XXX 的”。
  • 在关底或游戏结束时给出路线分支图,或是有关选择的统计数据。看到有 X% 的玩家也选择了 XXX,不仅能知道自己有多趋同/异类,也能一瞥其余的可能性。
  • 记录一些连续发生的事件,给予特殊的回应。例如:在那些可以接收打字作为命令的复古文字冒险游戏中,若系统连续 5 次都没能在玩家打下的那句话中找到有效的动词,那么除了告知“无法识别您的指令”外,还可以加上几个有效动词的例子,临时性地辅导玩家推进剧情。同理,《侠盗猎车手 5》中,任务失败若干次后,系统会询问是否需要跳过该段剧情。这个思路也不必总是用在异常状态上,事实上,把它用在司空见惯的小事上效果更好。如果一个商人 NPC 察觉到玩家连续 N 次造访时都没有戴头盔,他大可以说一句“你就这么放心你的脑袋?”,甚至可以临时决定为店里的头盔降价促销。
  • 观察事件发生的时间间隔,给予特殊的回应。《黑帝斯》中,如果这一局结束得特别快,会在复活后遭到特殊的嘲讽,想必是因为游戏计算了你从出生到阵亡的间隔。

结语

游戏叙事从来不存在公式或是万金油,但这也恰恰给了开发者们用来突破的一个口子。时不时地,我们就能看到一些小成本 / 独立游戏靠着好看或是好玩的故事,从层见迭出的 3A 大作那儿夺去玩家们的目光。
仅仅因为“我想讲一个故事给你们听”而决定做游戏,或许也是一件浪漫的事。而我一直相信,互动叙事还存在着很大的开拓空间去成全这份浪漫,让作者能讲得更精彩,听者能听得更入神。希望本文像 ENIGMA 框架一样,乱中有序,为你们带去了启发。

扩展阅读

RESPONSIVENESS IN NARRATIVE SYSTEMS (论文的篇幅相当大,但带来的也是对叙事游戏中“响应度”的巨细无遗的剖析)
《80 days》:如何以软件工程的思路编写一部互动小说(由低多边形厌氧菌于 2019 年发布的文章,本文所说的 storylet 其实本质上和该文章介绍的“故事模块”是同一个思路,只是那篇文章更侧重对游戏 80 days 本身及其叙事方式的讨论。总之,如果你觉得阅读本文有了收获,那么强烈建议也读一读那篇)
游戏分支剧情创作中的挑战和工具(侧重技术实现层面的、对分支剧情创作工具的介绍。出现的几个工具中,ink 尤其适合运用本文中提到的思路)

© 2022 3楼猫 下载APP 站点地图 广告合作:asmrly666@gmail.com