疾跑

From Minecraft Parkour Wiki
This page is a translated version of the page Sprinting and the translation is 100% complete.
Other languages:

疾跑是一个很重要的机制,它使玩家移动得更快,跳得更远。


触发

疾跑是通过疾跑键双击前进(仅在地面)触发的。

  • 它还可以借助后退键进行激活。无论如何,激活时间都为 7 刻以内。
  • 如果没有按住前进键,玩家就会停止疾跑。
  • 除非按住疾跑键,否则玩家在 30 秒后停止疾跑。
  • 不能在疾跑的同时潜行。(除了在 1.14 以上版本)。
  • 与墙相撞会导致玩家在下一刻停止疾跑。
  • 在空气中疾跑会延迟 1 刻(触发和停止会晚 1 刻)
  • 饥饿、使用物品或受失明影响时,不能触发疾跑。


速度

疾跑的速度比无疾跑快 30%,给予的基本加速度为 0.13。在地面上的渐进速度是 ~0.286m/t。

此外,当玩家在疾跑时跳跃,会向其所朝的方向加速 0.2(不管玩家是否在斜跑)。

  • 这意味着玩家在疾跑跳跃时加速很快,使其成为提高速度的最佳方式。
  • 侧键疾跑跳跃实际上比前进疾跑跳跃慢,而且方向会偏离。但它确实有用途:
    • 用于 Backward Momentum,在普通的疾跑跳跃会带来太多速度的情况下。
    • 用于旋转跳的“Sidestep”技巧。(示例)


代码

下面的代码片段与触发疾跑有关。

/* EntityPlayerSP.java */
public void onLivingUpdate()
{
    if (this.sprintingTicksLeft > 0)
    {
        --this.sprintingTicksLeft;

        if (this.sprintingTicksLeft == 0)
            this.setSprinting(false);
    }

    if (this.sprintToggleTimer > 0)
    {
        --this.sprintToggleTimer;
    }

    //获取玩家在上 1 tick 中的行动。
    boolean prevJumping = this.movementInput.jump;
    boolean prevSneaking = this.movementInput.sneak;
    float f = 0.8F;
    boolean prevMovingForward = this.movementInput.moveForward >= f;
        
    //运动输入被更新(包括moveForward——在潜行时它会被乘以0.3)。
    this.movementInput.updatePlayerMoveState();

    [...]

    //遗留方法:玩家在之前的 Tick 中没有向前移动,但现在移动了。必须在地面上。
    if (!this.isSprinting() && this.onGround && !prevSneaking && !prevMovingForward && this.movementInput.moveForward >= f && isntHungry && !this.isUsingItem() && !this.isPotionActive(Potion.blindness))
    {
        if (this.sprintToggleTimer <= 0 && !keyBindSprint.isKeyDown())
            this.sprintToggleTimer = 7; //时间是 7 刻
        else
            this.setSprinting(true);
        }
        
    //当玩家在上一刻上向前移动时激活
    if (!this.isSprinting() && this.movementInput.moveForward >= f && isntHungry && !this.isUsingItem() && !this.isPotionActive(Potion.blindness) && keyBindSprint.isKeyDown())
    {
        this.setSprinting(true);
    }

        
    if (this.isSprinting() && (this.movementInput.moveForward < f || this.isCollidedHorizontally || !isntHungry))
    {
        this.setSprinting(false);
    }

}



/* 来自 Entity, EntityLivingBase, EntityPlayerSP */
public void setSprinting(boolean sprinting)
{
    this.setFlag(3, sprinting);

    EntityAttribute movementSpeed = this.getEntityAttribute(movementSpeed);

    if (movementSpeed.getModifier(sprintModifierUUID) != null)
        movementSpeed.removeModifier(sprintModifier);

    if (sprinting)
        movementSpeed.applyModifier(sprintModifier); //sprintModifier 会给 multiplier 加上 0.3。

    this.sprintingTicksLeft = sprinting ? 600 : 0;
}


以下是在 1 刻中执行的简化步骤顺序:

  1. 更新疾跑状态
  2. 计算速度并移动玩家
  3. 更新 groundMovementFactorairMovementFactor(疾跑的话乘以 1.3),影响移动速度。


空中疾跑的触发之所以会延迟 1 刻,是因为应用空中移动时游戏获取了 airMovementFactor(在玩家已经移动后更新)。于此相反,当玩家在地面上时,游戏直接从 movementSpeed 中获得乘数,在移动之前更新(在 setSprinting 中获取修饰符)。对于玩家实体 groundMovementFactor 本质上是无用的。