林晨晨:下面由我来分享一下我们《战双》的两个方面的技术要点。
![](https://img-blog.csdnimg.cn/img_convert/d31a31c2a97c8b198ec51806932a16d9.png)
第一个方面是关于游戏安全的,第二个方面是关于我们怎么去做好一个动作类游戏。
一、7点防范措施,保证《战双》公平安全
在游戏公平方面,《战双》是一个网络游戏,所以我们把玩家的公平和游戏的安全看得非常重要,让《战双》尽可能地为玩家保持公平竞争,我们做了一系列事情来保障这个环境。
1.第一件是包体加固。
它可以非常好地杜绝一些非法的二次解包的情况,而那这些二次解包出来非法包可能会欺骗一些玩家。
![](https://img-blog.csdnimg.cn/img_convert/4bc98eac01f8f211194c6f056511d9d3.png)
比如说我们在某一次测试中发现,有一个群里面流出来的包,充值比较高的金额,居然只要使用一分钱,虽然这个一分钱充值不能经过我们服务器的验证,但是这种包流出来之后,会导致玩家听信一些传言。
2.第二个是外挂识别。
我们有一个外挂的黑名单,这个黑名单里面罗列了比如葫芦、烧饼等等常见的修改器,并且屏蔽了一些调试的工具。
![](https://img-blog.csdnimg.cn/img_convert/1d7582c3c1dc422a4ed41ca5077416be.png)
这样的做法可以防止《战双》在运行时的内存被修改,那样会导致非常严重的战斗不平衡、购买逻辑出错、活动流程被打乱等等问题。
那防止被调试还有一个非常好的作用,就是可以尽可能地防护包体的整个交互过程,减少协议被探测的情况。
3.第三方面是关于协议加密的。
协议加密在这里主要是防止脱机挂,它会导致一个严重的问题——工作室可以通过非常廉价的成本批量的养一两百万个号,长期积累下来之后,形成一个黑色产业链,会给我们的收入造成非常大的影响。
![](https://img-blog.csdnimg.cn/img_convert/9fa960e95112ae30dca970293cc309ed.png)
4.第四个是关于我们与Unity合作获得的Asset Bundle加密能力。
这个加密机制,主要有两个特点,一个是片段式加密,第二个是在运行时的实时加密与解密。
![](https://img-blog.csdnimg.cn/img_convert/38fd3e68721d7e4b1f7c439c20a45091.png)
这样做的主要原因是,我们的活动是以6周为一个周期,在这个6周的活动期间,我们会尽可能把所有的活动资源打包在完整的母包里面,这样会导致我们的资源提前出现在线上的包体里面。
玩家可能经过一些破解的方法,把我们后期,比如说第3周第4周甚至是第6周的活动也提前曝光出来,会比较影响我们整个运营的节奏,比如说我们后期第6周的活动比较给力,提前被泄露就会导致我们前三周的数据下跌。
5.第五方面是关于文件签名的。
前面介绍的都是基于对称的加密,我们还有一个最后的保险手段,就是对非常非常重要的配置表,代码等文件,做了一个非对称加密。
![](https://img-blog.csdnimg.cn/img_convert/eb79b84ea0e18886da2517902c9113e4.png)
非对称加密,如果是技术同行的话应该知道,是一个耗时非常久的一个算法,我们如果对完整的文件做非对称加密跟解密,在运行时是不太可能的。
我们采取的做法就是对整个文件做一个哈希,求取它的特征,再对这个特征做一个签名。在没有拿到我们只在公司有的密钥的情况下,外部人员是没办法修改我们的文件,签出跟我们一样签名的。
这个流程我大概列了一下,我们在打包的时候会获取这个文件的具体内容,会对这个文件的内容做一个哈希求值,然后用私钥对这个哈希做签名,再把我们的签名最后的签名段加到文件的头部,最后生成一个资源。
解密就是一个相反的过程:加载的时候我们会加载完整的资源,再截取他的头部签名,再用剩下的部分算一个哈希,再用公钥对这个哈希做一个签名的校验,以此来达成我们每个重要的文件都不可能被修改的目的。
6.然后最重要的一点是我们在《战双》里面对战斗做了一个完全的脱离引擎的剥离。
《战双》里面所有的战斗都可以在服务端复现,我们把战斗内核和表现层完全做了脱离。基于这个东西我们做了几件事情:
![](https://img-blog.csdnimg.cn/img_convert/2326a5bb48358d74f54aef26a484bd79.png)
第一个是做了一个世界状态码,第二个是做了一个服务端校验,第三个是做了一个NPC随机出生。
![](https://img-blog.csdnimg.cn/img_convert/14bd04b1540a98bb89e1022e5a17d5a5.png)
关于第一个世界状态码,我们把当前世界的迹象完整留下是不太可能的。就用了一个比较取巧的方式,对游戏世界里面的相关属性的数值做了一定的算法计算,最后形成一个值。用这个值来代表现在这个游戏世界里面的一个镜像状态,这个状态上传了服务端之后,我们把客户端的操作包还有客户端传上来的每一帧的世界状态码,丢到我们的服务端的,计算战斗内核里,以这个战争内核加上操作数据包和世界状态码做一个校验,最后可以得知一场战斗里面到底哪一帧作弊了,哪一帧的数值有可能被修改。
![](https://img-blog.csdnimg.cn/img_convert/842af364134190c49c6859adc001158b.png)
如果发现我们的世界状态码跟我们客户端放上来的状态码不正确,那这个玩家就可以判别是一个作弊的玩家。
![](https://img-blog.csdnimg.cn/img_convert/6a14c63437d444b786076fb188ad4bb7.png)
那除了以上的这个情况之外,我们还发现有一些工作室会有一些取巧的办法,他们会拿一些相对比较简单的关卡,然后用手动打一遍的方式,然后重复的向我们服务器提交打完的数据包。
基于这个情况,我们做了另一件事情,就是对每一个NPC的出生做了一个随机的波动,这个波动在视觉上是非常非常小的。它是一个1万×2 -32的一个这样的一个范围内的随机数。
![](https://img-blog.csdnimg.cn/img_convert/896dd2e733ee80615401760310de450a.png)
每一个NPC在出生的时候,看起来像在同一个地方出生,实际上它在内部会有一个极小的一个波动,我们视觉上看不出来,但是在数据校验的时候,每一场战斗都不可能一样。
7.最后一方面是战斗相关的数据统计。
我们把所有校验失败的战斗入库,再挑取一些随机的场次,在后台有一套完整的数据校验,对这些战斗做一个完整复算校验,最后会形成一个定向追踪的IP池。
![](https://img-blog.csdnimg.cn/img_convert/2f9a950f83f5c66b6b2eb1bf2ae120f3.png)
如果某一些工作室,长期的对我们的服务器发起一些奇怪的包的攻击,那这些IP会被定向追踪。
最后这整套做下来,之前我们高峰的时候每天会收到接近千万次的这种非法的战斗包。经过我们的一系列的做法,大概维持了半年之后,现在工作室已经完全对我们失去兴趣了。
二、战双的打击感是怎样被一步步打磨出来的?
下面我要稍微介绍一下我们怎么做好《战双》这样一个动作类游戏的。
我把几个主要方面做了拆分,分为攻击方、受击方的动作处理,还有特效对打击感的加持,这部分的内容以展示为主。
第一个方面是攻击方的动作处理,关于这个我们做了战斗动作位移问题的优化,第二个是做了打击的震屏,还有打击的顿帧,最后做了一些镜头轨迹的运算。
第一方面,动作位移,我们在修正前发现一些激烈的战斗动作会产生滑步的现象,大家可以比较明显的看到人物某些技能特效出来的时候,它的脚会跟地面发生位移的,这个是由于我们把技能跟移动分开的做法所导致的。
![](https://img-blog.csdnimg.cn/img_convert/6a73ab72fe5d36bb2564f2861974bc10.gif)
于是我们之后就把一个动作的所有帧的骨骼移动情况全部导出,参与我们人物移动的计算,就达到了基本是每一帧都不可能出现动作跟移动脱离,与地面产生错位的情况。
![](https://img-blog.csdnimg.cn/img_convert/cb579f1178c219625973ed52a6e52a33.gif)
第二方面,我们为了增强打击感做了震屏效果。
![](https://img-blog.csdnimg.cn/img_convert/df45be0fb84583fb904abb67948705ca.gif)
第三方面我们在打击的受击点的那几帧会做时间减缓,达到一个顿帧的效果。
![](https://img-blog.csdnimg.cn/img_convert/f1855a4f6f1d0bda3b81123a9d160caf.gif)
第四个是我们做了一套完整的镜头操作轨迹。
![](https://img-blog.csdnimg.cn/img_convert/fb97ff1b1fede9e7d92fc6b39a6d8ab2.gif)
以上是攻击方的,下面我说一下受击方的。
受击方主要分了5个方面,第一个方面是我们有一个受击动作库。受击方到底是播哪一个受击动作,是由攻击者和受击方共同来决定的。
![](https://img-blog.csdnimg.cn/img_convert/b2609cdfec066960c999ce13fa60ff4c.gif)
在上面的基础上我们做了一个抖动,会根据我的攻击方真实打到我的受击方的受击位置,在它受击的骨骼周围的范围内,做一个骨骼的波动。
![](https://img-blog.csdnimg.cn/img_convert/fd66635506471fdcfe01d0cd8a33fa2d.gif)
![](https://img-blog.csdnimg.cn/img_convert/1f030f29960a3ed776e304bb532744c7.gif)
第三方面是击飞曲线,我们做了一套物理击飞轨迹的计算模块,还有一套跟他相配的击退相关的计算模块。
![](https://img-blog.csdnimg.cn/img_convert/c655db7e7a7a26d26a488a51c9af35b2.gif)
![](https://img-blog.csdnimg.cn/img_convert/2198a6971dd3e226872da74fe0b9b8fa.gif)
最后效果是受击方会根据攻击方攻击帧的时间点,做符合攻击动作的受击动作,所以我们有着非常精准的受击点判定。
![](https://img-blog.csdnimg.cn/img_convert/ea6eedacd42fb6dc96167af6b60d6f24.gif)
下面是关于打斗特效的。特效对我们整个打击感的加持是非常重要的,我们的特效主要分为八个层次。
![](https://img-blog.csdnimg.cn/img_convert/427b8647c831e29ea79092fba8693a8a.png)
首先是最基础的攻击动作跟受击动作;
![](https://img-blog.csdnimg.cn/img_convert/1d8b66afd2b1584a0234f2d2f84885ce.gif)
然后是场景灯光,还有角色灯光;
![](https://img-blog.csdnimg.cn/img_convert/02f39081a0f4978816c1637b1526afe3.gif)
第三为普通特效;
![](https://img-blog.csdnimg.cn/img_convert/c583a40f8d27fa4b96ffde388fd4acea.gif)
接下来是径向模糊,可以在受击的范围内产生一定的模糊效果;
![](https://img-blog.csdnimg.cn/img_convert/1f9c3700af2eaf7436cf409b34948b1c.gif)
接下来是加入大量的GPU粒子,我们把原本基于CPU去做的粒子计算迁移到GPU去,可以达到之前做不到的粒子规模;
![](https://img-blog.csdnimg.cn/img_convert/1f2ee97a474a722f9c5f3a0828e4f9e8.gif)
之后加入空气扭曲,效果可以让人物的剑好像把空气划开了一样;
![](https://img-blog.csdnimg.cn/img_convert/a63b0dcef33aa9a4975b91d4771cd774.gif)
最后是在发动技能的时候会产生场景的变色。
![](https://img-blog.csdnimg.cn/img_convert/9e76d186eb7acf68f9b1a8c72a16d08f.gif)
大家可以看到最终效果就是外界对我们的评价是在打击感方面做得比较好的一个原因,是因为我们做了这一系列的事情,并且这一系列的事情现在还在不断的加强,今年还加了一些新的效果进去,往更强的打击感方面去做。
![](https://img-blog.csdnimg.cn/img_convert/5b20247246eb980d815b6ee55be80a1e.gif)