《戴森球计划》战斗系统开发日志
阅读
2023-03-19更新
最新编辑:丸丸辣
阅读:
更新日期:2023-03-19
最新编辑:丸丸辣
时间:2023-03-17
最后更新时间:2024-10-18
来源:Steam
原文地址:https://store.steampowered.com/news/app/1366540/view/5311472123811585119
,请注意文章时效
亲爱的工程师们,周五好呀!
自《戴森球计划:黑雾崛起》去年在TGS上的内容展示以来,我们已收到了大量来自玩家的支持和鼓励,这让我们非常的兴奋,并在团队的一顿火力输出下,越来越多关于战斗的内容也被加入到游戏当中来,先上几张高清大图:
这段时间除了战斗系统的开发以外,我们还为大家带来了新的配送物流玩法,更高级的化工厂,能存货的四向分流器和更便利的传送带功能等等。
为了在开发战斗的同时能够给大家提供尽可能多的新内容,我们内部在早期将 黑雾崛起 和 游戏内容更新 分成了两个项目分支(Branch)同步开发:“战斗分支”和“内容更新分支”。在开发过程中,我们需要定期将“内容更新分支”所做的改动合并到“战斗分支”中来,从而让战斗模式在发布后能够继承之前所有的更新,同时也避免了战斗模式的资源提前泄露。
然而坏消息是:战斗系统作为独立项目分支跑了一年多,在内容上已经和主分支产生了大量的代码和资源冲突,而每次解决这些冲突都会占用我们大量的精力,有时甚至还需要刻意去避免改动公共资源和底层代码,这让我们无法专注于战斗系统的开发。为了让战斗模式早点和大家见面,我们决定全面切换到战斗分支,所以在战斗模式推出之前,只能修改部分旧内容,而无法再提供新内容更新了。
这样一来,我们才有机会对战斗系统代码和一些底层进行重构。因为在零零碎碎地加入了一堆内容后,游戏性能瓶颈开始凸显,我的老机器还能跑到十帧甚至九帧,最终在帧率不支的情况下,我们决定推翻一些无法优化、不够灵活的代码,在实现过一次过后,大家也有了一些经验,也愿意尝试更好的方案。虽然过程比较艰难,但是必须得保证我们最初的目标:加入战斗后游戏必须流畅。
(顺便提升了一下配置)
在我们的理念中,策划和程序不能是两个独立思考的部门,“策划只管提需求,然后程序来实现”。像遇到这样的性能问题时,这种流水线式做法根本不管用,策划要么会坚持说:“我不管,你程序必须得整出来”,要不然就会放弃说:“算了,现在技术还达不到”。
在戴森球计划中,玩家的工厂物件规模动不动就上十万百万,性能无疑是需要重视的。而一个游戏的性能最终上限是从策划设计时就定下了,然后再是靠程序的技术水平去努力达到它。所以我们要求策划在设计时就利用好这些仅存的性能空间来实现尽可能多的可能性。在经历了一次玩法验证之后,我们给出了一个设计目标,下图展示了在设想中玩家通关前和黑雾的战斗力对比。
此外我们比较清楚:如果黑雾挤占了玩家的发展空间(和CPU算力),玩家势必会消灭它们,所以黑雾和玩家工厂的活动大致呈此消彼长的关系。我利用这些特性制定了一个性能优化目标:
如果玩家玩到后期,选择“养着黑雾不打”,那剩余的大量黑雾巢穴开销一定会成为很大的负担,而此时黑雾的整个生产体系(太空巢穴、地面基地)对于玩家来讲是非敏感的,更新频率并不需要像玩家工厂那么高。
(黑雾的扩张逻辑)
经过考虑后,我们将黑雾巢穴的更新逻辑设定为每60逻辑帧更新一次,此外,所有巢穴的更新尽量平均的分布在每一帧,避免大量逻辑集中在一帧内更新。例如玩家选择了60个恒星的开局,那每一逻辑帧将轮流更新一个行星系的黑雾巢穴。以下是简单的负载均衡代码:
上面看似简单的想法却带来了其他的麻烦:如果黑雾每60帧更新一次,那除了建筑以外的其他战斗单位怎么办?太空中的运输单位怎么办?黑雾地面建筑的动画该怎么衔接?
(太空单位的舰队方阵)
(地面单位群体行为)
这种情况必须得祭出大招:利用GPU来处理一些运算。
就像物流运输机的优化那样,CPU根本不用计算运输机从A点(xA,yA,zA)出发,到达B点(xB,yB,zB)卸货,中间经过的这条弧线,以及机身旋转、上升下降的过程、尾焰特效如何变化等等,CPU要做的仅仅就是累加一个t值。
而将比较复杂的数学运算工作交给GPU:
以下是大量物流运输机的性能测试存档,有兴趣的话可以下载试试看:
运输机性能测试存档
(21,000物流运输机同时更新)
由于敌方战斗单位99%的时间都是在执行闲逛行为(Wandering Behavior),所以从设计上可以让它们的轨迹更具有可计算性,即可以使用参数方程来表示其运动轨迹,这样就可以像优化物流运输机那样优化绝大多数正在闲逛的敌人了。
接下来我们计划当它们进入攻击状态时,或是退出攻击状态返回闲逛时,在GPU演算和CPU演算之间进行无缝切换。
这样做同样存在一些难点,比如在攻击这群敌人时,自由目标弹道很难找到合适的攻击目标。这的确让简单问题复杂化了,不过相比全CPU模拟带来的性能“灾难”,我们必须先这么做,再解决后面的问题。复杂度不能被消灭,性能优化就是把运行时的复杂度转移到代码的复杂度上。
(现在还没有做出来.jpg)
除此之外,我们还发现在以最高难度创建新游戏后,由于64个行星系的黑雾建筑总数多达200k(这还只是建筑),即使在逻辑开销已经被压至3ms以下,黑雾在存档中的数据量仍有50M左右。
对于新开的存档而言,玩家是感受不到其他行星系黑雾的存在的,这样的存档大小比较难以接受。但同时,我们也认为即使是远处的黑雾也必须按照一定规则来发展,并且这些规则的确定性(Determinism)结果在之后会逐渐变得十分重要。就像游戏中“真实宇宙”的一贯运行逻辑那样,玩家并不会因为离开星球,而让星球上的工厂失去逻辑的确定性。
为此我必须将黑雾生长的逻辑和数据分成多个具有确定性的LOD(Level of Details),并指定各级间的切换规则。
而为了保持一定的确定性,我重新翻版了巢穴生长过程的设计,使其在不受干扰的情况下,根据确定的年龄和随机数种子可以实时烘焙出一个确定的巢穴生长版图。这样的话,即使每个巢穴包含多达2000个建筑和单位,我们至少能将远处未相遇的巢穴转化为“年龄”、“随机数种子”等若干头部数据。同时仍然生成中继站和火种,以确保未相遇的黑雾仍然可以向外扩张。
(最简数据形式)
(蓝、红、黄框分别是三个等级的逻辑LOD)
目前,战斗系统的代码重构还在进行中,已基本完成了上图中蓝色和红色两个等级,黑雾巢穴的自我复制和扩张部分也已基本完成。等到重构完成,接下来我们还将继续着手比较复杂的战斗部分优化。
模型制作方面,还需要完善敌我双方每个建筑的摧毁效果和所有黑雾建筑的LOD,以及每个LOD对应的动画。
对于一些需要大量渲染的复杂效果,仍需要改用shader来进行模拟。比较典型的一个例子是弹道的击中特效:
如果直接使用引擎提供的粒子系统,将无法支持大量特效实例,我们需要利用之前开发日志提到的方法,逐一将制作好的粒子系统改成用shader来模拟这些击中特效。下面是其中一个做好的击中效果:
(请各位玩家放心,这只是在做测试)
在本篇开发日志的最后再次说明一下,喜欢安心种田的玩家是可以彻底关闭黑雾的,除此之外,玩家还可以详细的设置黑雾的一些难度参数。
(以上选项仅基于目前的设计,并非最终版)
最后,向大家小小地报个喜:戴森球计划制作人3号已经落地啦!
母女平安,还在医院,左手抱娃,右手代码。
今天的开发日志就到这里了,感谢阅读!
如果对过往的《开发日志》感兴趣,可以点击这里回顾:
发在上线前的《戴森球计划》开发日志