暗黑3野蛮人攻速讨论:Thinking In IAS
新闻导语
我所说的很多东西,都是基于假设,测试结果接近也不能说明他就一定是对的,未必可靠,只有官方说的才可靠。
七 对表进一步修正
前面我们推出了帧数-攻速-攻击次数表,并收集了一些数据,但仔细将这些数据与表对照,是有问题的,主要是2个:
1)比如2.01攻速应该是30F,1分钟120下,实测是124下,也就是实测打击数多余预测。
2)比如1.98和2.01攻速没有发生变化都是124,变化发生在2.01个和2.04之间,变成了128,但根据这个表,断点应该是2.00整,变化应该发生在1.98和2.01之间才对。前面在做小旋风测试的时候,断点也确实是发生在2.00,他就没这问题。
发现了这两个问题后,我又做了一个更直观的测试。1.00攻速,打5分钟,结果:
攻速 | 总伤害 | 暴击次数 | 非暴击次数 | 5分总次数 | 每分次数 |
1.000 | 215380 | 22 | 288 | 310 | 62 |
1.0攻速5分钟打出了310次,每分钟62次,这很奇怪,用传统的想法,攻速1.0么一分钟应该60次,解释不了;用我的理论,1.0攻速正好是 60F的断点,达到1.0就应该意味着每次猛击的时间是60F,一分钟3600F,应该也是正好60次才对,即使1.0是算作59F,那根据表也应该是 61次/分,还是解释不了。
其实这个现象我已经不止一次的看到有人提出过了,因为这很容易观察到,打2分钟,发现打出来的次数比120多,或者打120下,发现用时不到120秒,即使用更粗糙目测+秒表,这个现象也很明显。接下来我试图对这个现象进行解释。
前面写的东西,都是客观的,但从这里开始,已经既没有官方的结论,也没有D2的经验可供参考,完全是我的主观推测,伴随着各种假设,以及去分析假设靠不靠谱,所以不要认为我接下去说的都一定是对的,很可能完全不是这么回事儿。如果你对这些不是很确定的东西不感兴趣,那么读到这里就可以结束了,截止第六段已经可以说明一些问题。 愿意读下去的人,可以帮我一起把遗留的问题解决。
为了解释1.0攻速1分钟打出62次这个现象,我做了两种假设:
1)1秒不是由精确的60F构成的,可能是62,或者说1F的时间不是精确的1/60秒,可能是1/62秒。一秒62F,1分钟3720F,一次攻击60F,那就会有62次。
2)依然是1秒钟精确的60F,这不变,但由于某种原因,在攻击过程中,一个完整的攻击动作中的某几个F被吃掉了,一个本需要60F时间完成的猛击动作,只用了58F的时间就打完了,一分钟还是3600F,每击只花了58F,就有62次。
以上两种假设都是有可能的,我个人比较偏向于第二种
假设一:我觉得这种假设可能性不大的原因有两个,一是因为现在的技术要做到准确的一秒60F并不难,二是经过一些研究,我觉得1F确实是1/60秒,回到前面尾气测试时贴的2.01 2.04这两个攻速的视频,我用他们来找1F的时间长。
在尾气测试中,我们知道尾气无论是断点的位置,还是在某个F值时的跳数,都是与理论计算出的表格完全符合的,他并没有猛击这样断点位置和攻击次数发生偏离的问题。他没有发生问题,我的猜测是因为连续猛击是由若干个独立的动作拼接而成的,在拼接的过程中可能会出问题,而一次小旋风的若干跳,他们是一个不可分割的整体,是一次成型的,所以我觉得去观察小旋风是靠谱的。
在2.01 2.04尾气这两个视频中,我保留了白字没有关闭,用来观察F的长度。视频的采样率是60,也就是视频里的一秒是由60张画面组成的,每张画面长1/60 秒,如果游戏中的1F确实是1/60秒的话,视频里每一副画面的时间长短就应该与1F相等,虽然他的生成节奏可能和F不同步,但时长是一致的。两个视频我都采用逐画格播放,按一下键盘,放一格,来观察到底用了多少格画面,即多少个1/60秒来完成这些跳。
在这两个攻速时,小旋风每跳都是9F,总共都应该是20跳。攻击动作都会有前摇,判定,后摆的过程,由于小旋风一直是那个样子,我看不清的前摇从哪里开始后摆到哪里结束,就只能从判定点来看,于是从第一次产生伤害,到最后一次产生伤害,这样去掉了第一跳的前摇,和最后一跳的后摆,总共就是19跳的时间,应该是9*19=171F。如果1F的长度确实等于1/60秒,那么这断时间也应该有171个画格,至少比较接近。观察下来的结果是:
2.01的视频中,第一跳从6分第8格开始,9分01格结束,一共173格
2.04的视频中,第一跳从5分第11格开始,8分01格结束,一共170格。
如果像假设一中说的,一秒有62F,每跳应该是9/62秒,19跳应该是19*9/62秒=19*9*60/62格=165格。
显然170和173还是更接近于171而不是165. 所以通过这个研究我觉得1F的时间应该就是1/60秒整,他不会被挤压。
假设二:既然研究表明1F应该就是1/60秒没问题,那么可能性就更倾向于假设二了,一个攻击动作的某几个F被吃掉了。为甚么会这样,前面已经有提到,因为我们在按住鼠标连续攻击时,这些攻击是有若干个动作连接形成的动作序列,你单独打一下猛击就停,根据攻速,他应该耗时比如20F,这没问题,但当按住鼠标连续打很多个猛击的时候,比如按住鼠标让他打10下,就不是200个F,某些F被吃掉了或者说丢失了,变成了可能190F,于是只需要比原来更短的时间就能打完。为甚么会这样,我说不出绝对正确的理由,只能继续假设。好吧,在假设里还要做假设。。。
接下来假设为甚么某些F会丢失,是怎么丢失的。
假设三:当你按住鼠标,等于不停的在向游戏发出攻击的指令,也就是你发送的比他执行的快,游戏受到这些来不及执行的指令时,生成一个指令序列,动作 1连着动作2连着动作3这样,在链接的过程中,发生了损耗,就好比你要把一些断掉的细纸条链接起来,你需要在每一条的末尾涂一些胶水,把后一条粘上来,这样就使断裂的纸条产生了连贯性,当然问题就是每一个纸条比原来短了一点,因为涂胶水的部分被后一条覆盖了。 既要把纸条连接起来,又不能损失一丝长度,现实中是做不到的。所以我猜测在游戏中,为了保证动作的连续性,也可能损失一点长度。
为甚么尾气没有问题,因为他是作用在怪身上的,你仍出去一个尾气,接下来他就是自己运作,与你本身不构成动作序列的关系,于是就不需要拼接,就没问题。
如果确实是这样的话,那本来一个10F的猛击,会变成9F,或者8F,一个60F的猛击会变成59F或者58F。等于每个攻速对应的F值会比表中低 1-2,这个看起来还算有点味道,比如测试中的1.74攻速 109跳,本来1.74攻速应该对应1.71的35F,给他减2F变成33F后,正好对应109次。
但这个假设还是有问题,你会发现,测试数据中,某些攻速需要-1F来看表,而有些又是需要-2F,这个无法解释。还有,降1-2个F看表不会改变表上的那些数字,这样依然无法解释为甚么会出现186次,这个数值。
总之这个假设感觉还是不太对,我觉得是因为我把F丢失的方式想的太简单了,确实,一款2012年的游戏,动作序列的连接,做的像连纸条这么简单,也是稍微扯淡了点。。。有必要把他想的再复杂一些。
假设四:我尝试来设计一套更复杂连接方式。
根据平时的游戏经验,我想到一个东西,半秒,有些东西以半秒为单位来显示,比如回血绿字,半秒一跳,他就像是一个结算周期,是一个比F更大的时间单位,之后我称一个半秒为1U。现实中,我们用毫秒,秒,分等单位来衡量时间,而游戏系统内,是以F和U为单位来计算时间,拍一巴掌需要几F,拍死一只怪需要几U,应该这样来说。
按理说1秒=60F,半秒应该是30F,但我要假设的是1U=31F,也就是1U实际比半秒长一点点=31/60秒,1F还是稳定的1/60秒。
为甚么我假设1U=31F,31这个数字,对编程来说也是有一定特殊性的。编程时经常会去用一些2的整数次方的数字,比如2^5=32。所以我会准备一个32个格子的容器U去存放F,并且编程中我们知道,各种容器,数组啊,集合啊,等等,格子的编号都是从0开始的,第一格编号是U[0],第二格是 U[1],依次。为了方便,很可能第一格留空,如果从第一格开始放,会变成U[N]里放的是第N+1个单位,后续调用很麻烦,从第二格开始放,这样格子的编号与单位的编号就一致了,比如编号是U[N]的格子放第N个单位,会比较比方便。这样一共32个格子,第一格空掉,使用的就是从U[1]到U[31]这 31个格子,U[0]空着不用。
说这些东西只是我想说明以1U=31F来作为一个游戏内时间计量单位,以一个32格的容器来制作U,这些在编程时的可能性是有的。
回到动作序列的连接,在假设三中我提出直接把各个动作连起来,这种方式不光是过于简单,而且实现上会受更多其他因素的干扰,因为每个动作的时间太短了只有几F,也许会受网络等因素干扰。相比之下,1U是一个比较长的时间单位,受影响的机会要小的多,所以更好的方式是,先把将要执行的每个动作放进一个更大的大容器U里,然后再去连接这些U。就像先把东西装进车厢,然后连接车厢变成火车。如果一3个动作是10F 10F 11F,正好放进一个U里,如果一个动作比较长,比如有40F,那么前31F放在第一个U1里,后9F放在U2里,这样。
当我们给游戏发送连续的游戏指令时,比如按住鼠标说攻击攻击攻击,就生成了动作序列,序列生成的方式就是一个U接一个U这样拼上去。拼U的人并不关心U里装的是甚么,他只管把1个个U拼起来并且保证一秒正好由2个U组成,由于每个U的长度是32格(第一格空着,二到最后一格存放这动作内容),直接拼时间会凑不拢,于是,这个拼接工把每个U去头去尾,变成30格即30F的长度,组装,就正好是整数秒了。去头没关系,头本来就是空的,去尾就有问题了,这里是存着东西的,但没办法,这一格里的F就被吃掉了,丢失了。
每秒由2U拼接成,每U丢失了1F,这样,等于每秒会丢失2F。这2个U里原本装着62个F,其中第31F和第62F在拼接时被吃掉了。
这样的话,游戏用1秒60F的时间,就能完成了62个F的动作,因为其中2F被吃掉了,不用表现了,这便是假设4得出的结论。看上去和假设一有点像,都提到了62F,但是不一样的。假设一里的一秒62F,是在1秒里确实装了62个F,每个F的时间被挤压了,假设四里的1秒62F,每个F的时间还是 1/60秒,没被挤压,只是有2个F丢失了,1秒里装的还是60个F。
造成这个问题的原因,我觉得是程序制作时的一个失误,设计者肯定是希望1.0攻速打一分钟出现60次攻击的,现在出现62次肯定不是他故意为之。在 1个U里,如果只储存30个F,头尾都空掉,就没问题了,拼接的时候去头去尾正好去掉两个空格,设计初衷应该是这样,但可能在实现时的忽略,把最后一格也存了一F,问题就发生了。其实平时编程时,诸如搞错数组序号这种事是很常见的错误,也没甚么稀奇。
根据假设四,1分钟60秒,能够用来完成60*62=3720F的动作,当然实际的时长还是3600F,能在3600F完成3720F的动作,因为 120个F在拼接时丢失了。也就是说,如果一个动作需要20F的时间,在假设四这样的机制下,1分钟能完成3720/20=186次。Oyeah,我很欣喜的发现我得到了186这个之间无法解释的数字。 同理,用3720/不同的帧数,就能得到在这个帧数下1分钟的攻击次数,于是我们得到一张修正表。
帧数 | 攻速 | 理论每分次数 | 修正次数 | 帧数 | 攻速 | 理论每分次数 | 修正次数 |
60 | 1.000 | 60.00 | 62.00 | 30 | 2.000 | 120.00 | 124.00 |
59 | 1.017 | 61.02 | 63.05 | 29 | 2.069 | 124.14 | 128.28 |
58 | 1.034 | 62.07 | 64.14 | 28 | 2.143 | 128.57 | 132.86 |
57 | 1.053 | 63.16 | 65.26 | 27 | 2.222 | 133.33 | 137.78 |
56 | 1.071 | 64.29 | 66.43 | 26 | 2.308 | 138.46 | 143.08 |
55 | 1.091 | 65.45 | 67.64 | 25 | 2.400 | 144.00 | 148.80 |
54 | 1.111 | 66.67 | 68.89 | 24 | 2.500 | 150.00 | 155.00 |
53 | 1.132 | 67.92 | 70.19 | 23 | 2.609 | 156.52 | 161.74 |
52 | 1.154 | 69.23 | 71.54 | 22 | 2.727 | 163.64 | 169.09 |
51 | 1.176 | 70.59 | 72.94 | 21 | 2.857 | 171.43 | 177.14 |
50 | 1.200 | 72.00 | 74.40 | 20 | 3.000 | 180.00 | 186.00 |
49 | 1.224 | 73.47 | 75.92 | 19 | 3.158 | 189.47 | 195.79 |
48 | 1.250 | 75.00 | 77.50 | 18 | 3.333 | 200.00 | 206.67 |
47 | 1.277 | 76.60 | 79.15 | 17 | 3.529 | 211.76 | 218.82 |
46 | 1.304 | 78.26 | 80.87 | 16 | 3.750 | 225.00 | 232.50 |
45 | 1.333 | 80.00 | 82.67 | 15 | 4.000 | 240.00 | 248.00 |
44 | 1.364 | 81.82 | 84.55 | 14 | 4.286 | 257.14 | 265.71 |
43 | 1.395 | 83.72 | 86.51 | 13 | 4.615 | 276.92 | 286.15 |
42 | 1.429 | 85.71 | 88.57 | 12 | 5.000 | 300.00 | 310.00 |
41 | 1.463 | 87.80 | 90.73 | 11 | 5.455 | 327.27 | 338.18 |
40 | 1.500 | 90.00 | 93.00 | 10 | 6.000 | 360.00 | 372.00 |
39 | 1.538 | 92.31 | 95.38 | 9 | 6.667 | 400.00 | 413.33 |
38 | 1.579 | 94.74 | 97.89 | 8 | 7.500 | 450.00 | 465.00 |
37 | 1.622 | 97.30 | 100.54 | 7 | 8.571 | 514.29 | 531.43 |
36 | 1.667 | 100.00 | 103.33 | 6 | 10.000 | 600.00 | 620.00 |
35 | 1.714 | 102.86 | 106.29 | 5 | 12.000 | 720.00 | 744.00 |
34 | 1.765 | 105.88 | 109.41 | 4 | 15.000 | 900.00 | 930.00 |
33 | 1.818 | 109.09 | 112.73 | 3 | 20.000 | 1200.00 | 1240.00 |
32 | 1.875 | 112.50 | 116.25 | 2 | 30.000 | 1800.00 | 1860.00 |
31 | 1.935 | 116.13 | 120.00 | 1 | 60.000 | 3600.00 | 3720.00 |
这张表看起来就比较靠谱了。与前面的一些测试结果差异也很小(我是指跳数上的差异比较小,断点位置的差异还是有的,这个下一步再解决)
再做一个测试来说明假设四比假设三更靠谱,通过表的走势可以看到,随着攻速的提升,攻击次数的变化也就跨度就越大,要验证哪一种假设更靠谱,比较好的办法是制造一个高攻速,看看他的攻击次数更接近哪种假设。
我做了3.816攻速,双持2把1.8速度的匕首,穿除了旧祖鞋外所有的满值攻速装,加变身。结果:
攻速 | 总伤害 | 暴击次数 | 非暴击次数 | 总次数 |
3.816 | 807047 | 31 | 202 | 233 |
(两把匕首的最小值是一样的,所以在饰品的最小值属性加成后,主副手的DPH一样,打出的数字一样,还是可以用同样的办法来统计攻击次数)
1分钟233次,这个数字在修正后的每分次数中可以找到,对应16F 3.750攻速的232.5次。而在原来的理论次数中,没有与之对应的数值225 240都差的很远,按照假设三的少看1-2个F去找,找不到,说明假设三不靠谱。
最后的这个高攻速测试应该可以表明,我的假设四还是有点谱的,毕竟在高攻速下,攻击次数的跳跃幅度是很大的,根据假设的修正能与实测很接近,应该不是巧合了。
八 遗留的问题和结论
最后通过假设四我依然没有解决的问题是,为甚么断点不是出现在60/N这些位置。这个很遗憾,这也是我长篇大论的主要原因,我想让看的人了解我的想法,帮我想想为甚么断点会偏移,偏移到哪去了。我不想用大量的实测去逐个逼出断点的位置,这样还是搞不清为甚么,肯定是有某个原因在里面的,还是先想出原因,算出理论值,再用实测去验证比较好。
更新,我暂时找清出断点位置,可以作为一个初步结论,还是比较准确的,可以作为参考,这张表适用于猛击,先祖:
帧数 | 每分钟攻击次数 | 攻速 | 帧数 | 每分钟攻击次数 | 攻速 |
60 | 62.00 | 0.983 | 30 | 124.00 | 1.967 |
59 | 63.05 | 1.000 | 29 | 128.28 | 2.034 |
58 | 64.14 | 1.017 | 28 | 132.86 | 2.107 |
57 | 65.26 | 1.035 | 27 | 137.78 | 2.185 |
56 | 66.43 | 1.054 | 26 | 143.08 | 2.269 |
55 | 67.64 | 1.073 | 25 | 148.80 | 2.360 |
54 | 68.89 | 1.093 | 24 | 155.00 | 2.458 |
53 | 70.19 | 1.113 | 23 | 161.74 | 2.565 |
52 | 71.54 | 1.135 | 22 | 169.09 | 2.682 |
51 | 72.94 | 1.157 | 21 | 177.14 | 2.810 |
50 | 74.40 | 1.180 | 20 | 186.00 | 2.950 |
49 | 75.92 | 1.204 | 19 | 195.79 | 3.105 |
48 | 77.50 | 1.229 | 18 | 206.67 | 3.278 |
47 | 79.15 | 1.255 | 17 | 218.82 | 3.471 |
46 | 80.87 | 1.283 | 16 | 232.50 | 3.688 |
45 | 82.67 | 1.311 | 15 | 248.00 | 3.933 |
44 | 84.55 | 1.341 | 14 | 265.71 | 4.214 |
43 | 86.51 | 1.372 | 13 | 286.15 | 4.538 |
42 | 88.57 | 1.405 | 12 | 310.00 | 4.917 |
41 | 90.73 | 1.439 | 11 | 338.18 | 5.364 |
40 | 93.00 | 1.475 | 10 | 372.00 | 5.900 |
39 | 95.38 | 1.513 | 9 | 413.33 | 6.556 |
38 | 97.89 | 1.553 | 8 | 465.00 | 7.375 |
37 | 100.54 | 1.595 | 7 | 531.43 | 8.429 |
36 | 103.33 | 1.639 | 6 | 620.00 | 9.833 |
35 | 106.29 | 1.686 | 5 | 744.00 | 11.800 |
34 | 109.41 | 1.735 | 4 | 930.00 | 14.750 |
33 | 112.73 | 1.788 | 3 | 1240.00 | 19.667 |
32 | 116.25 | 1.844 | 2 | 1860.00 | 29.500 |
31 | 120.00 | 1.903 | 1 | 3720.00 | 59.000 |
如果你的攻速达不到下一档,那就只有上一档的攻击次数,比如攻速是1.98,没有达到会突变的2.034,那实际就只有1.967的攻速,1分钟只能打出124下。
相关阅读:暗黑3
- (2024-12-27) 暗黑3 猎魔人输出心得 娜套站桩输出方法
- (2024-12-26) 暗黑3 猎魔人速刷技巧与跑酷心得分享
- (2024-12-25) 暗黑3 辅助圣教军高层秘境冲榜打法攻略
- (2024-12-24) 暗黑3 野蛮人和猎魔人嘲讽流装备属性推荐
- (2024-12-23) 暗黑3 武僧无限疾风击高层秘境装备技能选择