两人研发卖出50万套,这个爆款独立游戏的续作经历了怎样的技术迭代?

发布于: 雪球转发:0回复:0喜欢:0

Unite 2019大会今天在上海开始了第一天的日程,除了Unity官方的技术干货,也有一些分享来自独立游戏,比如Switch平台上广受好评的《胡闹厨房》(Overcooked)系列。

《胡闹厨房》系列背后的故事堪称传奇。游戏初代开发者只有两人,一度连办公室都租不起。而游戏发售后由于其独特的玩法和社交性大获成功,Switch版本售出50多万套。

续作《胡闹厨房2》也延续了前代的成功,成为NS平台实体销量Top 30的游戏。不过游戏的升级换代并不容易,为了实现玩家呼声已久的“多人在线合作”等玩法,游戏开发期期间经历了不同的技术难题。今天的Unite 2019大会上,《胡闹厨房》系列的发行商Team 17总监David  Smethurst分享了这一独立游戏爆款背后的技术思考。

以下为David演讲实录:

我叫David  Smethurst,是Team17的总监,负责编程内部的工作,与我们的合作伙伴合作。我的演讲是有关于《胡闹厨房2》(Overcooked 2)的内容。

先讲一下游戏的历史,《胡闹厨房》最早由Ghost  Town  Games开发,一款多人合作、烹饪益智类游戏,可以让4位玩家同时在一个游戏中,通过多个步骤准备烹饪。游戏的玩法很有趣,也获得了很多的奖项。游戏本身非常成功,但玩家对它有更多期待,Ghost  Town发了两个DLC,仍然觉得不够。

所以接下来在续集中我们想要做什么呢?

这是续集中Team17所做的工作,我们对续集很感兴趣,希望和Ghost合作,提供一些功能集,让更多的人参与,在保持本地游戏的基础上,支持全球联网游戏。多人在线互动是游戏核心的功能。

当然,我们也希望在关卡中设置更多内容,有一些人已经在不同地区和分节关卡中有不同的进度,但是我们还想要做得多一些,所以我们在关底设置了动态“英雄”的关卡。

这是一个气球的关卡,游戏设计的第一个原型关卡。在飞行的过程中,玩家就是这些厨师,被放置在气球里,随着时间推移,暴风雨进来,绳子被卡住,篮子落到地面,场地布局和食谱也改变了。这就是《胡闹厨房》中,Team17所做的工作——我们做了更多的设计,将玩家分隔开,你需要在这些环境之中来找到切分的可能。

比如我们在场地中加入了一些障碍,准备区和烹饪区的人必须在分离前进行食材传递。这里面我们还设置了时间限制,以及新的厨具和可投掷的道具,也更新了一些物品。我们通过设置各种挑战来达成目标。

比如这里玩家还需要跨越边界,运送食品到另一部分,或者是让玩家来规划一个方案。穿过两个部分之间的间隔,回到自己的区域。当然,我们还需要设置更多食谱,所以我们加入了像寿司、汉堡、披萨这些,以及烤炉之类的新工具。这里地图也有变化,续集为什么要这样做呢?因为游戏本身是受欢迎的,可能有很好的前景。

这些是Team17之前所做的工作,《百战天虫》我们开发了21个版本,还有其他的内容我们也做得非常成功。这是我们在《胡闹厨房》中做的一些工作,首先要解决风险最高的部分是联网。

我们先从原始代码库开始,希望能够保持游戏本身的玩法和风格,但是要增加多人在线,同时不损坏游戏原有的风格。所以我们非常需要网络插件的增强,我们可以使用Unity或者是完全重新编写,但考虑维持到原有风格,这不太可行。

所以我们来看看第三方插件,这里有几个选择:Photon、Ulink、Forge和Darkrift,这几个插件要考虑到成本,有些是云平台的付费,我们是多平台发布,要保证兼容,所以插件使用要考虑到重要的因素,就是要对原有的代码进行兼容。如果是有过多的设置或者是让游戏更加复杂,那我们的开发时间会受到更大的影响。另外大量的开发人员,在解决方案上可以帮助我们设置到最好。Unity有一个高级的API,就是HLAPI,通过它进行网络连接同时也进行很多工作的同步,包括变量的协调。新的代码库也有大量的工作要做。

接下来就是传输层,而且还要考虑到像平台的套接层,以及比较低层级平台上的表现。这是在Unity中可用的传输层之上的网络层,我们需要完全控制,并且决定每一个平台上的具体细节。而我们内部的程序员也在开发这样的项目,同时我们也会培训其他的成员来提供内部的支持,共同达成我们的技术需求。

现在,我们来看看网络拓扑。这部分在网络构建中非常重要,我它决定了游戏何时是需要去进行通讯和协作的,还有就是我们的数据以及带宽方面的限制。我们采用的云托管服务器需要非常大的带宽,因为客户包来回传递这会导致成本非常高,每一次都会因为新加入的玩家来遇到更大的带宽要求。

另外也要保证所有的游戏端都要可以充当服务端,每个端都有对象,在所有点都有所有权,然后在单点保证信息的传递,它是多向的,非常混乱。所以我们采用cs结构的网络拓扑形式,然后对客户包进行调整,它是直接适用于游戏当中的物理对象,选择拓扑结构是因为他们适合我们的需求。这也决定了我们使用原始的游戏的代码,就可以保持原有的风格,这对我们来说很重要,可以进行不同的模拟。另外是代码在不同服务器上的相互移动,也可以更加高效。

最后是更高层级的网络上,通过Unity在传输层上传输自己的解决方案,我们有一种办法让原本的脚本在网络环境下工具,而不需要对这些脚本进行破坏性的修改。我们使用额外的组件来扩展。这也意味着每一个原始的组件我们都要做出三个版本,一个是服务端,第二个是客户端,第三个是原始功能。我们的服务器使用全部三个版本,其他的端是使用两个版本。当我们使用Unity时,我们为游戏当中的每一个对象添加网络组件,以便提供唯一的网络标识。

我们还提供了客户端版本,如果将现有组件加入当中,这些游戏已经预先应用到了厨房设计的预制件,无论游戏对象如何使用游戏的脚本,我们都希望网络代码在所有的层级当中顺利移动,这也意味着说,我们会通过在加载关卡时对场景进行扫描的方式,来增加网络组件。我们迭代场景中的所有对象,对于每一个对象,我们都会添加server组件或是client组件。这就是无论我们如何捕获这些实例,都无须检查每一个资源,也不用告诉设计师和美工,如何在我们的GameObject上做出修改才能联网。

做《胡闹厨房》续集时,从第一天我们希望游戏保持这一状态。现在这一游戏仍然可以单机运行,同时也支持多人在线游戏,同时我们的功能在开发时进行网络测试,在完整的pipeline中能够足够地去完成它的工作,避免在实际的平台上运行不了的情况。

这是我们新的网络层,现在通过扫描和设置场景中预先存在的对象添加多人支持,同时也需要在关卡中生成新的对象,因此创建新对象的级别中是可以生成一些预制的游戏对象,列表来完成目标,同时通过网络生成新对象引用列表。听起来很简单,但是需要确保所有的客户端,在所有的衍生对象上都能保持同样的ID。这样就意味着我们的网络、数据的路线非常重要。

当游戏开始运行时,接下来就要进行网络的验证,我们必须重新编写所有的代码,首先是要支持移动玩家的平台,同时我们还需要支持各种不同的物理对象。比如物品的掉落,比如移动,还有玩家在厨房当中扔食材等。我们建立了一个系统,客户将他们的输入发送到服务器,并且进行整个模拟,向周围传输结果。这样的话,我们就有可能面对一个滞后的问题,在等待服务器物理结果传输回来,我们还允许他们在服务器上直接移动,以响应本地的输入。唯一的问题是,物体放在游戏环境中会移动或者是旋转,因为它们没办法平滑地在平台上相互移动。

为了解决这一问题,我们在所有的物体上都是通过统一平台,来防止物体旋转滑过的时候发生误差,而且厨师也会在他们的平台上移动食材,如果不能让厨师和食材移动的时候,就会出现情况。我们可以检测厨师和空间的定位,将厨师角色和物体同时移动,在这当中进行了大量的迭代和测试,特别是低带宽情况下,游戏的玩家也没有发现误差,但是仍然有一个问题:两个玩家相聚比较晚就会出现一些解决不了的延时的问题。

接下来看看网络的功能,我们希望性能保持稳定,尤其是帧率,玩家也希望玩游戏有流畅的体验,而网络的速度是比较稳定的。我们带宽足够,但是要保证数据传输量不要太大。原始的游戏是将各个预制件水平拼凑在一起,所有的站点都是单独的对象。那么在这里,我们需要大量的绘制调用,因此,运行的性能是比较差的,为了能够帮助美工建立了一个地板编辑器,就是说可以在场景的视图中编辑地板的位置,这样我们可以做计算,进行可视化的处理。

那么我们也确实是传递给美术,我们必须在Maya中创建整个对象的FBX的文件,然后导入到Unity中。而不是在编辑器中编辑,并且将对象简单地组合在一起。但是为了解决我们在绘制耗时,我们依然需要做效率上的提升。比如说我们的美工他们需要更多的纹理和共享材料,我们会由渲染器进行合批,另外为了在满足美术的要求的同时,达到能在最差的平台运行的标准,我们选择了配合Forward Rendering使用烘焙光照。为了辅助烘焙过程,我们会有专门的工具在专用的机器上运行。

另外我们还有一个编辑器工具,他们是强制在预制的物体上应用正确的设置。比如说它强制设置Motion Vectors选项为”Camera motion only”,以防止的TAA中的额外DrawCall开销。我们要求所有的美工关闭静态物体的Light probe功能以防止合批被破坏。我们还要求美术对所有不对场景产生明显画面影响的物体关闭阴影,这不会影响主要的操作区域的视觉质量。并且我们进行定期Profile分析,来确定瓶颈在什么地方,我们也要确定未来一个开发更好的改善机会是怎样的。

我们在使用Unity的Profiler的时候,也会去进行特定平台的Profiler的研究,在进行游戏的时候,我们还要去进行关卡和关卡性能的检查,我们设计了简单的性能、跟踪的系统,这个系统在一个关卡中对FPS进行采样,关卡结束向玩家(这里指的是QA)汇报统计的数据,这是分不同的帧数范围来进行汇报,还有帧数波动等等。

同时我们也会进行质量的检查,另外我们还会收集标准差,帮助我们评估帧速率的检查。有时候这些测试可以自动化地进行,而且可以非常快,容易规划,另外就是在夜间可以完成,这样的话,很容易去帮助我们提交数据。在这部分,目前一切进行很正常,但是实际上我们仍然遇到困难,比如说项目结束时发现特定关卡的CPU的性能出现在渲染问题上,对这些问题我们确认以后很明显是DrawCall瓶颈,部分物体还是基于Prefab拼接,而不是在Maya中作为一个整体制作。在Unity批处理材料时,没办法在低端机上绘制足够多的DrawCall。之后我们做了很多美工方面的工作,因为我们的内存资源是丰富的,我们选择将相同的材质的对象合批,这样我们就可以减少不需要资源的浪费。

在可能的情况下,我们还进行了网格的调整,尽可能合并和减少资源的调用,在平台的低端平台上运行时依然还是会面对很大的挑战。因为我们内容的创作者它想要实现更多的东西、更多的内容和更多的光照效果和细节。所以我们必须在统一的渲染管线中实现操作。所以在这里很重要的一点就是渲染功能,因为我们低端控制没有大量的内存,帧速率降低,而且我们考虑效果的时候是需要压缩的,一开始进行的测试它是采用Forward渲染的,通知渲染了除太阳以外的所有灯光,最初在照明方面我们取得了很大的进步,包括深度缓冲区等。

另外我们还必须在后期效果上进行验证,就是使用Depth+Normal,最初使用这些工具降低了成本,但是仍然是有效率和时间的问题。然后我们最后的结果就是包括大量的绑定阴影,虽然说屏幕空间的阴影对于我们的阴影效果非常有用,但是它是比较花时间的。尤其是在这一过程中,我们是进行了一些常规的阴影贴图。那么我们所选择的是在这个工具箱中的阴影,阴影的分辨率非常高,我们采样一次shadowmap,通过双线性插值时阴影变得柔和,来保证视觉效果相同。

最后一个问题是后处理,最初花费了10毫秒,降低Quality设置,在每一个像素上做更少的读入和其他的优化,会让整个的速度都会更好一点,但是很明显,我们需要一个新的解决方案。同时你可以看到SSAO是唯一的一个后处理管线当中需要法线的部分,所以如果我们可以去掉这个步骤,我们就可以简化pre-pass。我看评估了volumetric obscurance方案,一种极端简化的SSAO技术,是非常方便而且容易实现的SSAO技术,它由CryTek针对XBOX360和PS3开发,这样的一种方法解决了我们高样本的需求,同时使得定制的发生器的输出,只需要4个样本就可以获得非常好的结果。

TiltShift也是经常使用的,经常5毫秒以上,最低质量的设置中也是如此,也是要优化它,不然我们的美工也是无法控制和使用的。他们只需要在底部和顶部使用这一技术,在我们的摄像机下,也就是最近和最远的区域,我们采用最新颖的方法,因为我们选择不将它全部变成全屏后处理效果,相反地我们渲染了两个四边形,一个在底部一个在顶部,其效果的覆盖40%屏幕的区域。

进一步的优化是,其实我们并没有实现一个正确的景深效果,我们研究了一些2000年初的技术,你只要在模糊纹理和清晰纹理之间进行双线性插值,就可以得到一个从模糊到清晰的景深过度。最后一个改进是把post processing stack中的FXAA的文件拿出来修改,强制它使用主机的code path。默认的是使用最高质量的实现。这个修改必须在源代码中进行,因为这些接口没有暴露出来,也不会受任何Quality设置的影响。

刚才讲到了美工的原则,就是减少网格的复杂度以及合并DrawCall。另外我们区分了渲染用的网格以及碰撞网格,主要是为了减少碰撞耗时。我们在网络层其中的增加的一部分关键就是更新管理,这个概念在开发后期添加到游戏中,当我们通过系统向游戏中添加大量的逻辑和修饰组件时,我们自然会增加场景当中实现了MonoBehaviour的Update方法的组件数量,这会导致引擎从C++跳到C#的回调增多,性能不是特别好。所以我们每一个网络组件实现了UpdateSynchroniser接口,而不是通过MonoBehaviour的Update方法。

通过这样的修改,组件所花费CPU的时间大大减少。我们还在加载界面增加了一个额外的步骤,就是扫描场景当中某些关键组件当中的某些关键实例,并且保存它们的引用,这对玩家交互代码很重要,因为每一帧,我们都必须扫描所有的可以跟玩家交互的GameObject。对于游戏当中的对象,预先存储的引用数组大大减少了分配。还有一个非常重要的改进,就是把委托放在一个List中,而不是使用+=,-=的方式来进行注册,功能是相同的,你可以看到加等和减等是相当大的垃圾源,所以我们还是要考虑尽量避免他们的发生。

还有一点是我们有时候没怎么讲到,是用户界面的一些具体元素的性能,特别是玩家的HUD,因为玩家用它们来理解游戏世界游戏中心的一些核心数值。最开始的时候,屏幕顶部的一些小部件都是带有Animator组件的用户界面元素,这个问题在于,UI组件的移动,会导致我们的Canvas被标记为需要重新布局。这对性能是有影响的,尤其是进行多处组件都在这样做的时候。

怎么办呢?我们干脆移除了Animator,将UI元素实例化设置成静态的状态,并且使用着色器进行渲染,这样相当于我们得到了动画,但是我们的画板还是非常干净的。如果在画板上任何内容发生了变化,整个画板都被标记使用过的或者是非干净的,并重新计算所需要的内容。所以将所有的静态元素放到一个画布上是最好的方法,将动态元素放到单独的一个Canvas上也有用。对于单个元素的影响我们可以控制,我们重新组织了层级结构,因为大大提高了时间的效率。另外一个就是性能优化就是一个定时器UI,一开始我们用一个整形计时,然后把整型转换成字符串,字符串的创建会造成垃圾的产生和废物的产生,我们通过预先分配的字符串来,避免垃圾的产生。

其他的内容或者是更加具体的是,我们的输入是否有延迟。你可以看到Switch的版本最终实现的目标是每秒30帧,PC、XBox的目标是60,与其他版本相比,Switch的版本即使是在稳定情况下也是响应很慢的。

通过调查我们发现两个问题,游戏移动系统以和游戏相同的帧数进行,它是30帧或者是60帧,当玩家施加一个力,只是增加DeltaTime并不会实现同样的结果,因为加速度和DeltaTime成正比,而速度不是,就意味着有一个物体在30的速度下加速变慢,我们必须把角色的刷新频率锁定,使其以60FPS的速度运行,哪怕是在较低的帧速率下也是如此。

即使做了这样的调整还是很慢。我们使用高速的摄像机录制200FPS的视频来进行测试。从我们输入到它出现到屏幕上的时间,我们拍摄屏幕和控制器,并且检测到输入后出现大白框的显示,可以测量游戏的输入延时,这个测试我们做了5次,同时计算了平均值。我们发现在游戏中有一个与帧速率的延时,60PFS当中延迟的是一半,PS4是5帧,XboxOne是3帧,Switch是3帧,直接读取本机的输入,测试时间为PS4节省一些时间。最后我们将这些时间安排在一起,他们都来自于Unity,我们和Unity进行交谈,看看我们有没有方法来解决这样一些问题。所以当你有机会做出这样的变化时,尽早测试,特别是由于游戏当中所产生的。

还有一个Split—Pad,其中有手柄问题,半个手柄操作译名厨师的控制方法。如果想让两个用户交互,或者做表情的话,这种新功能是对整个环境是非常敏感的。玩家不能同时切菜和投掷,因为相同的按钮不能用于两个操作。

由于兼容性问题,我们无法在联机模式下使用Split-Pad,Split会创建一个新的游客玩家,在联网环境下,这个新玩家无法通过认证。但是我们确保了在线环境下可以用半边手柄来操作厨师的能力,它有一定的支持能力。

往后看,并不是所有的这些主机都有相同的功能,我必须要考虑到主机的一些差别。而且UI必须满足这些不同主机的差异性。比如说这种系统集成到主菜单当中,选择玩哪种模型之前,主人邀请朋友参与到他们的厨房活动中,这是非常好的系统,尤其是对于PS4和Xbox1和Steam来说。

但是在Switch上我们遇到了一个问题,这样的功能并不是所有平台都支持的。我们需要在平台上保持相同的体检,就需要不同的用户界面,这样主机就可以进入在线的状态,他们的朋友通过自定义菜单来加入游戏,我们需要另外一个自定义的代码路径来支持浏览列表的概念,以支持附近的玩家加入进去。这样的类型我们在下载的时候,有的时候都是在争夺这一焦点,常见的例子是由于某些错误的状态,如手柄断开链接而出现的对话框,这些对话框的焦点,就是你要将它关掉焦点将丢失,所以我们要考虑到它的逻辑层。

由于我们是在主机上开发,我们还需要计划一些不定和DLC作为其中的部分,在开发NS版本时有时候需要AssetBundles的支持。同时平台也要求你将Asset收集到Bundle当中,而不是将资源添加到场景当中。所以在游戏当中,我们创建了自动化的系统,将资源添加到一个固定大小的Bundles里面,我们尽量调大这个阈值,创建小的资源包,然后减少不定的范围,或者是限定补丁的大小。我们使用了Asset Bundles,当你从里面加载数据时,你的加载时间也会受到影响。

基本上讲完了,大家有问题可以提问。这是非常好的游戏,也有很多人非常喜欢《胡闹厨房》的游戏,我们会不断地优化我们的管线,希望能够让我们觉得这个工作还是有没有完成的地方。尤其是关于它的细节,其中的一个挑战就是我们希望能够有更多的设置。

一开始的版本当中,游戏使用了大量的半透明面片,让美工可以控制,性能非常差。当游戏发布以后,我们发布了特别建模的叶子,这提高了性能,也是让游戏有了风格。这样一种单独建立的树上的叶子,也是比较好的改进,因为它更加适合我们的风格。

此外,在最初的游戏版本当中,几乎每个游戏对象都有自己的素材,还有一个简单的着色器,完全满足了对象在游戏开发当中的需求,虽然这让这个游戏的开发变得更加简单,这让我们开始为每一个不同主题开始绘制它的纹理图,并且贴合实际情况的着色器,每一层仅对所有的艺术资源使用很小的这样一种素材,这只用了1/4,所以提高了整体的帧速度,这是我们发布以后最大的单性能提升,因此,我们的游戏基本上都是以60秒/帧来运行。

目前我们已经发布了DLC,每个DLC都有一个小型的活动,自从游戏发布以来,我们还添加了练习和生存模式,玩家可以很放松地学习,并且知道每关怎样玩。通过精心设计的组件系统,运行时可以切换网络组件和本地组件,无需对场景进行更改即可切换本地模式和联机模式。这可以让补丁非常小。

我的演讲完了,谢谢!

推荐阅读

明日方舟|隐形守护者|自走棋手游|疑案追声

游戏人众生相|版号|游戏公司招聘|王牌战士

如果你认为写得好,不妨点个“在看”呗

最新的游戏专业书上架啦!点击下方小程序即可获取

关注微信公众号“游戏葡萄”,每天获取最前瞻的游戏资讯