游戏
首页>游戏>正文

模拟经营游戏《Project Hospital》的优化经验

2019-07-1815:57:19来源:北青网

x

分享到微信朋友圈

使用“扫一扫”即可将网页分享到朋友圈

本文将由《Project Hospital》的开发者Jan Benes分享该项目的优化经验。由独立工作室Oxymoron Games使用Unity打造的《Project Hospital》(中文名:《医院计划》)是一款模拟经营类游戏。它具备该类型游戏的特点,包括:由玩家创建的动态场景,大量的活动角色和物体以及可扩展的UI系统。让《Project Hospital》在不同硬件上运行需要不少努力,而且这也是“积小流以成江海”的典型性能优化案例,正是我们处理了许多小步骤,解决了大量具体问题,花费很多时间进行性能分析,才有最后性能卓越的提升。

性能目标在早期开发阶段中,我们为将要支持的大型场景设定了主要性能目标以及硬件要求。我们的目标是至少在一个屏幕上同时显示100个活动的动态角色。《Project Hospital》共有300个活动角色,大小约为100 x 100的瓦片地图,最多有4个楼层。我们希望游戏以合适的帧率运行在1080P的画面中,即使在集成显卡上也有这样的效果。由于CPU是此项目标的主要影响因素,所以这种效果并不难实现。随着医院的扩大,集成显卡在2560 x 1440的高分辨率下才开始比较吃力。为了实现简单的模组支持,游戏中的大部分数据都是开放的。这意味着和打包文件相比会牺牲一些性能,但这不会造成太大影响,只会稍微延长加载时间。

图形由于《Project Hospital》是一款典型的2D等距游戏,所有内容都是从后向前渲染。在Unity中,这种渲染方式通过设置图形对象上正确的Z值或摄像机距离来表现。在可能的情况下,不相互交互的对象会组织到不同图层,例如:地板和物体及角色是相互独立的。等距渲染场景中的所有几何体都是使用C#代码动态创建的,因此对于图形性能而言,几何体重构的频率是重要部分之一,另一个重要部分是Draw Call的数量。

Draw Call无论对象的简单程度如何,一帧中绘制的独立对象数量都是主要的限制,特别是在低端的硬件上,而Unity本身也有额外的开销。最好的解决方案是将更多图形对象批处理到单个Draw Call中。这样得到一些有趣的结果,例如:由于支持批处理的对象是和摄像机有相同距离的对象,因此其它图形会得到正确的渲染。

下面列举几个数字:在96 x 96的贴图上,我们理论上可以放9216个对象,也就是要进行9216次Draw Call,在批处理后,Draw Call减少为192次。在实际环境下,情况会变得更加复杂,因为只有具有相同的纹理的对象才可以进行批处理,所以得到结果的优化程度不那么高,然而这种方法依旧是很有效的。

大多数批处理通过手工完成,从而对结果进行控制。我们也使用了Unity的动态批处理作为后备方案,但这种方案是一把双刃剑。Unity的动态批处理确实可以帮助减少Draw Call的数量,但是每帧都有额外性能开销,在某些情况下,性能开销会难以预测。例如:与摄像机距离相同的二个重叠精灵会在不同帧以不同顺序进行渲染,这会造成精灵闪烁现象,手工进行的批处理则不会出现这种现象。多楼层建筑允许玩家构建多楼层建筑会增加很多复杂度,但是对性能有所帮助。只有在活动楼层和户外环境的角色和物体需要动画和渲染,医院中活动楼层之下或之上的内容都可以隐藏起来。

着色器《Project Hospital》使用相对简单的自定义着色器,利用了颜色替换等多个技巧。例如:通过在着色器代码中使用条件,角色着色器可以使用最多5种颜色替代。它的性能开销较大,但因为角色很少占据屏幕的大量空间,所以这不是我们需要担心的问题。我们也学会了如何避免设置着色器参数,转而使用顶点颜色。纹理质量有趣的是,我们没有在《Project Hospital》中使用任何纹理压缩。因为如果对游戏中存在矢量风格的图形进行压缩,有一些纹理会看起来非常糟糕。为了节省系统上的GPU内存,使它小于1GB,除了用户界面的纹理外,我们会自动减小游戏内纹理大小为一半的分辨率,我们可以将选项设置为“texture quality:low”(纹理质量:低)。UI纹理会保持原始分辨率。

多线程处理虽然Unity脚本逻辑基本上是单线程的,但我们可以选择使用C#代码运行多线程。对于游戏逻辑而言,这可能不是一种合理的方法,但是有些非时间相关的任务可以受益于以Job System形式在各个单独的线程上运行。在这款游戏中,我们把多线程用于二个功能:寻路作业,特别是在大型地图上,由于糟糕的布局可能需要数百毫秒处理,因此它是从主线程移除的理想选择。并行作业的数量会考虑到机器上硬件线程的数量。光照贴图也会在单独的线程上更新,但每次仅更新一个楼层,它不是一个重要的系统,房间中的自动灯光会以较慢的更新速度淡出。动画在开发阶段早期,我们就决定使用2D骨架动画系统。在考虑当时不同的动画软件后,我们最后修改和使用了几年前开发的简单系统,使它符合《Project Hospital》的特别用例,你可以把它看作直接支持创建角色变体的简单样条曲线。类似于样条曲线,该工具系统使用C#运行时,显然这比原生代码的性能开销更大,因此我们在开发期间进行了多轮优化。幸运的是绑定非常简单,每个角色仅有20个骨骼。最重要的部分是在访问单独骨骼的Transform时,从地图查询切换为简单数组索引的过程。

除了不使摄像机视图外的角色有动态效果,另一个和动画相关的技巧是让主UI窗口背后的角色也不需要有动态效果,然而切换为半透明UI后,我们无法在最终版本使用这个技巧。缓存在可能的情况下,我们会尝试仅在有影响数值的改动时,运行有特别要求的计算。最好例子大概是房间和电梯,在角色放置电梯或建起墙面时,我们会运行楼层填充算法,它会标记可以访问电梯和房间的瓦片。这样会加快寻路过程,向玩家展示哪些房间目前无法访问。分散和延迟的更新在一些情况下,我们会偶尔运行一次特定更新,我们使用了下面的方法。一些更新每帧只可以在一部分角色运行,因此会出现这样的情况:一半病人的行为脚本仅在奇数帧更新,另一半会在偶数帧更新,而动画和移动会流畅的运行。在特别状态下,有时角色闲置时会调用开销较大的代码,例如:员工检查过程需要填充和寻找可用设备,该过程仅在特定时期完成,例如:每秒进行一次。性能开销最大且最常见的调用是每个病人可以进行哪些检查的估算。我们需要评估很多因素,例如:哪个部门的员工目前处于忙碌状态,哪些设备目前已被预订。因为他们的指定医生和谈话技能也有影响,所以这些信息对所有病人来说并不常见。游戏中可能有多个可用检查需要执行,因此更新只在每帧进行几次,而且会持续到下一帧。

其它经验优化具有大量不同交互部分的游戏是一个持续的过程,使用Unity的性能分析器能够解决性能影响较大的部分问题。游戏按照我们原来的目标运行,玩家可以给游戏添加模组,使游戏内容超过原始角色限制。相对于我参与过的其他AAA级游戏项目,《Project Hospital》具有最复杂的游戏逻辑,因此很多问题是和项目相关的。最后要建议大家:不管是什么项目,一定根据游戏的复杂性预留出足够的时间进行优化。

结语《Project Hospital》的优化经验为大家介绍到这里,更多Unity项目的优化经验分享,尽在Unity Connect平台(Connect.unity.com)。来源:UNITY官方平台

责任编辑:周经韬(EN069)

热点聚焦

头条新闻

  • 雄安将建机场快线 启动区设航站楼

    机场快线(R1线)工程南起雄安新区启动区,北至北京大兴国际机场北航站楼,线路全长85千米,其中雄安新区段40千米,廊坊段41千米,北京段4千米。线路采用市域城际铁路标准制式,预设4-6座车站。

  • 北京高速公路将实现ETC全覆盖

    今后北京高速公路所有车道将实现ETC支付。收费站将至少保留一条混合车道,供没有安装ETC设备的车辆通行。目前北京实行ETC车载设备实行免费安装政策,北京市多家银行都可以申请办理。

  • 女生网上买药,3个月减肥30斤?

    月经连着四个月都没来,小岚慌了,这才找到何教授的门诊来就诊。经过检查,诊断为“早发性卵巢功能不全”,属于卵巢早衰前期的一个症状。经过何教授治疗,小岚的月经才慢慢规律起来。

  • 研究称喝果汁和可乐增加患癌风险一样高

    据CNN报道,法国一项新的研究发现,每天只喝一小杯含糖饮料(100毫升),总体癌症风险就会增加18%,患乳腺癌的风险就会增加22%。

  • 青蛙唱歌 居民有了“幸福的烦恼”

    傍晚微风拂面,宅边阵阵蛙鸣,这本是惬意的生活场景,但日前,有居民打12345热线进行投诉,说小区水系中的蛙鸣影响日常休息,希望相关部门能够进行处理。

点击加载更多

频道推荐

  • 社会
  • 娱乐
  • 生活
  • 探索
  • 历史
关闭 北青网新闻客户端