《The Last Of Us》的同伴AI(一):非战斗跟随AI
本文大部分内容都是翻译自Max Dyckhoff在GDC 2014中的一篇演讲,演讲题目是《Ellie- Buddy AI In The Last Of Us》,从多个角度去向大家介绍了《最后生还者》中艾丽同伴AI的做法。
题目中的Buddy AI翻译过来就是同伴AI,同伴AI在很多大作里都有出现,比如顽皮狗自家《神秘海域4》中的山姆·德雷克、《失落的遗产》中的Nadine、今年索尼《战神》中的儿子阿特柔斯等等,在这些时刻陪伴在玩家旁边的角色上使用的AI就是同伴AI。
同伴AI的作用不言而喻,同伴可以帮你战斗、可以跟你聊天、平时会在旁边游荡、玩家陷入谜题的时候又会提供帮助,同伴AI涉及的范围相当之广,而且根据玩家当前的行为会有不同的AI。而且在功能性之外,同伴AI也是用来刻画人物性格的重要工具,合情合理的AI才能让玩家代入到游戏中去。
原演讲的内容相对比较口语化,所以我会把核心内容整理翻译之后,以可读性比较高的描述方式写出来,部分章节我会插入原演讲的PPT截图以方便阅读、部分内容可能会加上我自己的一些理解。演讲的文字量相当大,所以比较方便阅读我会分成几个章节来写,有兴趣的话还可以到原链接里去看:
演讲的官方音频链接:http://www.gdcvault.com/play/1021010/Ellie-Buddy-AI-in-The-Last-of-us
演讲的官方PPT链接:http://www.gdcvault.com/play/1020364/Ellie-Buddy-AI-in-The-Last-of-us
演讲的视频有人搬到B站了:https://www.bilibili.com/video/av8176561/
目录
第一章 同伴AI的设计思路(当前章节)
第二章 非战斗状态下的跟随AI(当前章节)
第三章 战斗状态下的跟随AI(翻译中~后续更新)
第四章 艾丽的战斗AI(翻译中~后续更新)
第五章 (翻译中~后续更新)
第六章 (翻译中~后续更新)
第一章艾丽AI的设计思路
1 我们为什么需要同伴AI
从很多方面来说,艾丽跟我们玩家是很非常非常像的。与乔尔不同,艾丽跟玩家一样都是刚刚才开始接触到这个充满瘟疫的世界,艾丽跟玩家一样会害怕那些感染者,艾丽厌恶战争,艾丽之前从未感受过这种末日世界里人类还要互相残杀的情景。至少对我而言,艾丽是一个充满真实感的角色。
我们在创造艾丽这个角色的时候,有很多东西是需要避免的。在一些具有同伴AI的游戏里,玩家经常感觉到自己要去保护同伴,需要时刻担心同伴的安危,看他是不是被困住了、是否需要援助他。而我们不想这样,我们反而希望艾丽是一个能帮助玩家的角色,艾丽不会令你觉得讨厌、乔尔(玩家)也不会埋怨艾丽。总而言之,她是玩家真正的同伴,而不是玩家通关游戏的累赘。
所以接下来,我会讲到我们用怎样的一个系统来创造艾丽的AI。当然我只会挑一些重点和基础的设定来说,希望大家可以理解我们做这个AI系统的思路,然后去思考进一步的设计。
我们最初在2013年1月公布了《最后生还者》,并且给大家提供了大概20~30分钟试玩版本。但经过那次测试我们发现,艾丽的同伴AI并达不到我们的预期。然后我们就决定延期游戏的发售,我们额外花了五个月的时间去重做了AI。
我们希望乔尔和艾丽在战斗中是互相协同、互相扶持的,我们希望战斗是更有情感冲击力的。战斗中遇见的感染者会让人害怕,但害怕的原因不仅仅是因为感染者在攻击你(乔尔),还会因为你害怕你的朋友(艾丽)会遭到感染者的攻击。我们希望你的同伴会至始至终都在任何遭遇中陪伴着你,这就是情感的表达方式之一。
在最初的版本里,上面说到的这些东西全部都是直接写到角色的代码里。但我们整个游戏不可能只有一场战斗,乔尔和艾丽在后面还有经历很多很多的事情。直到那时候我们才意识到,我们需要做一个同伴AI、用AI来应对大部分场合。虽然我们已经之前已经做了一些综合性、能广泛使用的AI,但那也不是我们最终想要的体验,所以我决定重新回到起跑线,在距离发售还有5个月的时候重新开始做同伴AI。
但幸运的是我们足够优秀的团队,我们有非常出色的物理系统、运动系统、动作系统和寻路系统,所以同伴AI其实就是在这些基础系统上额外做文章。
开始同伴AI的工作时,一般我们都会想到战斗AI,但我们想优先把位置关系AI做了.比如说艾丽会倾向于待在乔尔的旁边、而非靠近那些可怕的感染者。只要完成了这个位置关系的AI,艾丽的同伴AI实际上已经会有明显体验了。
所以我开始重点关注艾丽跟乔尔之间的关系。我们想让玩家感受到他们两人之间是如何共同去应对困境,乔尔作为玩家控制的角色是如何去关心艾丽,之后艾丽又是如何反馈乔尔的帮助,艾丽如何回报乔尔等等。所以我跟Bruce(Max的同事)花了很长的时间去讨论艾丽的之前的经历、艾丽跟乔尔结识之后发生的一切、艾丽一直跟着乔尔走的原因等等。
2 艾丽AI的设计方向
我们想做的第一件事就是让艾丽更靠近乔尔。
这有很多很多的好处,如果让艾丽远离敌人的话会让我们的敌人AI更难出错,这个等下我们在后面的章节会讲到;如果让艾丽距离乔尔太远、不主动靠近你、不跟你聊天,你可能会开始忘记她的存在,再加上我们的游戏场景到处都是废墟、被毁坏的建筑、荒地,玩家可能就会有一种废土中身陷孤独的感受,这并不是我们所预期的游戏体验(毕竟顽皮狗不是在做辐射系列)。我们希望的是让玩家保持对艾丽的关注,并且会想要照顾艾丽(毕竟艾丽设定的年龄跟乔尔的女儿相仿),同时也方便艾丽对乔尔进行交互。
第二点就是我们希望艾丽是有用的。
艾丽应该不仅仅作为乔尔的一个保护对象,艾丽会在战斗中、或者一些解谜场景中会帮助乔尔。当然艾丽能够做的事情有限,但艾丽会随着游戏进程的推进会越来越有用,至少她不会是一个累赘。
第三个方向就是我们想让艾丽在战斗内外都会很有趣。
我们为她制作了一套特殊的动画,让艾丽在战斗中和非战斗时间内都有不同的动作表现。除此之外还将艾丽的聊天系统加强,艾丽与乔尔在战斗中的对话会明显跟战斗外有不同,艾丽的谈话内容、发声方式都会不同,并且随着游戏的进程会进一步看到差异。
除此以外,还有一点我必须要强调一下:我们不想在艾丽上作弊。
作弊就是指我们在代码上赋予艾丽一些特殊且高级的规则、甚至是超越了乔尔可执行行为范围之外的规则(比如后文会说到一些瞬间转移的设定)。乔尔是玩家的控制角色,是一个高度理性的角色,他在游戏世界有一系列的限制条件,我们希望艾丽也要遵循这些规则。因为即便艾丽是一个系统控制角色,我们也希望艾丽的一系列行为都是合理的、能让玩家信服的,而不是通过作弊来额外给艾丽提供特殊行为。总而言之就是,我们希望艾丽在游戏世界里是一个相当真实的角色,真实这一点将会在整个游戏进程中有所体现。
接下来,我们从第二章开始就依次来说说上面这几点具体的做法了。
第二章 非战斗跟随AI
这一章我们来讨论艾丽如何在非战斗的环境下跟随乔尔,以及在跟随乔尔的过程中会触发什么样的逻辑。
1 艾丽不会使玩家卡关
首先要说的是,如果艾丽跟乔尔同时位于一个场景里,艾丽的行为看起来不能比乔尔更笨。也就是当玩家陷入一些困难的时候,玩家首先不会去选择责怪艾丽,艾丽绝对不能成为玩家卡关的原因。当然如果剧情需要的话那就另说,比如艾丽本身的设定就是不太会游泳,玩家也就只能控制乔尔去想办法渡过难关,我们讨论艾丽的AI时不会包括这些内容。
所以,如果可能的话,艾丽一般会在玩家所视范围内活动,并且一般只会距离乔尔几米远。如果玩家在一些关卡上遇见难题或者挫折时,都应该会归因到自身而非归因到艾丽身上。比如说在一些潜行关卡,一般来说感染者发动攻击时都是因为乔尔(也就是玩家)暴露了位置,而艾丽一般都会紧跟在附近的掩体处、并且很难惊动感染者。
2 艾丽会触发对话逻辑
此外,如果艾丽靠近乔尔,艾丽就会触发一个较为复杂的对话逻辑,具体的细节我在后面章节到,但我可以提前告诉大家的是,这些对话的触发可以取决于当时场景中的情况,比如当艾丽和乔尔靠近敌人、且乔尔处于一些危险位置时,艾丽就会说一些像“小心!”、“前面好像有感染者”之类的对话,当两人在并肩赶路时,艾丽有时也会主动找乔尔聊天。
这个AI进一步去强化了游戏进程中的体验,你可以试想一下,当乔尔已经习惯于艾丽在他身边之后,游戏在某些关卡因为剧情的需要而把艾丽拿掉了,然后过了一段时间艾丽又重新回到乔尔身边、并重新激活上述的种种互动时,乔尔的心路历程就会是:
艾丽在乔尔身边,乔尔感到放心
艾丽离开了乔尔,乔尔感到一些孤独
艾丽还没回来,乔尔开始感到不安
艾丽回来了,乔尔:Holy shit!I'm so glad she's back!
在这个过程里,玩家会身临其境地感受到乔尔和艾丽之间的羁绊。
3 乔尔身后的跟随范围
接下来再看另一个设定:跟随范围,这决定了同伴AI如何去让艾丽跟随乔尔。我们会在乔尔身边设定一个跟随范围,并且让同伴AI获得乔尔目前所在位置的坐标。
跟随范围的区域细节非常多。首先它是一个范围较广的弧形区域,可能会在乔尔身前、也可能会会在乔尔身后,在不同环境下的区域面积会不一样。乔尔身边障碍物的多少也会用来调节范围的大小,当周围障碍物比较密集时,可跟随区域就会小一些。
然后我们会通过计算乔尔和艾丽的移动速度来进一步确定范围大小,有些地方我们希望乔尔带着艾丽快速过场、有些地方我们希望他们会停下来观察四周,不同场景都有不同的做法。
而随着玩家的游戏进程,跟随范围会不停在变化。比如在玩家接近于战斗时我们会把跟随范围收紧,周边很安全的时候这个范围可以相应扩大一些。
总结起来就是,根据乔尔的位置、当前所处的场景、周围单位的多少和类型,给艾丽的AI定义一个跟随范围。
4 通过发射射线来确定跟随坐标点
一旦我们确定了跟随范围之后,我们就进入下一步:发射射线。
我们会在范围内以扇形的方式去扫描一些坐标点,一些我们认为看起来不会很蠢的坐标点(比如一般不会站在垃圾桶或者死掉的感染者旁边)。然后再去按照权重去选择一个点,这个点就是同伴AI中希望艾丽前往的坐标点。我们会根据角色站位的方向、角度,以及角色距离危险或者同伴有多远,来分配坐标点的权重。
这个发射光线比较复杂,单单这么说会很生硬,我下面用一个例子来说。
这里图中蓝色的点表示乔尔的位置。在这个场景中我们希望艾丽是跟在乔尔后面的,所以经过我们先前的一个步骤已经确定好了一个弧形的跟随范围。那么艾丽具体要跟在这个弧形范围的哪里呢,我们一步一步来看:
为了逼真,我们给这个场景再加入一个障碍好了,这块灰色的矩形就表示一堵不能通过的墙壁,墙壁的存在会把跟随范围进一步减小。
然后我们以乔尔所在的坐标点为中心,向外弧发射射线,图中这里为了表达清晰所以只显示了5根线,实际上我们在代码里用到的会更多。如果这根线在过程中碰到了障碍物,那这根线就会被删掉,我们只保留没有碰到障碍物的线,比如图中绿色的这些。
我们取得外弧和射线交点的坐标,然后进入下一步。
然后我们以这些坐标为中心,朝乔尔坐标的垂直方向发射射线,如图所示:
射到障碍物上的射线我们会弃用掉。为什么要这么做呢?
我们想象一下我们的日常场景,当我们在跟随一个人时、或者刚刚追上一个人时,我们大概率不会面向墙壁,就算我们靠在墙壁上等人的时候也大多面向外侧。也就是我们会考虑到艾丽到达这个点之后、下一步再去跟上乔尔时的朝向,我们希望做得更自然一些,所以这些面向障碍的点我们是不会用的。经过了这一步,我们在这就剩下三个候选坐标点了。
然后我们在这三个候选坐标点的射线方向取一个距离,这个距离意味着艾丽跟上乔尔之后,短时间内可能前进的范围。这三个距离都会对应一个坐标点,我们把乔尔的坐标跟这些坐标点连接。如果能确保乔尔等会是可以看到艾丽的,那么这些坐标点都是可行的。
如图所示,这三个坐标点其实都是目前为止我们可以使用的坐标点。
这个例子就暂告一段落,我们再看另外一个例子。
乔尔的位置和弧形的跟随范围不变,但我把障碍物变得更小了一些:
然后按照上面我们说的步骤一步步去做,得到这样的结果:
从这个图中我们可以看到,左边的那个点就会存在一个问题,当艾丽往乔尔的大致方向移动后(艾丽移动时必然是朝大致的方向移动,肯定不会是直挺挺地朝乔尔移动),有可能就会跟乔尔相隔一个障碍物,这就是我们上面说到的那些很蠢的点。所以我们会在最后一步在乔尔身上发射出射线,确保艾丽在移动之后还能看到乔尔。
在游戏的场景中我们可能会有大量障碍,大量分割空间的房间、院子、围墙等等,通过我们上面的做法就可以保证艾丽能够跟着乔尔进入同一个空间。
我们再来看一个实际画面的例子。
下面的图就是乔尔和艾丽,以及旁边那些用框框标出来的障碍物。橙色的点就是艾丽AI里候选的坐标点,如果你仔细看的话还能看到上面的权重值,这跟每个点的角度、目标值之类的东西有关,这里就不展开了。
然后通过这张图你会发现一个很有趣的东西:艾丽站的坐标点并不对,艾丽坐标点射出的射线是红色的(因为射到了中间那辆车,车是障碍物)。
我当时在截这张图的时候慢了一拍,在截图前的一秒钟我其实移动一下乔尔。也就是说当艾丽站在一个正确的坐标点之后,乔尔又再次移动了。你们可以注意到,艾丽脚下的那个坐标点不是橙色,而是红色,坐标点的射线也是红色,而非绿色,理论上艾丽应该前往那些橙色的坐标点,而她却没有移动。大家不要认为这是个BUG,艾丽停留在这个地方是有合理原因的。
我猜你们应该想到了,接下来要说的是:艾丽的移动时机。
5 艾丽的移动时机
你可能会在其它游戏里见到一些非常活跃、甚至是很狂躁的同伴角色,它们不停在动,甚至还会尝试去挤开你,根本不管你在干什么,你也不知道他们在干什么,你能见到的就是他们一直在从A点走到B点,但不知道他们为何这么做。
为了避免这种情况,我们在艾丽AI的代码里会记录并监测艾丽的移动事件。
每次当艾丽想要进行下一步动作时,代码通常就会告诉艾丽说“诶你先别动,等一等”。然后我们为艾丽设定了很多的条件,仅当这些条件成立时艾丽才会去选择移动,并且是在接下来的一段小段时间内挑选一个时间点来移动。也就是艾丽不会在得知目标坐标之后立刻移动,而是会有一小段等待时间。
当艾丽被一些什么东西吓到时,艾丽可能很快就会触发移动;当艾丽距离乔尔比较远时,艾丽也会很快就触发移动;当乔尔走得很慢、在四处观察时,艾丽的移动频率也会变慢,甚至因为条件没有触发而暂时先静止在原地。
6 艾丽的移动速度
在这个基础上,我们再去确定艾丽的移动速度。
一旦艾丽选定了一个坐标点并开始移动时,AI会取得移动距离的长度,然后根据这个距离去确定艾丽应该要慢走、要跑、还是要冲刺过去。
具体的计算细节这边就不展开了,反正有了这个速度之后,我们再也不会见到当乔尔已经把艾丽拉开50米远距离时、艾丽还在慢悠悠地走过来这种看起来很蠢的情况了。总之,这个功能就是用来计算艾丽每次要如何跟上乔尔。
关于艾丽的移动速度,我这边还可以再说一些细节:移动速度的调整。
我们前面说了艾丽要通过走路或者跑动来移动到某个坐标,而在这个过程中的每一帧,我们都会根据乔尔的位置来实时计算、来进一步调整艾丽的移动速度,从而使艾丽看起来更自然。
比如当艾丽如果距离乔尔太远了,我们会提高艾丽约25%的移速以便她更快追上乔尔,当然这个过程里我们也会加快艾丽的动作播放。直到艾丽已经跑完50%的距离之后,我们会让艾丽的速度匀速下降,直到玩家看起来乔尔跟艾丽会以几乎相同的速度在奔跑。
无论艾丽处于哪个状态(走路、奔跑还是冲刺),我们都会有这个移动速度的调整规则,并且这个过程其实非常细微,一般来说玩家肉眼不太容易观测到,但又能把艾丽的速度调整得非常顺滑。
7 移动AI里的回避逻辑(Dodging)
可能你们在别的游戏里见过一些类似的回避逻辑,就是当玩家走向一个同伴角色时,同伴角色会避开、闪到一边去。
我们游戏也有同样的机制,不过后面我们慢慢发现这样其实不算特别好。我们想象一下,在现实中你和你的朋友在一个房间里站着,然后你直挺挺地往对方的方向走到对方跟前,你的朋友有可能以为你要去揍他。
相比于直接走过去,更自然的移动方式应该是稍微带点弧形、以对方坐标为目标来半绕着前进,最终走到对方的旁边。
我们在观察玩家试玩的时候的确也发现了类似的情况,因为乔尔和艾丽是接近于朋友、亲人的关系,玩家通常不会采用充满攻击性的直挺挺走法,而是在想靠近艾丽时会稍微绕一下然后走到艾丽旁边,然后一起看向下一个关卡目标。因此,虽然这里我们说的是玩家控制乔尔移动时的游戏习惯,当我们反过来要做艾丽的移动AI时,艾丽的移动方式应该也是如此。
但这引出了一个问题,既然大家都会回避,那当艾丽如果在乔尔之前到达了一个目标点,然后刚好这里是一个窄路、把乔尔挡住了怎么办?
在一些楼梯上、在一些相对较窄的洞口处出现这种情况时,AI会控制艾丽开始了回避系统里的寻路,让艾丽在附近找到一些不会挡住乔尔的坐标点,比如窄路旁的一些小斜坡、楼梯的栏杆旁等等。然后下一步再把艾丽的朝向改变成面向乔尔,相当于示意乔尔说:“我给你让开了,你从这边走吧!”。这就是回避逻辑的基础做法之一。
此外,同伴AI还会触发抱怨逻辑。比如无论艾丽有没有挡住乔尔,一旦乔尔撞到了艾丽,艾丽就会做出一些反应动作,并且会触发抱怨的对话。
8 跟随AI这么复杂,干脆做个瞬间转移好了
有人可能会说:“嘿!Max!你不是想让艾丽紧跟在乔尔后面吗?干嘛不直接把艾丽传送过去呢?瞬间转移!”
如果你们还记得我前面所说的话,我们有一个原则就是从不作弊。我们希望游戏中的世界是真实的,让人有代入感的。
(这里我插入一句,在《战神》里阿特柔斯的同伴AI就用到了传送,但由于《战神》中一些更重要的游戏设定而不得不加入传送,否则游戏会在一定程度上变得不太连贯,这边就先不展开了,以后有机会再说。而《神秘海域4》则跟《最后生还者》一致,一直没有使用传送。)
而第二个原因是关于脚步声。
如果我们用传送的做法,艾丽的一大部分脚步声可能都会被忽略掉,玩家在一秒前明明听到20米外有脚步声,然后忽然就什么都听不到了,这并不好。而且当艾丽用跑的方式赶上乔尔的时候,脚步的音量随着时间慢慢变化,这本来就是我们希望达到的效果。
第三个原因则是,传送这个行为本身就太tm惊悚了。
你想想,当你远远地看着艾丽在远处某个地方,然后你转身看了一下身后,然后又回过头看向艾丽,你发现艾丽忽然就出现在你面前。对不起我们不是一个恐怖游戏。
我们取消传送这件事最主要还是游戏的原则性问题,我们不想在《最后生还者》的世界观里加入一些匪夷所思的事情,瞬间转移这件事情在这个世界上是说不通的。所以,我们开发组宁愿花很大精力去完成这件事情,也不要去作弊。当然可能艾丽自己会认为这导致她少了一项很厉害的技能而不开心(开玩笑)。
以上这就是非战斗状态下跟随AI的基础内容了,下一章我们来讲艾丽在战斗状态下的跟随AI。