Unite 2019大会今天在上海开始了第一天的日程。除了Unity官方的技术干货,还有一些来自独立游戏的分享,比如Switch平台广受好评的《胡闹厨房》(煮过头)系列。
《胡闹厨房》系列背后的故事很传奇。游戏第一代只有两个开发者,曾经连办公室都租不到。游戏发布后,由于其独特的玩法和社交上的成功,Switch版本的销量超过了50万套。
续作《胡闹厨房2》也延续了上一代的成功,成为NS平台实体销量前30的游戏。然而,升级游戏并不容易。为了实现期待已久的“多人在线合作”等游戏,游戏在开发期间经历了不同的技术难题。在今天的Unite 2019大会上,《胡闹厨房》系列的发行人Team 17的总监David Smethurst分享了这款独立游戏爆发背后的技术思维。
以下为大卫演讲实录:
我叫大卫史密斯斯特。我是17队的队长。我负责内部工作的编程和与我们的合作伙伴。我的发言大概是《胡闹厨房2》(煮过头了2)。
先说说游戏的历史吧。《胡闹厨房》最早由鬼城游戏开发。它是一个多人合作和烹饪的益智游戏,允许四个玩家在一个游戏中同时通过多个步骤为烹饪做准备。游戏很有趣,获得了很多奖项。游戏本身非常成功,但玩家对它的期望更高。废城送了两把DLC,还是觉得不够。
那么我们接下来想在续作中做什么呢?
这是续集中Team17所做的工作。我们对续作很感兴趣,希望与Ghost合作,在保留本土游戏的基础上,提供一些功能集,让更多人参与和支持全球网游。在线互动是游戏的核心功能。
当然,我们也希望在关卡中设置更多的内容。有些人已经在不同的领域和分层次的层面取得了不同的进步,但我们还想做得更多,所以我们在大门的底部设置了一个动态的“英雄”级别。
这是一个气球关卡,游戏设计的第一个原型关卡。在飞行过程中,玩家就是这些厨师,他们被放在气球里。时间久了,暴风雨来了,绳子卡住了,篮子掉地上了,场地布置和菜谱都变了。这就是Team17在《胡闹厨房》所做的。3354我们做了更多的设计来分隔玩家。你需要在这些环境中找到细分的可能性。
比如我们在场地上加了一些障碍物,准备区和烹饪区的人必须在分开前把食材送到。我们还设置了时间限制,新的厨具和投掷道具,更新了一些物品。我们通过设置各种挑战来实现我们的目标。
比如这里,玩家需要穿越边境,给另一个地方送食物,或者让玩家策划一个计划。穿过两部分的缝隙,回到自己的区域。当然,我们需要设置更多的食谱,所以我们增加了新的工具,如寿司、汉堡包、比萨饼和烤箱。这里的地图也有变化。续集里为什么要这么做?因为游戏本身受欢迎,所以可能前景不错。
这些是Team17之前做的作品,《百战天虫》我们开发了21个版本,其他的也做的很成功。这是我们在《胡闹厨房》中所做的部分工作。首先要解决的是联网。
先说原代码库,希望保留游戏本身的玩法和风格,但增加在线人数,不破坏游戏原有风格。所以我们真的需要网络插件的增强。我们可以用Unity或者完全重写,但是考虑到保持原来的风格,这个不可行。
所以我们来看看第三方插件。这里有几个选项:光子,尤林克,锻炉和黑暗裂缝。这些插件要考虑到成本,有一部分是云平台付费的。我们在多个平台上发布它们是为了保证兼容性,所以插件的使用要考虑到一个重要的因素,那就是与原代码的兼容性。如果设置太多或者让游戏变得更复杂,那么我们的开发时间会受到更大的影响。此外,大量的开发人员可以帮助我们建立最佳的解决方案。Unity有一个高级的API,就是HLAPI,通过它进行很多作业的网络连接和同步,包括变量的协调。新的代码库也有很多工作要做。
接下来是传输层,也是类似平台的套接字层,以及在更低级平台上的性能。这是Unity中传输层之上的网络层。我们需要完全的控制,决定每个平台上的具体细节。我们内部的程序员也在开发这样的项目,我们也会培训其他成员提供内部支持,共同满足我们的技术需求。
现在,我们来看看网络拓扑。这部分在网络建设中非常重要。我认为它决定了游戏什么时候需要交流和协作,以及我们的数据和带宽的限制。我们采用的云托管服务器,需要非常大的带宽,因为来回传递客户包,会导致非常高的成本,每次新玩家都会遇到更大的带宽需求。
另外,要保证所有的游戏终端都可以作为服务器,每个终端都有对象,所有的点都有所有权,然后在单点保证信息的传递,这是多向的,非常混乱。所以我们采用cs结构的网络拓扑形式,然后调整客户包,直接适用于游戏中的实物。我们选择拓扑结构是因为它们适合我们的需要。这也决定了我们可以通过使用游戏的原始代码来保持原始风格,这对于我们做出不同的模拟是非常重要的。另外就是不同服务器上代码的相互移动,也可以更高效。
最后,在更高层次的网络上,通过Unity在传输层传输我们自己的解决方案,我们就有了一种方法,可以让原来的脚本在网络环境中工作,而不需要对这些脚本进行破坏性的修改。我们使用额外的组件来扩展。这也意味着我们要对每个原始组件做三个版本,一是服务器,二是客户端,三是原始功能。我们的服务器使用所有三个版本,而其他服务器使用两个版本。当我们使用Unity时,我们为游戏中的每个对象添加网络组件,以提供唯一的网络标识。
我们还提供客户端版本。如果加上现有的组件,这些游戏已经提前应用到厨房设计的预制件上了。无论游戏对象如何使用游戏的脚本,我们都希望网络代码在各个关卡间平滑移动,也就是说我们会在加载关卡时通过扫描场景来增加网络组件。我们遍历场景中的所有对象,对于每个对象,我们将添加一个服务器组件或一个客户端组件。也就是说,无论我们如何捕捉这些实例,我们都不必检查每个资源,也不必告诉设计师和艺术家如何在我们的GameObject上进行更改以上线。
在做《胡闹厨房》的续作时,我们希望游戏从第一天就保持这种状态。现在这款游戏依然可以单机运行,也支持多人在线游戏。同时,我们的功能在开发时都是在网络上测试的,这样它就可以在一个完整的流水线中完成它的工作,足以避免它无法在实际平台上运行的情况。
这是我们新的网络层。现在,我们可以通过扫描和设置场景中预先存在的对象来添加多人支持。同时,我们还需要在创建新对象的层次上生成新对象。所以在创建新对象的层面,我们可以生成一些预制的游戏对象和列表来完成目标,同时也可以通过网络生成新的对象参考列表。这听起来很简单,但是您需要确保所有客户端都可以在所有派生对象上保持相同的ID。这意味着我们的网络和数据的路由非常重要。
游戏开始运行,接下来就是验证网络了。我们必须重写所有的代码。首先,我们必须支持移动玩家的平台。同时,我们还需要支持各种物理对象。比如物品掉落,比如搬家,玩家在厨房扔食材。我们建立了一个系统,客户将他们的输入发送到服务器,并执行整个模拟,将结果传输到周围环境。这样,我们可能会面临一个滞后问题,等待服务器的物理结果被传输回来,我们也允许它们直接在服务器上移动以响应本地输入。唯一的问题是,在游戏环境中,物体会移动或旋转,因为它们无法在平台上平滑移动。
为了解决这个问题,我们在所有物体上使用统一的平台,防止物体旋转和滑动时出错,厨师也会在他们的平台上移动食材。厨师和食材搬不动,就会出事。我们可以检测厨师和空间的定位,同时移动厨师和物体。在这个过程中,进行了大量的迭代和测试,尤其是在低带宽的情况下,游戏的玩家没有发现任何错误。但是还有一个问题:两个玩家在一起晚了,会出现一些无法解决的延迟问题。
接下来看网络的功能。我们希望性能保持稳定,尤其是帧率。玩家在玩游戏时也希望有流畅的体验,同时网速相对稳定。我们有足够的带宽,但必须保证数据传输量不要太大。原来的游戏是把预制的部分横向拼凑起来,所有的场地都是单独的物体。所以这里需要大量的画图调用,所以运行性能差。为了帮助艺术家,设置了地板编辑器,也就是说地板的位置可以在场景的视图中进行编辑,这样我们就可以进行计算和可视化处理。
那我们就真的把它传递给了艺术。我们必须在Maya中创建整个对象的FBX文件,然后将其导入Unity。而不是在编辑器中编辑,只是将对象组合在一起。但是为了解决画图耗时的问题,我们还是需要提高效率。比如我们的美工需要更多的纹理和共享材质,我们会由渲染器来审批。另外,为了满足美工的要求,达到在最差平台上运行的标准,我们选择了配合正向渲染使用烘焙光。为了协助烘焙过程,我们将有特殊的工具在特殊的机器上运行。
我们还有一个编辑器工具,它强制将正确的设置应用于预制对象。例如,它强制将运动矢量选项设置为“仅相机运动”,以防止TAA中额外的DrawCall开销。我们要求所有美工关闭静态物体的光探头功能,防止批次被破坏。我们还要求美工关闭场景中所有没有明显画面效果的物体的阴影,这不会影响主要操作区域的视觉质量。我们会定期进行概况分析,以确定瓶颈在哪里,我们还需要确定未来更好的改进机会是什么。
当我们使用Unity的Profiler时,我们还会对特定平台的Profiler进行研究。玩游戏的时候,我们也要检查关卡和关卡的表现。我们设计了一个简单的性能和跟踪系统,它在一个关卡中采样FPS,并在关卡结束时将统计数据报告给玩家(这里是QA)。这是在不同的帧范围内报告的,还有帧波动等等。
同时我们也会检查质量,也会收集标准差帮助我们评估帧率。有时这些测试可以自动完成,并且非常快速和容易计划。此外,它们可以在夜间完成。在这种情况下,很容易帮助我们提交数据。在这一部分,目前一切都在正常进行,但实际上我们仍然遇到困难。比如在项目的最后,我们发现某个特定级别的CPU的性能出现了渲染问题。在我们确认了这些问题后,显然是DrawCall的瓶颈,有些物体仍然是基于Prefab拼接而不是在Maya中整体制作。Unity批量素材的时候,没有办法在低端电脑上画出足够多的DrawCall。之后我们做了大量的美术工作,因为我们的内存资源比较丰富,我们选择批量处理相同材质的对象,这样可以减少不必要的资源浪费。
如果可能的话,我们也对网格进行了调整,尽可能的合并和减少资源调用,在平台的低端平台上运行仍然会面临很大的挑战。因为我们内容的创作者想要实现更多的东西,更多的内容,更多的灯光效果和细节。所以我们必须在一个统一的渲染管道中实现操作。所以这里很重要的一点就是渲染功能,因为我们的低端控制没有太多内存,帧率降低了。而且我们考虑效果的时候,需要压缩。在最初的测试中,它是由Forward渲染的,除了太阳以外的所有灯光都被渲染了。最初,我们在光照方面取得了很大的进步,包括深度缓冲等。
另外,我们还要验证后期效果,也就是使用深度法线。最初,使用这些工具降低了成本,但这仍然是效率和时间的问题。那么我们最终的结果就是包含了大量的束缚阴影。虽然屏幕空间的阴影对我们的阴影效果很有用,但是需要时间。特别是在这个过程中,我们做了一些常规的阴影贴图。所以我们选择的是这个工具箱里的影子。阴影的分辨率很高。我们对阴影贴图进行一次采样,阴影通过双线性插值变得柔和,保证同样的视觉效果。
最后一个问题是后期处理,一开始用了10毫秒。降低质量设置,在每个像素上少做读取等优化,会让整个速度好一点,但显然,我们需要一个新的解决方案。同时,你可以看到SSAO是后处理管道中唯一需要法线的部分,所以如果我们可以消除这一步,我们就可以简化预过程。我评估了体积障碍方案,这是一种极其简化的SSAO技术,是一种非常方便且易于实施的SSAO技术。它是由CryTek为XBOX360和PS3开发的。这样的方法解决了我们对高样本的需求,同时定制生成器的输出只需要4个样本就可以得到非常好的结果。
TiltShift也经常使用,经常超过5毫秒,即使在最低质量的设置。优化也是必须的,不然我们的美工也控制不了,用不了。他们只需要在底部和顶部使用这种技术。在我们的镜头下,也就是最近和最远的区域,我们采用了最新颖的方法,因为我们选择不把它全部变成全屏的后期处理效果。相反,我们渲染两个四边形,一个在底部,一个在顶部,其效果的区域覆盖了屏幕的40%。
进一步的优化是,实际上我们还没有达到一个正确的景深效果。我们在2000年初已经研究了一些技术。通过模糊纹理和清晰纹理之间的双线性插值,可以获得从模糊到清晰的景深过渡。最后一个改进是修改后处理栈中FXAA的文件,强制其使用主机的代码路径。默认情况下使用最高质量的实现。这种修改必须在源代码中进行,因为这些接口是不公开的,不会受到任何质量设置的影响。
刚才讲了美术设计的原理,就是降低网格的复杂度,合并DrawCall。此外,我们区分用于渲染的网格和碰撞网格,主要是为了减少碰撞时间。我们网络层的一个关键点是更新管理。这个概念是在开发后期加入游戏的。当我们通过系统在游戏中加入大量的逻辑和装饰组件时,自然会增加场景中实现MonoBehaviour的update方法的组件数量,导致引擎从C跳到C#的回调增加,性能也不是特别好。因此,我们的每个网络组件都实现了UpdateSynchroniser接口,而不是MonoBehaviour的Update方法。
通过这种修改,组件花费的CPU时间大大减少。我们还在加载接口中增加了一个额外的步骤,即扫描场景中一些关键组件的一些关键实例,并保存它们的引用。这对于玩家交互代码非常重要,因为每一帧,我们都要扫描所有能与玩家交互的游戏对象。对于游戏中的物体,预存的参考数组大大减少了分配。另一个非常重要的改进是将委托放在一个列表中,而不是使用=,-=来注册。函数都是一样的,你可以看到加法和减法是相当大的垃圾源,所以我们还是要考虑尽量避免。
还有一点我们有时候不会说的是用户界面的一些具体元素的表现,尤其是玩家的HUD,因为玩家在游戏世界里用它们来了解游戏中心的一些核心价值。一开始,屏幕顶部的一些小部件是带有Animator组件的用户界面元素。问题是UI组件的移动会导致我们的画布被标记为需要重新铺设。这对性能有影响,尤其是当多个组件都这样做时。
我该怎么办?我们只是简单的去掉了动画师,将UI元素实例化设置为静态,用着色器渲染,相当于得到了一个动画,但是我们的画板还是很干净的。如果画板上有任何变化,整个画板将被标记为使用过或不干净,并重新计算所需的内容。所以把所有静态元素放在画布上是最好的方法,把动态元素放在单独的画布上也很有用。我们可以控制单个元素的影响,我们重组层次结构,因为它大大提高了时间的效率。另一个是性能优化是一个定时器UI。一开始,我们用一个整数来计时,然后把整数转换成一个字符串。字符串的创建会造成垃圾和浪费。我们使用预先分配的字符串来避免垃圾。
其他内容或者更具体地说,我们的输入是否有延迟。你可以看到Switch的版本最终达到了每秒30帧的目标,而PC和XBox的目标是60帧。与其他版本相比,Switch的版本即使在稳定的情况下也反应缓慢。
通过调查,我们发现了两个问题。游戏移动系统玩的帧数和游戏一样,不管是30帧还是60帧。当玩家发力时,仅仅增加DeltaTime并不会达到同样的效果,因为加速度与DeltaTime成正比,而速度却不是,也就是说一个物体以30的速度加速减速。我们必须锁定角色的刷新频率,使其以60FPS的速度运行,即使是更低的帧率。
即使这样调整,还是慢。我们使用高速摄像机录制200FPS的视频进行测试。从我们输入的时间到它出现在屏幕上的时间,我们拍摄了屏幕和控制器,检测了输入后一个白色大方框的显示,可以测量游戏的输入延迟。这个测试我们做了五次,同时计算平均值。我们发现游戏中帧率有延迟。60PFS延迟一半,PS4 5帧,Xbox one 3帧,Switch 3帧。测试时间为PS4节省了一些时间。最后,我们一起安排了这些时间。他们都来自团结工会。我们和Unity谈过,看能不能解决一些问题。所以当你有机会做出这样的改变时,尽早测试,尤其是因为游戏的原因。
还有一个分体式——Pad,里面有一个手柄问题,半个手柄用来操作厨师的控制方法。如果你想让两个用户互动或者做表情,这个新功能对整个环境非常敏感。玩家不能同时切菜和扔,因为两种操作不能用同一个按钮。
由于兼容性问题,我们不能在在线模式下使用Split-Pad。Split会创建一个新的客玩家,这个新玩家在联网环境下无法通过认证。但我们已经保证了在线环境下操作半柄大厨的能力,有一定的支持能力。
回过头来看,并不是所有这些主机的功能都一样,我不得不考虑主机的一些差异。并且UI必须满足这些不同主机的差异。例如,这个系统被集成到主菜单中。在选择玩哪个型号之前,主持人会邀请朋友参加他们的厨房活动。这是一个非常好的系统,尤其是对于PS4、Xbox1和Steam来说。
但是我们有一个Switch的问题,不是所有平台都支持的。我们需要在平台上保持相同的体检,所以需要不同的用户界面,让主持人上线,他们的朋友可以通过自定义菜单加入游戏。我们需要另一个自定义代码路径来支持浏览列表的概念,从而支持附近的玩家加入进来。在下载这种类型的时候,我们有时会争夺这个焦点。常见的例子是由于一些错误状态而出现的对话框,比如句柄的链接断开。这些对话框的重点是,如果你关掉它,焦点就会丢失,所以我们不得不考虑它的逻辑层。
由于我们是在主机上开发,所以也需要规划一些不定和DLC作为其中的一部分,有时候在开发NS版本的时候也需要AssetBundles的支持。同时,平台还要求你将Asset收集成Bundle,而不是将资源添加到场景中。因此,在游戏中,我们创建了一个自动化系统来向固定大小的捆绑包添加资源。我们试图提高这个阈值,创建一个小的资源包,然后减少变量范围或限制补丁大小。我们使用资产捆绑包,当你从其中加载数据时,你的加载时间也会受到影响。
基本写完了,可以提问了。这是一款非常不错的游戏,很多人都非常喜欢《胡闹厨房》的游戏。我们会不断优化我们的管道,希望能让我们觉得这个工作还没有完成。尤其是关于它的细节,挑战之一就是我们希望有更多的设定。
在最初的版本中,游戏使用了大量半透明的补丁,允许艺术家控制,性能很差。游戏发布的时候我们发布了专门的建模叶子,提升了性能,让游戏有了风格。这种单独树上的叶子也是很好的改进,因为更适合我们的风格。
另外,在游戏的初始版本中,几乎每个游戏对象都有自己的材质,并且有一个简单的着色器,完全满足了对象在游戏开发中的需求。虽然这让这个游戏的开发变得更加容易,但是我们开始为每个不同的主题绘制它的纹理贴图,以及符合实际情况的着色器。每一层对于所有的艺术资源只使用了少量这样的素材,只占1/4,所以提高了整体。
目前我们已经发布了DLC,每个DLC都有一个小活动。自游戏发布以来,我们还增加了练习和生存模式,让玩家可以非常轻松地学习,知道每个关卡的玩法。有了设计良好的组件系统,运行时可以在网络组件和本地组件之间切换,在本地模式和在线模式之间切换,无需改变场景。这可以使补丁非常小。
我的演讲结束了,谢谢大家!
推荐阅读
明日方舟|隐形守护者|自导棋游|神秘追击
游戏|版本号|游戏公司招聘|王牌战士
如果你觉得写得好,不妨点击“看着吧”
最新的游戏专业书籍上架了!点击下面的小程序获取。
关注微信微信官方账号“游戏葡萄”,每天获取最具前瞻性的游戏资讯。