故事工程学:人工智能和交互式叙事
交互式叙事(Interactive Storytelling)意指在叙事过程中,故事线的展开并不是固定的,而会根据观众对叙事系统的输入而发生变化,如此在传达故事作者的主旨的同时,让观众产生亲身参与到故事之中的感觉。电子游戏作为一种以交互性机制和多媒体作为媒介的艺术形式,很自然地成为交互式叙事的平台。
交互式叙事在游戏中的运用
在现今的大部分游戏中,从文字冒险中的故事分支到 RPG 中 NPC 面对玩家不同的行为产生的不同反应,我们多少都能看到一定程度的交互式叙事。交互式叙事的目的也多种多样——有的游戏希望借此提升玩家的代入感而获得更好的娱乐体验(例如许多出产自大公司的RPG),有的游戏则是希望向玩家呈现一个线性叙事难以完整表达的庞大而立体的故事,而不得不要求玩家去通过不同的与故事进行交互的方式来探索故事的不同角度。后者的例子包括很多世界观复杂侧重于剧情的游戏,比较典型的例子有 Chunsoft 出品的 428: 被封锁的涩谷,其中作者希望玩家去了解的是发生在整个涩谷、牵涉到众多人物的一个庞大的故事,同时又希望带给玩家从一个特定人物的视角看到的这整个故事的某个局部的体验,因此交互式叙事就成为顺理成章的设计策略。
也有的游戏采用交互式叙事,是希望玩家通过他的亲身参与来更加亲密地进入到作者希望传达的体验,例如著名的独立游戏 Stanley Parable 及其精神续作 The Beginner’s Guide。在这两个游戏中,作者直接与玩家对话,玩家在反抗或者认同作者的选择之中感受到故事的张力和身临其境的情绪体验,从而深入地走进作者的精神世界。
人工智能:一些可用于交互式叙事的新兴技术
虽然交互式叙事在电子游戏中如此普遍地出现,但现今不成熟的技术却制约着它以更加高级的方式出现——对玩家每个动作的反应,几乎都必须人为地一一列举清楚。这就导致玩家在叙事上与游戏的交互方式通常都非常的有限,对游戏中的故事要素的影响也非常有限。另一方面,即使我们拥有足够成熟的技术来毫不费力地处理成千上万的玩家动作输入,也仍然存在一个设计上的问题:过多的玩家自由度与故事主旨表达之间的矛盾。一个故事想要说什么,很大程度是由在这个故事中作者引导观众去观看的那个特定的角度所呈现出来的。如果玩家拥有过于强大的视角选择权,作者又怎么引导玩家去走进这个故事呢。如果一个故事讲述的是英雄救世,玩家却沉迷于跟街上的路人扯淡,这显然也不是作者想要的。因此,就还存在平衡玩家自由度和传达故事主旨的问题。
对于一个电子游戏而言,解决这两个问题,从某种意义上说需要的是同一种技术——人工智能。对于提高玩家自由度的问题,我们需要的是一个能够高效产生叙事内容来应对玩家输入的人工智能系统;对于平衡玩家自由度和传达故事主旨的问题,我们需要的是一个能够根据玩家的行为,智能地调整故事中其他元素(例如NPC)的行动来将故事发展重新引导回重点的“实时导演”。现今的人工智能技术虽然还远远没有发展到能够完美解决这两个问题的程度,但至少有一些前沿的研究向我们展示了一些看起来有前途的新方法。下面我就为大家介绍几种这些新方法,希望能够对各位独立游戏开发者带来启发。
首先,我们来讨论有关高效产生叙事内容来应对玩家交互输入的问题。在现今大部分的游戏中,叙事内容往往都是人为提前安排好的(Predefined)——作者提前定义好玩家可能作出的动作(例如文字冒险游戏中的文字选择支),然后将每个动作发生后的叙事内容(例如文字冒险游戏中的故事分支)定义好。这种产生叙事内容的方式就像是给一个三维立方体的每个可能被观察的角度都拍一张二维照片,然后给定观察的角度输出对应的那张照片,以此来创造观察者观察的是一个三维物体的错觉。这种方法显然是非常低效的,并且因此只能支持很有限的观察角度(玩家动作)。一种真正可行的方法,很显然是保存三维立方体的数据本身,而不是它每个角度的投影。这个三维立方体的数据本身能够比它各个角度的投影精练得多地定义它在各个角度如何呈现它自身。然而在讲故事这个上下文中,什么才是对应于“三维立方体本身的数据”的内容呢?
如何定义一个故事?维基百科上的解释是这样的:
“A narrative or story is any report of connected events, real or imaginary, presented in a sequence of written or spoken words, and/or still or moving images.”
译文:一个叙事或故事是指对一组真实的或想象的关联着的事件的报告,它的表达形式可以是口头或书写的文字序列,或者静态/动态的图片序列。
由此我们看出,一个文字或图片的序列仅仅是故事的表达形式,它的核心在于一组关联着的事件。
而这组关联着的事件在故事中以何种顺序出现,各自以何种形式出现,很多时候可以说并不是故事本质性的属性,它们是可以根据玩家的动作而变化从而产生观众参与性(audience agency)的。
一个故事本质性的属性,仅仅是那组关联着的事件以及它们如何关联。事件间关联的方式可能会对事件出现的顺序和方式有所限制(例如坏人必须先作恶,英雄才能去救世),但大多时候这些限制不会严格到让故事只能以一种序列出现(例如坏人是先杀人还是先放火,其实并不会对故事发展有很大影响)。除了事件的顺序之外,许多事件也可以以很多不同的形式出现而并不会影响故事的发展。例如,如果一个事件只是为了给坏人的邪恶做铺垫,那么在其中坏人掳走的是路人A还是路人B其实无关紧要。
因此我们发现,要定义一个故事,只需要定义这个故事中发生的事件和这些事件相互关联的方式。
在有了这个相当于“三维立方体本身”的故事定义之后,我们就可以根据玩家的行动去动态地生成从他的那个特定角度看到的故事发展序列。例如,恶人先杀人还是先放火可以由玩家先去杀人的现场还是先去放火的现场决定;恶人是掳走路人A还是掳走路人B可以由这两个路人对玩家的好感度决定(谁好感度高就掳走谁,以此来刺激玩家的情感投入)。
那么在实际的游戏开发中,我们如何这样来定义故事呢?为了叙事系统的灵活性,事件的粒度(Grain Size)必须足够小;为了系统能够实时计算叙事内容,事件对于整个故事发展的影响必须定义清楚;事件最好还能具有一定重用性以降低人力需求(Reusability)。事件之间要尽可能解藕(Decouple)以实现模块化的自由组合;事件与它的呈现方式之间要解藕以方便呈现方式的丰富度和日后的扩展;事件呈现方式与其描述最好也能够解藕,这样我们甚至能请不同风格的作家来模块化地写故事(想象未来的某个文字冒险游戏甚至可以在选项中配置叙事风格)。如此听起来,这种写故事的方式是不是简直像是在编程?没错,这的确是类似于编程的活动,因为此时我们的故事已经不是一段扁平的文字序列,而是一个立体、有机的系统。我们这种意义上的写故事也不再是一个纯粹的文学创作活动,而变得充满了工程学。
“A narrative or story is any report of connected events, real or imaginary, presented in a sequence of written or spoken words, and/or still or moving images.”
ABL语言
为了能够进行这种工程学式的写故事,其实已经有很多类似于编程语言的“故事编写语言”被开发出来,这里我来介绍其中的一种:ABL (A Behavior Language,读作“able”)[1]。这个语言的语法类似于JAVA,它也有用JAVA编写的编译器,能够被编译成可以在游戏中指挥三维模型动作和游戏变量变化等的控制程序。ABL中的基本单位被称作Behaviour,一个Behaviour代表一个叙事目标,其内容则是一个不可分割的动作序列,代表要完成这个叙事目标需要执行的步骤。实现目标需要的执行的步骤可抽象可具体,可以具体到一个玩家能看到的游戏中的事件,也可以是另一个子目标。如果一个Behavior下的所有步骤都成功执行,系统就认为这个Behaviour所代表的叙事目标已经达成。在Behaviour的生命中我们也可以定义一个步骤成功或失败情况下的操作。通过定义不同层次的Behaviour,我们就能够实现不同层次的事件极其呈现方式的定义。ABL这个语言被应用在了一个试验性交互式叙事游戏Façade[2]中,有兴趣的读者可以访问链接:http://interactivestory.net/。
ABL代码片段:
sequential behavior AnswerTheDoor(){ WME w; with (success_test { w = (KnockWME)}) wait; act sigh(); subgoal OpenDoor(); subgoal GreetGuest(); mental_act { deleteWME(w);} }
上面所介绍的这种方法,最终还是得由人来描写具体的文字描述(或CG等其它类型的描述)。其实即使在这个方面也仍然有提高效率的余地。当我们的叙事基本模块粒度变得足够小以后,我们就可以实现“模块化的写作”,这意味着我们可以用很多人来分工进行写作。如果模块之间接口定义得足够好,每个人甚至都不需要了解其他人写的那部分故事。甚至我们还可以考虑群众外包式的写作(Crowdsourcing)。事实上也已经有人在尝试这样的创作模式。
另一种可能性则是借助现在热门的深度学习(Deep Learning)。考虑一个架构类似于谷歌自动翻译机(或者谷歌最新的Sequence2Sequence技术)原理的神经网络,构建这样一个训练数据集:它的输入是使用类似于ABL这样的语言定义的一组事件,输出则是一种特定文学风格的对这组事件的文字描述。如果神经网络的模型合适并且训练数据集足够庞大,这个神经网络也许就能学会使用这种叙事风格来将ABL脚本渲染成文字。
在有了定义故事本质的事件和事件间的关联之后,剩下的问题就是如何结合玩家的实时动作输入来生成叙事内容:给定玩家对系统的输入,我们需要选择下一个发生的事件,并确定这个事件的呈现方式;而做选择的原则则是尽可能同时最大化玩家的参与感和故事的精彩程度——我们发现,这实际上是个人工智能领域经典的规划问题(Planning Problem)。
故事的精彩程度取决于很多要素,其中很重要的一个要素是玩家看到的事件于故事主题的相关性。因此只要我们明确定义了每个事件对于故事发展的作用,就能够通过现有的技术计算出对故事发展贡献最大的事件。前面所介绍的内容,很大程度上已经解决了这个问题。
而玩家的参与感则又跟游戏系统中某些局部的要素对他/她的反馈相关,其中非常重要的是NPC对玩家的反应。在传统的游戏中,虽然NPC与玩家之间能够有互动,但在这些互动中NPC做出反应的依据往往只有玩家在当前互动中的那几个动作——NPC对玩家远远没有一个完整的认知。例如在某个剧情事件中,NPC可能会问玩家是选择战斗方式解决还是和平解决,根据玩家的那一个选择,NPC对此再作出反应。这种处理方式很可能造成NPC的态度上的不一致,也常常暴露出NPC对玩家的无知——玩家可能在这个事件之前刚刚进行过疯狂的杀戮,然而就因为在这个选项中选择了和平解决,就受到NPC“爱好和平”的称赞。更加成熟一些的做法是使用某些数值来判定玩家的行为类型,例如在UnderTale中,游戏会存储玩家杀死的怪物数量来判定玩家的暴力程度。但这种方法毕竟无法处理更加复杂的玩家信息。
在理想的情况下,我们希望能建立一个代表玩家的数学模型,随着游戏的进行更新这个模型让它越来贴近玩家在游戏中表现出的方方面面的个性。由这个模型来决定NPC的态度,而不是让玩家简单地通过几个文字选项就让NPC相信他/她是怎样的人。关于如何进行这种建模,我们可以借助许多现有的机器学习方法。例如,加拿大阿尔伯塔大学的一个小组就开发了一个叫做PaSSAGE (Player-Specific Stories via Automatically Generated Events, http://webdocs.cs.ualberta.ca/~bulitko/research/is/)的系统,在其中整合了玩家建模和基于玩家建模的决策系统。在他们为PaSSAGE开发的示例游戏中,他们通过机器学习判定玩家的游玩风格(战斗型、角色扮演型、策略型),然后再根据判定得到的玩家游玩风格来动态生成叙事内容。
结语
近几十年,人工智能技术出现了很多突破,然而笔者却很少看到最新的技术被应用到游戏开发中。这些技术带给了游戏开发者非常多的可能性,希望这篇文章能够引起大家去探索那些新技术的兴趣。