行为决策系统:龙腾世纪的实用评分架构

31.1 Introduction
龙腾世纪的实时战斗序列使玩家得以控制英雄审判者同死灵、恶魔和巨龙战斗。这是一个艰巨的任务,但玩家并不孤单,同玩家一起战斗的还有三个AI控制的单位——The Iron Bull,身材高大的斧头雇佣兵;瓦里克·特瑟拉斯(Varric Tethras),一个轻声细语的矮人;多利安·帕乌斯(Dorian Pavus),一个迷人而机灵的法师。
在龙腾世纪中,战斗是由“能力(abilities)”驱动的。一个典型的战士拥有2到20种能力,从简单的“用持有的武器攻击敌人”到精心设计的“向敌人进行火力覆盖”。每种能力都有相应的“费用”,这些“费用”以“法力”或“耐力”之类的可消耗资源表示。由于法力/耐力是有限的,所以能力也具有隐含的机会成本——当前能力会消耗的法力/耐力不可避免的会影响之后可能会使用的能力的选择。这在玩家和AI单位形成了一个具有挑战的问题:当面临有限的资源,多种选择以及不断变化的游戏状态时,战士如何迅速确定将产生最大可能收益的行动方案?对龙腾世纪,我们创建了一个基于实用性的AI系统,称为行为决策系统(BDS),以应对该问题并处理战士必须执行的复杂决策。 在本章中,我们将描述BDS的原理和体系结构,为您提供实施类似系统并扩展其满足您自己游戏需求的必要信息。
31.2 The Behavior Decision System
BDS系统架构由以下几条假设组成:
在任何给定时间,AI角色都可以执行有限的一组动作。
一个AI单位在同一时间只能执行一个动作。
动作具有不同的效用值,有些动作比其他动作更有效。
可以量化每个动作的效用。
综合考虑,基于这些假设自然而然能想到通过一个简单的贪心算法来确定AI单位的最佳行动方案:首先确定合法可采取的行动。然后,评估每个动作并根据其效用为其分配分数。 在评估完每个动作之后,得分最高的动作就是应该采取的动作(Graham 2014)。
这种方法有两个主要挑战。 首先,一个AI角色如何枚举它可以执行的所有动作? 其次,AI角色如何限定动作的效用? 在AI角色可以应对这些问题之前,我们必须首先赋予它知识——对自身及其所处世界的知识。
例如,考虑一个简单的动作,例如“喝生命药水”。大多数人类玩家都知道,健康状况不佳时喝生命药水很有用。不幸的是,AI角色无法直观地理解生命,死亡,健康和治愈药水等概念。他们不知道活着是“好”,而死是“坏”。 他们不了解在健康状况低下喝生命药水是好的,在健康状况下喝生命药水是浪费的。 而且他们不理解生命药水是消耗品,除非拥有生命药水,否则不能喝生命药水。
在最基本的层次上,BDS是一个框架,允许游戏设计师将知识传授给AI角色。具体来说,BDS的存在是为了应对以下这些问题:AI角色可以执行哪些动作?他们在什么情况下可以执行这些动作? 应该如何处理这些动作之间的优先级?最后:这些动作实际上如何执行?
31.3 Enumerating Potential Actions
在DA:I中有超过60种能力,但其中许多能力可以以不同的方式来实现不同的目的。例如,“Charging Bull”能力可以让战士冲进战场中,造成伤害并击退任何阻挡在路径上的敌人。这是预期的、明显的目的。但是,这种相同的功能也可以用作受伤的战士快速撤离战斗的一种方式。尽管基本能力是相同的,但使用该能力的动机却可以完全不同。因此,在列举潜在动作时,仅计算角色可使用的能力数量是不够的——我们还必须包括执行这些能力的各种方式。为了区分使用能力的各种场景,我们定义了一种称为“行为片段”的数据结构。
行为片段是BDS运行的基本单位。每个片段均包含AI角色以特定方式评估和执行能力所需的信息。从某种意义上讲,片段代表了知识的一部分,并且在整个游戏中,可以通过BDS将片段“注册”到角色,从而将知识授予角色。例如,一件武器可能附带一个或多个行为片段,这些片段告诉AI角色如何使用该武器。当AI角色装备武器时,这些片段将通过BDS注册到角色。类似地,当不配备武器时,片段将从该角色中取消注册。
行为片段使BDS可以简单地枚举角色可用的动作列表。 只需查看一组已注册的片段即可。DA中最复杂的AI角色:同时注册了50多个行为片段,平均每个AI角色将注册10–20个片段。
31.4 Evaluating Behaviors
一个行为片段包含Ai角色在特定场景下需要评估和执行能力所需的信息——但这究竟意味着什么?如前所述,BDS基于以下假设:可以量化每个动作的效用。为了使这种假设成立,每个行为片段都必须在其中包含一种量化其所代表动作的效用的方法。量化效用的方法有很多种,但是对于DA,我们选择使用经过修改的行为树(称为“评估树”)来表示效用。
31.4.1 Calculating Utility
用最广泛的术语来说,评估树的目的仅仅是为其相关的行为片段生成一个得分值。之后这些分数会被当做比较两个行为片段的基础,以对它们的有效性进行排名。得分值是通过嵌入评估树本身的“得分节点”分配而来的。当树从其根节点开始执行时,得分初始值为零。当树从一个节点前进到下一个节点,它执行的任何计分节点都会将其值添加到树的总分。
评估树是“在上下文中”进行评估的,也就是说,树中的节点可以访问诸如正在执行评估的AI角色之类的信息。这样就可以创建一个可以根据不同“上下文”场景产生相对应分数的评估树。(Merrill 2014)。例如,图31.1显示了一个评估树,如果评估角色的生命值小于50%,它将返回5分,否则返回0分。

在构建评分系统时,我们考虑了各种用于评分值自动归一化或缩放的方案。最终,我们选择使用(并建议使用)面向设计师的评分规则,来提供一个规范动作之间如何进行评分的框架。注意,这些规则是内容创建者的指导,在游戏数据中没有明确的表示。表31.1给出了一个示例。

设计者有责任为每个代码片段构建评估树,有条件地分配分数,以使树在适当的范围内动态生成值。在DA中,每个动作类别使用一组不同的评分逻辑资产(scoring logic assets),以返回适当范围内的分值。例如,“Support”动作的评估树拥有25个初始基准点,然后在上下文环境中有条件的提升到最高值45。
31.4.2 Target Selection
DA中大多数能力都需要有一个目标来驱动。例如,一个AI角色不能简单地“施放献祭”这个动作,他们必须对特定敌人进行该动作。选择的目标会影响执行的能力的结果(即效用值)。考虑:向虚弱的目标施放献祭会造成重大伤害,而对具有免疫力的目标施放献祭只会浪费法力。因此,目标选择是评估步骤的必要部分。 为了准确表示某项行动的价值,我们必须考虑该行动的所有潜在目标,然后选择可以提供最大效用价值的目标。因此,BDS系统不仅仅返回一个值,还包括一个目标。
评估树的上下文性质允许我们可以通过引入“目标选择器”节点来添加目标选择逻辑。该节点遍历设计师指定的目标列表,分别评估和指定分数。图31.2展示了一个使用目标选择器节点的评估树。

目标选择器节点维护其当前临时评估状态(evaluation state)和记录表(record table),并根据以下算法执行:
将评估上下文(evaluation context)的当前分值记录为“初始分值”。
对于迭代器数据指定的每个可定位目标(targetable):
将上下文的分值重置为初始分值。
将上下文的“行为目标迭代器”插槽到当前可定位目标上。
评估孩子节点。
如果孩子节点返回 true,则记录迭代器当前可定位目标的上下文分值。
如果至少一个可定位目标有被记录的评估分值:
将上下文的分值最高的行为目标(Behavior Target)插槽到可定位目标上。
将上下文的分值设置为与该目标相关联的分值。
返回 true。
如果没有记录有评估分值的可定位目标,则返回 false。
在这种方式下,通过比较多个目标,选择其中能在每个行为片段上得到最高分值的目标,让其与BDS核心评估表对应的行为片段进行关联。
31.4.3 Comparing Snippets
作为AI角色更新的一部分,每个已注册行为片段的评估树都会运行,并将由该树生成的分数和目标与代码段一起存储在摘要表中。运行完所有评估树后,将选择记录分数最高的片段来执行。 通常在AI的每个更新周期中循环执行此操作,但可以根据需要选择性执行。列表31.1包含此评估步骤的伪代码实现。

31.5 Execution Step
确定了得分最高的片段和它能力的目标后,最后一步就是执行该片段。正如每个片段都包含一个评估树以显示应如何评估该行为一样,它也包含一个行为树(称为“执行树”(execution tree))以显示应如何执行该行为。执行树负责为一个动作在其播放动画和游戏逻辑之前,处理好所需的全部准备或定位——该动作的“主动执行(active execution)”。
如评估树一样,执行树在被执行期间可以访问上下文信息。具体来说,BDS会公开在评估阶段被选择的目标的信息,以及同该片段相关联的能力。为了简化执行树,我们定义了一个名为“执行能力(Execute Ability)”的任务节点,该节点功能为激活AI角色,使其执行针对上下文指定的目标使用上下文指定的功能。图31.3显示了一个典型的“移至范围内并攻击”的执行树。

在上下文中存储有关能力和目标的信息(而不是在执行树中显式引用它们)可使执行树保持通用性,从而使它们可在多个不同的片段中复用。例如,图31.3所示的执行树可以应用于“猛击”、“刺击”或“撕咬”等能力——只要该行为属于近战。
在每次AI更新阶段,将执行在先前BDS评估阶段中选择的行为片段的执行树,直到触发“Execute Ability”节点,表明该行为的执行已完成。然而,在AI角色执行特定片段时候,BDS可以继续进行评估阶段。以这种方式进行重新评估(Reevaluating),可以使AI角色适应不断变化的环境,及时更新并执行新的不同的片段,而不会盲目的执行已经选定的过时的片段。实际上,评估和执行逻辑之间的协约是一个评估树,且该树负责识别和防范执行树指令无法正常执行的情况。在无法完成执行树的情况下(例如,如果执行目标在使用该能力之前就死了),则重新评估可确保将当前无效的片段被替换为有效的片段。话虽这么说,一旦一个AI角色触发了“执行能力(Execute Ability)”节点,就可以暂停AI更新,直到该能力完成执行为止。 这样就不会浪费资源在那些“AI角色被占用时无法使用”的决策。
31.6 Movement and Passive Behaviors
尽管BDS最初旨在优先处理,准备和执行离散的动作,但是在开发DA的过程中,我们发现BDS评估执行框架对于调节正在进行的或“被动的”行为也很有用。
例如,在DA中,如果玩家的AI队友无事可做,那么无论玩家走到哪里,他们都只会跟随玩家。这个行为通过注册一个片段到BDS中来实现,该片段的评估树返回一个比任何动作都要低的固定分数”(例如,在表31.1的评分系统中分数为0),并且该执行树只会触发“跟随领队”这一行为。这个片段会在其优先级达到最高时由BDS自动调用(即,没有其他分数大于0的片段是可执行的)。
该方法的进一步应用——就像战斗能力那样——通过条件化评分逻辑,使BDS在上下文相关的运动行为之间进行选择。DA通过这种方法来对跟随者的行为进行变化,在战斗时或者命令跟随者前往某个确定的位置。这些有条件的评估方法比基础行为具有更高的优先级,同时处于激活行为的次一级地位。
该方法对创建具有高优先级的行为片段也十分有效,因为这会抑制其他可行的行为。DA使用这种方法来让角色留在休息区。对于这些角色,我们创建了一个行为片段,其执行树会迫使AI角色返回其指定区域的中心。相应的评估树返回的分数高于任何其他战斗能力,但仅当角色位于其指定区域之外时才返回。通过这种方式,可以确保当AI单位偏离指定位置太远时,可以立即脱离当前目标并返回,而不是越跑越远。
31.7 Modularity and Opportunities for Reuse
通过使用行为片段,BDS强调了AI设计的模块化方法。模块化方法有几个好处。在调试时,它允许开发者轻松地隔离特定行为的评估逻辑,或通过检查评估步骤的结果来比较AI角色的相对优先级。
模块化设计还能够使行为在AI角色和原型之间轻松的迁移和共享。DA:我利用这一特性让人类玩家能够自定义它们的AI同伴。在整个游戏中,玩家可以添加、移除和修改AI角色的装备和能力。通过将行为片段与装备和能力资产绑定,并遵循一致的评分系统(如第31.4.1节所述),我们可以确保AI角色能够根据自己的命令有效地使用装备和能力,而不管这些装备和能力是什么。
尽管模块化设计的初衷是为了玩家控制的队友,但该设计也可以应用到敌人AI角色上。在我们的敌人AI开发中,发现针对特定AI角色开发的能力和行为可以很轻松的迁移到其他角色上,只要相关资产(如动画和视觉特效)也适用于新角色。
为了支持BDS的模块化设计,需要特别射线评估树和执行树的数据结构,以便它们可以跨多个行为片段复用。在开发DA时,我们发现大多数行为片段可以复用相同的行为树资产,只有小部分复杂的行为需要特定的评估树或执行逻辑。通过将经常复用的子树分离成独立的行为树资产,供其他树引用,可以进一步解耦,提高复用,降低持续维护成本。
31.8 Conclusion
本章介绍了一种决策行为系统(BDS):一个简单高效的支持复杂AI行为决策的框架。该系统核心是是“行为片段”—— 一种数据结构,封装了评估和执行离散操作所需的信息。片段使用行为树进行评估和执行,“评估树”是经过修改的行为树,它返回一个实用程序得分和一个目标,而执行树包含执行操作的必要指令。
在运行时,行为片段可以通过BDS注册到AI角色,每个注册的片段代表角色可以执行的单个动作。通过将这些代码片段作为角色更新循环的一部分进行评估,并定期执行产生最大效用值的片段,BDS会产生定向的、有目的的和反应性的行为模式。