KZ
Author

admin

落地为什么要接狗跳?——“耐力”机制

译者:太长不看

CS 存在名为 fuser2 的参数,会对玩家产生以下影响:

  • 正常起跳落地后存在一段硬直时间,硬直时间内玩家水平移动速度会非常慢,这是由于玩家的水平速度是通过基本速度乘以一个受到 fuser2 影响的系数计算而来的
  • 连续的常规跳跃高度(约为 44 u)将比第一次起跳高度低不少(约为 33 u),连续跳跃过程中在正确时机按蹲(玩家模型抬高 18 u,参见 关于“下蹲”你需要知道的事)可将滞空时间延长,将下一次跳跃高度提高至 34 u 左右,这也就解释了为什么弹跳比连跳更远。

小跳、狗跳不属于常规跳跃范畴,不受 fuser2 影响,因此,在玩家跳跃落地时使用小跳或狗跳进行衔接能够起到一定的缓冲的效果(保持落地前的空速,期间 fuser2 继续减少为 0)。在实践中,通常采用狗跳而非小跳,其原因在于单次小跳滞空时间太短,不能使 fuser2 完全减少为 0

耐力与 fuser2

我们在游戏中俗称的“耐力(stamina)”实际上是由代码中一个名为 fuser2 的变量参数所决定的。早期的 CS 版本中并没有这个参数,而是历经游戏版本的数次迭代最终加入的。

fuser2 在玩家在出生点复活时初始化为 0,随后,每一次跳跃都会将该值置为 1315.789429

void PM_Jump() {
  ...
  pmove->fuser2 = 1315.789429;
  ...
}

在随后的跳跃过程中,fuser2 在每一帧中减去帧长(即刷新一帧时间,以毫秒为单位)。于是,在帧率为 100 fps 的情况下(帧长为 10 ms),每一帧中 fuser2 减少 10,大约需要 1.31 sfuser2 才会减为 0,停止其对玩家运动的影响。

译注

1 s = 1000 ms

当在一帧中 fuser2 减为负数时,其值被设置为 0。

void PM_ReduceTimers() {
  ...
  if (pmove->fuser2 > 0.0) {
    pmove->fuser2 -= pmove->cmd.msec;
    if (pmove->fuser2 < 0.0) pmove->fuser2 = 0;
  }
  ...
}

该变量还在引擎的 PM_WalkMove()PM_Jump 函数中使用,由该变量还会引起 velocity 向量中其他三个成员的变化,即垂直速度和水平速度的变化。

译注

水平速度包含 x 轴和 y 轴方向上的速度。

PM_WalkMove()

玩家在地面上的每一次移动都会调用该函数。

假设 fuser2 大于 0,其值将被用于限制玩家的水平速度 (velocity.x, velocity.y)。水平速度乘以一个通过如下方式计算的系数 factor

    factor = (100 - pmove->fuser2 * 0.001 * 19.0) * 0.01;

跳跃的时间越短(fuser2 值越大),factor 的值越小,这就意味着您在着陆后开始移动时会出现的减速越大(水平速度最终乘以该系数)。这也就回答了为什么您在每次跳跃落地之后走得会更慢,当您由低处向高处跳跃着陆在一个高处的平台上时,这种减速将更为严重。

PM_Jump()

顾名思义,该函数在玩家每次跳跃时调用。此函数中,fuser2 被用于限制玩家的垂直速度 velocity.z。其系数计算方式如下:

    factor = (100.0 - pmove->fuser2 * 0.001 * 19.0) * 0.01;

由于 PM_Jump()fuser2 的存在,连跳中后续的跳跃高度将会比第一次起跳时更低。考查在相同高度的地面上起跳,从起跳到落地的滞空时间为 0.66 s,这不足以使 fuser2 恢复为 0(需要 1.31 s)。

另外,有了上述背景知识,您就能够理解这样的现象:进行弹跳时由于按蹲使得滞空时间更长,进而使 fuser2 参数减少了一点,让我们在下一次起跳时拥有了稍高于连跳的起跳高度。