ApplyJumping() Logic Problem

I'm having some trouble understanding the logic of the ApplyJumping() function of the Unity 2D side scroller tutorial.

function ApplyJumping () {
// UNITY: Prevent jumping too fast after each other

if (jump.lastTime + jump.repeatTime > Time.time)
    return;

if (controller.isGrounded) {
    // UNITY:Jump
    // UNITY: - Only when pressing the button down
    //UNITY: - With a timeout so you can press the button slightly before landing

    if (jump.enabled && Time.time < jump.lastButtonTime + jump.timeout) {

        movement.verticalSpeed = CalculateJumpVerticalSpeed (jump.height);
        movement.inAirVelocity = lastPlatformVelocity;
        SendMessage ("DidJump", SendMessageOptions.DontRequireReceiver);
    }
}

}

If I understand the SendMessage function correctly, this calls the DidJump( ) function:

   function DidJump () {

    jump.jumping = true;
    jump.reachedApex = false;
    jump.lastTime = Time.time;
    jump.lastStartHeight = transform.position.y;
    jump.lastButtonTime = -10;
}

As you can see this function sets lastButtonTime to -10.

In the Update() function lastButtonTime is set to the current time whenever the "Jump" button is pressed:

function Update () {

if (Input.GetButtonDown ("Jump") && canControl) {

    jump.lastButtonTime = Time.time;
}

ApplyJumping();

}

jump.timeout is declared with a value of 0.15 and jump.enabled is declared as true. So lets say the game has just started. We are 10 seconds in when the player presses the spacebar.

Time.time (10) < jump.lastButtonTime (10) + jump.timeout (0.15) is true. This if statement executes. The DidJump() function is triggered. lastButtonTime is set to -10. The character jumps.

He presses spacebar again 0.10 seconds after the first jump. And here I find one of the logic problems...

ApplyJumping() and the Input.GetAxis are both in the Update() function. When the spacebar is pressed the second time will lastButtonTime equal -10, as it was set to when DidJump() was executed, or will it equal Time.time because spacebar was pressed?

Because Input.GetAxis is first in the Update() function logic would seem to suggest that this code is executed first, and therefore lastButtonTime resets to Time.time, but if this is the case then the if statement (Time.time < lastButtonTime + jump.timeout) would always evaluate to true.

The comments from the unity devs say that this code allows you to press the jump button slightly before hitting the ground, allowing you to jump again. I'm not quite seeing the logic. I know it will seem ludicrously simple once someone points out to me what I'm missing.

It's a bit convoluted, but it actually works.

  • Update stores the last time the jump button was pressed (jump.lastButtonTime).
  • ApplyJumping only jumps when:
    • jump.repeatTime seconds have elapsed since jump.lastTime (note that jump.lastTime is different from jump.last*Button*Time)
    • The character is grounded
    • Jumping is enabled
    • The jump button was pressed in the last jump.timeout seconds.
  • When a jump actually occurs
    • lastButtonTime is set back to -10
    • lastTime is set to Time.time.

Storing the button time in Update allows you to press the jump button slightly before landing. In this case, the GetButtonDown event would occur in one frame (when the character was ungrounded), but would be stored and used in a subsequent frame (as long as the character became grounded before jump.timeout seconds had elapsed).

As for your question about pressing the spacebar again 0.10 seconds after the first jump, one of the following would occur:

  • The character would not jump if:
    • jump.repeatTime <= 0.10
    • Jumping is disabled
    • isGrounded == false, and stays false until jump.timeout seconds have passed
  • Otherwise, the character would jump.

Hope this helps!