疾跑

    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,在普通的疾跑跳跃会带来太多速度的情况下。
      • 用于需要转头的跳跃的 "侧身"技术。(示例)


    代码

    下面的代码片段与触发疾跑有关。
    /* 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 本质上是无用的。