响应系统

From Valve Developer Community
Jump to: navigation, search
English 简体中文

本页面由大康ComaAlanwong35Yakumo koishi正在翻译中。



The Response System(响应系统)用于决定 NPC(或玩家)在想要说什么或是否说什么时应该使用哪种语言(和/或动画)。

Note.png 注意: 本文大部分内容基于 Source 2013 分支。求生之路 求生之路 使用了一个重写的响应系统,它执行大部分相同的功能,但具有不同的优化、路径和实用程序,本文尚未完整记录。此增强系统也适用于求生之路之后发布的所有游戏,包括 求生之路 2 求生之路 2。该系统的代码在异形丛生(Alien Swarm)的创作工具中公开可用。

大多数响应系统用户都是为了响应游戏中发生的事件而发言。语音可以从代码或地图的输入中触发。触发语音涉及响应概念,它对应于系统中的响应。概念是用于特定事件的语音类别,例如注意到危险 (TLK_DANGER) 或看到敌人 (TLK_STARTCOMBAT)。虽然一个概念可以单独用于基本和简单的对话,但语音也可以通过各种标准来触发,这些标准描述了与该概念和/或说话者的当前状态和周围世界相关的事物。这允许复杂的对话树涉及不同情况下的不同台词。

例如,当玩家杀死敌方 NPC 时,HL2 情节系列中的npc_alyx会说出TLK_PLAYER_KILLED_NPC概念。这个概念对于与 NPC 相关的条件或它被杀死的方式有额外的标准。如果玩家通过爆头杀死了 NPC,则响应系统将选择需要该标准的响应,这通常会导致艾利克斯称赞玩家的射击或评价这是爆头。

响应系统通常使用scripts/talker目录中的脚本。当它接收到一个概念及其标准时,它会在响应脚本中搜索与其概念和标准相匹配的规则(rules)。当它找到一个时,它会使用该规则的响应(response)或响应选择。响应可以是声音脚本句子,甚至是实例化的排编场景

尽管有这些优点,但大多数 NPC 默认不使用此系统。例如,npc_pigeon默认只使用声音脚本,不使用响应系统。

以下是使用响应系统的地方的快速列表:

关于代码的注释: 响应系统通常用于从具有CAI_ExpresserHost<>模板类的CBaseFlex派生的类上,该模板类在CAI_BaseActor上自动实现。所有 NPC 和玩家都已从CBaseFlex派生,因此你通常只想使用CAI_ExpresserHost<>,但响应系统可以使用DispatchResponse()函数以更有限的方式在任何实体上使用,这就是env_speaker的工作方式。GetResponseSystem()可用于使概念搜索特定的响应系统树,如果你计划在没有CAI_ExpresserHost<>的情况下使用DispatchResponse(),则必须将其覆盖。

目的

创建响应系统,以便 NPC、玩家等使用统一且强大的系统来管理语音。它不仅允许开发人员和作家创建复杂的对话树,而且还允许模组制作者轻松修改或向游戏添加新语音,而无需编写代码或修改 BSP 文件,同时仍然可以完全控制语音的方式和使用次数。

该系统最适合用于来自 AI 系统的语音,因为这些台词将在整个游戏中被多次说出。 (例如,市民在装填武器时会说些什么。很多市民会在游戏过程中装填武器。)

这是一个来自 NPC 使用响应系统的复杂对话树的示例:

  • I just killed an enemy. 我刚刚杀死了一个敌人。
  • Did I use a shotgun? 我用了散弹枪吗?
  • "Eat shotgun! 吃散弹枪!"
  • Was the enemy really close? 敌人真的很近吗?
  • "You got too close! 你离的太近了!"
  • "Thanks for getting close! 感谢你靠近!"
  • "You're not getting MY head! 你没有得到我的头!"
  • "I hate headcrabs! 我恨猎头蟹!"

你还可以使用标准组合。

  • "You got too close to my shotgun, headcrab! 你离我的霰弹枪太近了,猎头蟹!"

你还可以控制单独的行,使其在一定时间内不重复,或者根本不重复。

构成

Note.png 注意: 'Criterion' 是 'Criteria'(标准)的单数形式。

响应系统由四个核心部分组成:Concepts(概念), Criteria(标准), Rules(规则),和 Response Groups(响应组)。它们的使用方法如下:

  1. 一个 NPC 为一个语音概念(Concept)请求一行语音。
    • 例如,假设我们的 NPC 为TLK_SHOT概念请求一行语音。 NPC 被敌人击中时会说出这个概念。
  2. NPC 收集了一堆反映 NPC 当前状态的标准(Criteria)以及有关世界状态的其他相关数据。许多概念也有修饰符(Modifier),这是特定概念特有的标准,通常反映事件本身。
    • 当 NPC 为TLK_SHOT概念请求一行时,游戏会将 NPC 当前的健康状况等作为默认标准集的一部分进行组合。然后,它附加了概念的修饰符,其中可能包括射击他们的敌人的类型、他们受到的伤害量等。
  3. 概念标准 被传递到 NPC 的响应系统中,该系统通常是所有 NPC 共享的单个全局实例。
  4. 响应系统搜索其规则(Rules)的大列表。
    • 每个规则都包含一个标准列表,该列表根据 NPC 预先设置的标准进行测试。请注意,概念在此阶段被视为高优先级标准。
    • 每个规则都会根据有多少标准是正确的而获得一个分数。如果至少一个标准被标记为“必需”(required)并且不满足,则永远不会选择该规则。大多数标准都设置为必需,但不需要的标准只会提高规则的分数。
      • 在我们的TLK_SHOT示例中,可能有多个包含不同行的TLK_SHOT规则。一条规则可能包含测试“NPC 是否离射击他的敌人非常近”的标准。另一个规则可能会测试是否是特定类型的敌人向他开枪(例如联合军士兵)。另一个规则可能会测试 NPC 是否在射击后剩余的生命值低于 25%。
  5. 响应系统对其列表中的所有规则进行评分,并选择得分最高的一项。得分最高的规则指定一个响应组(Response Group)。
  6. 响应组只是可能的响应列表,每个响应可能是一行语音和/或动画。一个响应根据响应组和个人响应的设置选择。选择有效响应后,NPC将执行该响应。
    • 在我们的TLK_SHOT示例中,假设选择了<25% 健康规则。该规则将有一个响应组,其中可能包含一系列行,例如“One more shot like that, and I'm done for! 再打一枪,我就完蛋了!”、“Oh man, I'm in trouble! 哦,伙计,我有麻烦了!”或“I need medical attention over here! 我需要医疗照顾!”
    • TLK_SHOT的另一条规则可以检查射击他们的敌人是否是联合军士兵,并指向一个响应组,其中包含“That Combine soldier's got me pinned down! 那个联合军士兵让我被压制了!”或“Help me with this soldier! 帮我对付这个士兵!”。另一个规则可以检查敌人是否是联合武装直升机,并用“That gunship is kicking my butt! 那艘武装直升机在踢我的屁股!”和“Someone help me take down that gunship before it kills me! 有人帮我在它杀了我之前拿下那艘武装直升机!”指向一个组。
  7. 如果没有任何规则符合给定的标准[或者所选的反应组没有重复并且已经筋疲力尽(exhausted)],NPC不会说任何话。

概念

concept(概念) 是一个字符串 ,它表示角色语音尝试的高级原因。 代码中定义了一组概念,这些概念将被自动调用,但从技术上讲,概念只是字符跟踪的特殊高级标准。它们与任何东西无关,你可以在响应文件中自由创建你自己的。你可以在代码中或使用参与者的DispatchResponseSpeakResponseConcept输入来调用概念。

以下是半条命 2 中使用的一些预定义 NPC 概念的列表:

TLK_HELLO		当我第一次遇见玩家。
TLK_IDLE		当我被闲置了一段时间。
TLK_USE		当玩家尝试使用(+use)我。
TLK_PLPUSH		当玩家把我推开。
TLK_STARE		当玩家盯了我一会儿。
TLK_DANGER		当我察觉周围有危险(比如手雷)。
TLK_WOUND		当我已经受伤。
TLK_HIDEANDRELOAD	当我打算藏起来然后换弹。
TLK_PLYR_PHYSATK	当我被玩家扔过来的物体砸中了。

不是所有的 NPC 都会说所有的概念,也不是所有的 NPC 在相同的情况下都会说概念。有关完整列表,请参阅响应概念列表

标准集(Criteria Set)

标准(Criteria)是一组条件,其中包含与对话者的当前状态相关的数据,以及每当请求尝试进行对话时概念的情况。它可以被解释为一组 键值。以下是一个由npc_alyx创建的标准集的例子,她试图说话因为她刚刚杀死了当前的敌人:

concept                = TLK_ENEMY_DEAD          NPC 尝试说话的概念。
map                    = d3_c17_07               当前地图的名称。
classname              = npc_alyx                正在说话的NPC的classname。
name                   = alyx                    正在说话的NPC的targetname。
health                 = 75                      正在说话的NPC的生命值。
healthfrac             = 0.9375                  正在说话的NPC的生命值与它最大生命值的比值(默认 npc_alyx 的最大生命值是80)。
skill.cfg              = 1                       目前的 skill 级别。
timesinceseenplayer    = 0.090000                从正在说话的NPC看见玩家时过去的时间。
distancetoenemy        = 312.639679              正在说话的NPC距它当前的敌人的距离。
activity               = ACT_RUN                 正在说话的NPC正在执行的动画活动。
npcstate               = [NPCState::Combat]      正在说话的NPC的 AI 状态。
enemy                  = npc_combine_s           正在说话的NPC的当前敌人的classname。
speed                  = 79.235                  正在说话的NPC的移动速度。
weapon                 = weapon_alyxgun          正在说话的NPC握着的武器。
distancetoplayer       = 211.240692              正在说话的NPC距玩家的距离。
seeplayer              = 1                       正在说话的NPC能否看见玩家。
seenbyplayer           = 0                       正在说话的NPC是否在玩家的视野内。
readiness              = agitated                正在说话的NPC的readiness级别。
playerhealth           = 100                     玩家目前生命值。
playerhealthfrac       = 1.000                   玩家目前生命值的生命值与它最大生命值的比值。
playerweapon           = weapon_shotgun          玩家握着的武器。
playeractivity         = ACT_WALK                玩家正在执行的动画活动。
playerspeed            = 0.000                   玩家的移动速度。

这个概念默认没有任何修改器。上列表中所有的标准都是通用的且是为每个概念收集的。

上面列表中的标准可以通过规则的标准列表进行检查,并用于决定将哪个响应组用于所需概念。比如说:

  • “enemy(敌人)”标准可用于选择对 TLK_ENEMY_DEAD 概念的正确响应。艾利克斯(Alyx)可以说“I took care of that soldier! 我解决了那个士兵!”或“I took care of that headcrab! 我解决了那个猎头蟹!”而不是做一般性说话。
  • 如果她(艾利克斯)在击杀敌人时生命值小于20%,healthfrac 字段(field)可用于选择“Phew, that was close! 唷,太险了!”一句。
  • distancetoenemy 字段可用于她在远距离或近距离杀死敌人时选择不同的语句。比如说“Those guys are scary when they get that close! 那些人靠得那么近就很可怕!”或“It's not easy hitting 'em at that range. 在那个范围内击中他们并不容易。

尽管上面列出的标准是一般性的而不是针对概念而设置的,但标准在不同的情况下总是会有所不同,并且可能并不总是可用(比如说不在战斗中的 NPC 不会有 enemydistancetoenemy 标准)。此外,地图制作者可以为特定的 NPC 或游戏中的所有 NPC 附加额外的标准。有关详细信息,请参阅 #Response contexts

规则标准

根据规则是有一个标准列表的,这些标准会根据人物的标准集进行测试。当规则得到分数(point)时,会根据给定数据检查每个标准,并且该规则会收到成功匹配的标准的分数(point)。用于规则的标准获得分数由标准的权重决定。

标准在脚本文档中的定义格式(见下文):

criterion <criterion name> <key to check> <desired value> <optional: weight X> <optional: required>

参数如下:

criterion name
不得与现有标准匹配。
key to check
该标准将检查的人物标准集中的键值。
desired value
条件集中的键的请求值。以下是使用格式:
  • Numeric values: "0", "1", or "100".
  • Inverse Numeric values: "!=0" (如果值不等于 0 则匹配)
  • String value: "npc_alyx", "weapon_alyxgun", or "npc_combine_s".
  • Enumerated value: "[NPCState::Combat]".
  • 范围(Ranges):
    • ">0" : 如果值大于 0,则匹配
    • "<=0.5" : 如果值小于或等于 0.5,则匹配
    • ">10,<=50" : 如果值大于 10 且小于或等于 50,则匹配
    • ">0,<[NPCState::Alert] : 如果值大于 0 且小于 NPCState::Alert 的枚举值,则匹配。
Note.png 注意: 这默认不支持通配符。
weight X
这是一个可选参数,其中 X 是该标准在匹配时值所得的分数(point)。如果未指定,则标准默认为 1 point。
required
这是一个可选参数,要想使用rules containing,则得需要此标准。如果所需标准未成功匹配,则包含它的规则所得分数会为0并立即跳过。大多数标准都使用此参数。

关于半条命2的一些实例:

  • 下面的例子中定义了一个名为PlayerNear的标准 (这是用于检查与确保玩家在以对话NPC以中心500格的范围内)
criterion "PlayerNear" "distancetoplayer" "<500" required
  • 下面的例子中则定义了一个名为IsCitizen的标准 (这是用于检查与确保说话的NPC是npc_citizen)
criterion "IsCitizen" "classname" "npc_citizen" "required"
  • 下面的例中定义了一个名为IsMap_d3_c17_12的标准,(这是用于检查与确保游戏当在d3_c17_12.bsp上。这也有助于使一张地图中的所有citizen说出与其他地图不同的台词)
criterion "IsMap_d3_c17_12" "map" "d3_c17_12" "required"
  • 下面的例子中定义了一个名为IsBob的标准,(这是用于检查与确保说话的NPC的目标名称为“bob”。这是游戏中独特的citizen,这个标准很容易让他说出特定的台词)
criterion "IsBob" "targetname" "bob" required
Tip.png 小技巧: 概念(concept)是一个标准,其权重几乎总是 5

规则

A rule contains a list of criteria and at least one response group. The rule receives points for each of the criteria that successfully matches the speaker's criteria set. The highest scoring rule will direct to one of its response groups, which is used to determine the exact speech the NPC will use. Rules are defined inside the script files (see below). The following format is used:

rule <rule name>
{
   criteria <criterion name 1> [optional: <criterion name 2> <criterion name 3> etc.]
   response <response group name> [optional: <response group name 2> etc.]
   [optional: matchonce]
   [optional: applyContext <data>]
}

The parameters are as follows:

  • rule name : The name of the rule. Must not match an existing rule.
  • criteria : The list of criteria the rule should score with.
  • response : The list of response groups that should be chosen if this rule scores the highest.
  • matchonce : An optional parameter which, if specified, causes this rule to be deactivated once it has been chosen once.
  • applyContext : An optional parameter which applies a response context. See #Response contexts for more information.

For example, the following text defines a rule called CitizenTalkStare. ConceptTalkStare is a criterion that checks to make sure the concept the speaking NPC wants to speak is "TLK_STARE". IsCitizen is a criterion that checks to make sure the speaking NPC is a citizen. NPCIdle is a criterion that checks to make sure the NPC's state is "NPCState::Idle". If this rule scores highest, the response group that will be used is CitizenTalkStare.

rule CitizenTalkStare
{
   criteria     ConceptTalkStare IsCitizen NPCIdle
   response     CitizenTalkStare
}

Note that the rule name and the response group name can be identical because rule names need only be unique amongst rules, and response groups names only unique amongst groups.

响应组

A response group contains a set of possible responses, along with some optional data that defines how the responses should be used. When a response group is chosen by a rule, a response is chosen from the list and given back to the speaker to use. Response groups are defined inside the script files (see below). The following format is used:

response <response name>
{
   [optional: permitrepeats]
   [optional: sequential]	  
   [optional: norepeat]		  

   <response type> <response> <optional: ...>
   <response type> <response> <optional: ...>
   <response type> <response> <optional: ...>
}

The response group parameters are as follows:

  • permitrepeats : If specified, responses in this group are allowed to repeat. If unspecified, the default behavior is to use all responses in the list before repeating any,
  • sequential : If specified, responses will be used in the order they're listed in the group. If unspecified, the default behavior is to randomly choose responses from the list.
  • norepeat : If specified, once all responses in the list have been played, the response group will be disabled. Any rules that choose this response group will return no response to the speaker.

响应

响应是由系统选择然后由说话者使用的实际响应。响应组可以根据需要列出尽可能多的响应,每个响应都应该以下类型中的一个:

  • speak : 该响应是一个音效脚本或原始音频文件。
  • sentence : 该响应是sentences.txt中的一段句子
  • scene : 该响应是一个.vcd文件。详见场景编排的实现
  • response : The response is a reference to another response group which should be selected instead.
  • print : 该响应是一段在developer 1模式下位于说话者位置生成的占位用响应。
    Note.png 注意: Mapbase Mapbase 默认将其替换为类似于game_text的屏幕信息
  • entityio (存在于自 Left 4 Dead)[confirm] : 该响应是一个I/O事件 ,它以说话者作为触发者(activator)对特定的实体触发IO事件,格式为entityio "<name> <input> <param>"。这与Followup Responses不一样,后者将会在下文进行介绍


Post-response delay parameters

Each response supports a variety of optional parameters.

    • nodelay : After the response has finished, the speaker is allowed to speak again immediately.
    • defaultdelay : After the response has finished, the speaker won't be allowed to speak for a random amount, between 2.8 & 3.2 seconds.
    • delay X : After the response has finished, the speaker won't be allowed to speak for X seconds. X can also be a range, e.g. "5.5,7.5"
  • weapondelay X : When the response starts, the speaker will not fire their weapon for X seconds. Only available on HL2 NPC allies by default.
  • speakonce : Prevents the response from being used more than once.
  • odds X : If specified, then when this response is chosen, there is a chance the speaker will say nothing instead of saying the response. The odds is a (0-100)% the chance of cancelling the response, meaning an odds of 25 gives a 25% chance of saying nothing.
  • respeakdelay : If specified, this response may not be used unless the concept hasn't been spoken in at least X seconds. X can also be a range, e.g. "5.5,7.5"
  • soundlevel : If specified, this soundlevel should be used for the response instead of the default SNDLVL_TALKING.
  • displayfirst : If specified, this response should be used first (ignores the weight parameter).
  • displaylast : If specified, this response should be used last (ignores the weight parameter).
  • weight : If specified, used to weight the selection of the responses in the list. By default, all responses have a weight of 1. Please note that responses won't be repeated until all of the other responses have been chosen, meaning once all of the high-weight responses are chosen, the system will only count the responses of less weight. This can be counteracted with permitrepeats.
  • noscene : Stops the Response System from creating an auto-generated scene for a speak response.
  • stop_on_nonidle : When the response is spoken, stops the scene when the NPC enters a non-idle state. In Source 2013, only works in HL2 episodic mods on scene responses.
  • predelay : When the response is chosen, it won't actually be spoken until X seconds have passed. Only works on scene responses. X can also be a range, e.g. "5.5,7.5"

For example, the following response group is used by citizens to respond to the TLK_STARE concept. Citizens will use the responses in the list in the order they're listed (due to the sequential parameter). Each response, when chosen, stops the NPC from talking for a random amount of time between 10 & 20 seconds.

response "CitizenTalkStare"
{
   sequential
   scene "scenes/npc/$gender01/doingsomething.vcd" delay "10,20"
   scene "scenes/npc/$gender01/getgoingsoon.vcd"  delay "10,20"
   scene "scenes/npc/$gender01/waitingsomebody.vcd"  delay "10,20"
}

Script files

The/scripts/talker/response_rules.txtis the base script file that contains all the criteria, rules, and response groups used by the Response Rules System. The file can also include other files using the #include keyword, which allows you to cleanly divide the rules up according to NPC, map, and so on. Note that some entities, like the env_speaker, specify their own script files that contain a subset of the criteria, rules, and response groups for the entity to use. Seescripts/talker/terminal_pa.txtfor an example used by the terminal announcement at the train station.

响应上下文

响应上下文类似于地图作者设置的标准。它们通过“Response Contexts”(ResponseContext)键值或AddContext输入进行设置,格式如下:key:value;key:value;key:value;……其中key是“键”,value是“值”。

待完善:关于响应上下文的独特部分,还有更多关于响应上下文需要解释的内容!

Followup responses

求生之路 求生之路 introduced "followups", events which occur following the response. They are triggered as response parameters similar to odds, predelay, etc.

Code: The code for the followup system is available in the Alien Swarm SDK, along with the rest of the rewritten response system.
  • fire : Fires an input through the I/O system with the speaker as the activator and caller. Format isfire <target> <input> <delay>. Does not support parameters.
  • then : Causes another response to be dispatched on an entity. Format isthen <target> <concept> <response contexts> <delay>. Used for making characters dynamically respond to each other.
Note.png 注意: A negative delay causes the followup to be dispatched X amount of time after the speaker starts speaking, as opposed to when they're finished speaking.

A few unique targetnames can be used:

  • self : The entity speaking the response.
  • subject : Uses the entity name found in the speaker's "Subject" context, if it exists. The game sets this for info_remarkable responses.
  • from : Uses the entity name found in the speaker's "From" context, if it exists. The game sets this to the name of the previous followup respondent, allowing followups to bounce back and forth.
  • any : Dispatched to any valid respondent within the range stored inrr_followup_maxdist(1800 by default).
  • all : Dispatched to all valid respondents within the range stored inrr_followup_maxdist(1800 by default).
Note.png 注意: The "Subject" and "From" contexts only store entity names, so be careful when there's multiple potential targets with the same name!

Example from Left 4 Dead 2 incoach.txt:

Response _c1m4startelevator4bCoach
{
	scene "scenes/Coach/WorldC1M4B01.vcd"  then mechanic _c1m4startelevator5a foo:0 -2.313 //Son, you got a DEAL.
	scene "scenes/Coach/WorldC1M4B02.vcd"  then mechanic _c1m4startelevator5a foo:0 -5.790 //Ha HA! All the way to New Orleans! Baby, that sounds like a PLAN.
	scene "scenes/Coach/WorldC1M4B05.vcd"  then mechanic _c1m4startelevator5b foo:0 -6.334 //Normally I wouldn't do this. But in these circumstances, I think Mr. Gibbs, Jr. ain't gonna mind.
	scene "scenes/Coach/WorldC1M4B10.vcd"  then mechanic _c1m4startelevator5b foo:0 -2.685 //Forgive us Jimmy, but we need your car.
}

Advanced response rules usage

The Response System can be used in many advanced and specialized ways. Here's a few tips and tricks for advanced usage of the system:

Firing custom responses withDispatchResponse
Absolutely anything can be passed to an NPC as a response concept, so long as it is to be found somewhere in the script files. You aren't limited to the AI's predefined TLK_* concepts at all.
For example, you might want NPCs from a onlooking group to speak congratulatory response concepts when a player successfully solves part of a puzzle.
Player allies in HL2 also have aSpeakResponseConceptinput with more advanced handling and conditions.

See the response scripts for Alyx in EP1/EP2 or the response scripts for the L4D survivors for more examples of advanced response system usage.

调试

待完善:sv_debugresponses

注意

  • 要能够使用响应系统,必须使用由 CAI_BaseActor 类派生的 NPC。
  • 参见scripts/talker/npc_*.txt文件以获取特定 NPC 响应规则的示例。
  • scripts/talker/response_rules.txt是响应规则系统的列表。如果为新 NPC 添加新的响应规则脚本文件,请确保在scripts/talker/response_rules.txt文件的末尾通过 #include 语句包括该文件。

另请参阅

(译注:以下链接链接到英文页面)

外部链接