植物大战僵尸吧 关注:563,867贴子:5,103,430

【友好易懂】PVZ僵尸速度完全解析

只看楼主收藏回复

本贴将以尽可能简朴易懂的语言解释一下PVZ里僵尸速度的相关机制。
鸣谢:@Elovi @失控的指令


IP属地:美国1楼2021-04-06 20:12回复
    一、前置知识
    想必聪明的你已经发现了,PVZ里的僵尸可以粗略分为两种,一种匀速前进,另一种非匀速前进。
    匀速僵尸举例:挖地的矿工、投篮、潜行的潜水
    非匀速僵尸举例:扶梯、巨人、普僵
    区分方法很简单。所有靠两腿驱动前进的僵尸都是非匀速僵尸,反之则为匀速。因为根据游戏设定,僵尸坐标随动画改变,所以视觉上由两腿驱动的僵尸,其步伐必然存在一大一小,也就是非匀速。因此,匀速/非匀速之间的区别也可以简单理解为“有无行走动画”。
    定义:把僵尸每厘秒的x坐标变化称作位移。则匀速僵尸= 位移保持不变的僵尸;非匀速僵尸 = 位移随时间变化的僵尸。


    IP属地:美国3楼2021-04-06 20:14
    回复
      2025-07-31 05:09:16
      广告
      不感兴趣
      开通SVIP免广告
      二、相对速度
      参考资料:p/6590729448
      如果你用过随机数修改器,应该对相对速度(也叫速度参数)这个概念并不陌生。
      引用一下rnd的Readme文件:
      小丑速度:小丑、橄榄、奔跑的撑杆、挖掘的矿工、奔跑的潜水的相对速度,参考值0.66-0.68;
      扶梯速度:有梯的扶梯、倭瓜僵尸的相对速度,参考值0.79-0.81;
      海豚速度:海豚、愤怒的报纸的相对速度,参考值0.89-0.91;
      普僵速度:大部分僵尸的相对速度,参考值0.23-0.37;
      实际上,还有一部分僵尸的相对速度是固定的:
      潜行状态的潜水僵尸:0.3
      右行的矿工:0.23(IZ里);0.12(其他关卡)
      IZ里的小鬼:0.90
      右行的雪人:0.80
      其他状态下的雪人:0.40
      舞王/伴舞/跳跳/旗帜:0.45
      大致来说,相对速度越高,僵尸速度就越快;越低就越慢。0.23的巨人走半天还没进场,0.37的巨人已经砸掉玉米炮了。而相对速度固定的僵尸,就代表个体间速度没有差异。
      注意:不要把“相对速度固定”和“匀速僵尸”的概念搞混了。前者指的是僵尸个体间没有速度差异;后者指的是每厘秒坐标变化相同。想想投篮就知道了:每个投篮各自速度不同,但其前进过程中坐标变化始终是匀速的→匀速僵尸,但相对速度不固定。


      IP属地:美国4楼2021-04-06 20:14
      收起回复
        三、从相对速度到位移
        当然了,事情总是没有想象中那么简单。对于匀速僵尸,相对速度越快,位移也越快,符合常理;但非匀速僵尸并非如此。
        换句话说,相对速度为0.81的扶梯并不一定是所有扶梯里最快的!事实上大部分情况下,它都不是最快的那个扶梯,极端情况下最快的扶梯的坐标比他还小3px。

        见上图,来自1000只扶梯的实测。正值代表有其他扶梯比0.81扶梯更快;负值代表0.81扶梯是最快的。


        IP属地:美国5楼2021-04-06 20:16
        回复
          导致这个玄学问题的原因是PVZ计算位移的机制。
          pak文件解包后,compiled/reanim文件夹里含有所有植物及僵尸动画的complied类型文件。对其解包后,可以得到reanim文件,里面ground元素处记录了非匀速僵尸的行走动画。
          比如撑杆的ground部分如下:

          我们只需要关注<x>元素内的浮点数。
          一共有37个浮点数,这其实是对应了奔跑撑杆运动过程中总共37个关键帧。如果计算这些数字间的差值,就可以得到每个运动片段里撑杆的移动量,共36个运动片段。
          对于撑杆来说,这个规律很简单,【0.8、0.8、0.9】一直重复,正好3*12 = 36个运动片段。
          有了以上数据,就能直接算出某僵尸每cs的位移:
          该cs内的位移 = 相对速度 * 当前运动片段移动量 * 47 * 关键帧总数 * 0.01 /所有运动片段移动量总和
          最后一个值的计算方法很简单,前面那37个浮点数里用最后一个减去第一个即可。对于撑杆来说,是 -29.8 - (-59.8) = 30。
          代入公式。撑杆每cs的位移= (0.66~0.68) * (0.8~0.9) * 47 * 37 * 0.01 / 30 = 0.306~0.355px。


          IP属地:美国6楼2021-04-06 20:17
          收起回复
            当然,还有一个问题是怎么确定“当前运动片段”。这里引入一个概念:动画进度,为0~1间的一个浮点值。对于一只持续奔跑的撑杆而言,动画进度每cs的增量是固定的,记作Δ,那么Δ = 相对速度 * 47 *0.01 / 所有运动片段移动量总和。撑杆出生的那一帧,动画进度初始化为Δ,之后每帧加Δ,若超过1则减去1。
            PS:僵尸进行【啃食】、【投掷】、【举锤】动作时,行走动画进度会被重置,这也就是常说的“相位重置”。这些动作执行完毕后,动画进度会重新从Δ开始。
            而当前运动片段就是int(动画进度* 运动片段总数 + 1)。注意运动片段总数不是关键帧总数,前者比后者少1。
            假设有一只相对速度为0.66的撑杆。Δ = 0.66 * 47 * 0.01 / 30 = 0.0134,所以其出生时动画进度为0.0134。而int(0.0134 * 36 + 1) = 1,所以此时撑杆在第1个运动片段内,对应的移动量是0.8。因而这一帧里,撑杆的位移是 0.66 * 0.8 * 47 * 37 * 0.01 / 30 = 0.306064。


            IP属地:美国7楼2021-04-06 20:18
            回复
              四、玄学问题的解决
              已知0.664933撑杆比0.66撑杆还慢。这个看似玄学的问题,其实现在就很好解释了。
              见下图:

              由于运动片段的计算方式,0.664933撑杆只在快速片段(第3段,对应移动量为0.9)停留了2帧,但0.66撑杆停留了3帧。也因此,运动片段分配的不均匀抵消了相对速度上的差距,使得0.664933的撑杆实际上更慢。
              因为撑杆的运动还算简单(移动量只在0.8、0.9间切换),如果是像扶梯这样移动量变化剧烈的,就很容易出现相对速度慢的扶梯反而(在某一时刻)更快的现象。

              如图,来自1000只扶梯的实测。x轴为时刻,y轴为当前帧里最快的扶梯的相对速度。可以清楚地看见0.81扶梯是最快的情况寥寥无几。


              IP属地:美国8楼2021-04-06 20:21
              回复
                五、IZE里的彩蛋:速度重置
                以下内容仅对IZ类关卡适用,且具体机理早已有定论,在此仅作补充。
                僵尸放下后,若5s内不受攻击,进入速度重置;受过攻击的僵尸若5.25s内不受攻击,进入速度重置。进入此状态后,【僵尸的相对速度每一帧都会重置】,连续起来就是匀速前进。受到伤害后此状态结束,速度重置到哪里就停留在哪里。


                IP属地:美国10楼2021-04-06 20:21
                收起回复
                  2025-07-31 05:03:16
                  广告
                  不感兴趣
                  开通SVIP免广告
                  六、结语
                  对于一般玩家,知道以上这些有什么用呢?一个是对于非匀速僵尸,rnd锁出的极值并不完全代表最慢/最快,可能存在几px/几cs的误差,所以脚本出bug的时候先别急着怪键控框架,万一只是因为你把数据卡太死了呢
                  其二是扶梯啃炮的极限波长又缩短了。喜闻乐见,虽然本来就已经挺短的了。另外一个小贴士:存在268cs的垫才不等效于延长268cs极限波长,现在看来对于8炮,其实际效果仅200cs左右,所以就算垫才不被炸不被提前啃掉扶梯也是可以啃炮的(可以重新录制)。
                  对于懂数据的玩家而言,有以上这套公式就足以正推逆推僵尸的精确位移与坐标了。以常见的内存表为准,相对速度→僵尸横向相对速度;关键帧总数→关键帧数量;动画进度→动画循环率。
                  一些没有信心能发出来的链接:

                  全贴完,楼下沙发。


                  IP属地:美国11楼2021-04-06 20:23
                  回复


                    IP属地:安徽来自Android客户端12楼2021-04-06 20:26
                    回复
                      沙发,日渐强


                      IP属地:四川来自Android客户端14楼2021-04-06 20:26
                      收起回复
                        沙……板凳


                        IP属地:北京来自Android客户端15楼2021-04-06 20:26
                        回复
                          所以楼主就是把零度和小e的结论整理一下发了出来


                          来自iPhone客户端16楼2021-04-06 20:27
                          收起回复
                            我爱渐强


                            IP属地:上海来自Android客户端17楼2021-04-06 20:38
                            收起回复