[BUG + Possible Fix] DoubleJump does not work when running off a ledge

Leorid

New member
The repeated jump does not work when the character does not jump from grounded state.

Expected behaviour: Character runs off a cliff -> is in mid air -> user presses the jump button -> Character uses the repeated jump

Current behaviour: repeated jump will not be used, unless the Charater jumps off the cliff

Fix at line 150 in Jump.cs, right below the "else" from the if (m_CharacterLocomotion.Grounded) { }else{ },
insert:

C#:
                // allow repeated jump even if the character did run off a ledge and did not jump
                // in the first place
                if (m_RepeatedJumpCount < m_MaxRepeatedJumpCount)
                {
                    m_JumpApplied = true;
                    return true;
                }


full CanStartAbility() method below:

C#:
        public override bool CanStartAbility()
        {
            // An attribute may prevent the ability from starting.
            if (!base.CanStartAbility()) {
                return false;
            }

            if (m_MinCeilingJumpHeight != -1) {
                // Ensure the space above is clear to get off of the ground.
                if (m_CharacterLocomotion.SingleCast(m_CharacterLocomotion.Up * (m_MinCeilingJumpHeight + m_CharacterLocomotion.SkinWidth + m_CharacterLocomotion.ColliderSpacing),
                                                        Vector3.zero, m_CharacterLayerManager.SolidObjectLayers, ref m_RaycastResult)) {
                    return false;
                }
            }

            if (m_CharacterLocomotion.Grounded) {
                // The character can't jump if they aren't on the ground nor if they recently landed.
                if (m_LandTime + m_RecurrenceDelay > Time.time) {
                    return false;
                }

                // The character can't jump if the slope is too steep.
                var slope = Vector3.Angle(m_CharacterLocomotion.Up, m_CharacterLocomotion.GroundRaycastHit.normal);
                if (slope > m_CharacterLocomotion.SlopeLimit) {
                    return false;
                }
            } else {
                // allow repeated jump even if the character did run off a ledge and did not jump
                // in the first place
                if (m_RepeatedJumpCount < m_MaxRepeatedJumpCount)
                {
                    m_JumpApplied = true;
                    return true;
                }
                // Allow the ability to start if the character is in the air before the grounded grace period. This allows the character to run off a ledge but still
                // be able to jump. The character may also be able to do a repeated jump even if the character isn't grounded.
                if ((!m_JumpApplied && m_InAirTime + m_GroundedGracePeriod <= Time.time) ||
                    (m_RepeatedJumpCount != -1 && m_RepeatedJumpCount > m_MaxRepeatedJumpCount) ||
                    (m_JumpTime != -1 && m_JumpTime + m_RecurrenceDelay > Time.time)) {
                    return false;
                }
            }
 
The repeated jump does not work when the character does not jump from grounded state.

Expected behaviour: Character runs off a cliff -> is in mid air -> user presses the jump button -> Character uses the repeated jump

Current behaviour: repeated jump will not be used, unless the Charater jumps off the cliff

Fix at line 150 in Jump.cs, right below the "else" from the if (m_CharacterLocomotion.Grounded) { }else{ },
insert:

C#:
                // allow repeated jump even if the character did run off a ledge and did not jump
                // in the first place
                if (m_RepeatedJumpCount < m_MaxRepeatedJumpCount)
                {
                    m_JumpApplied = true;
                    return true;
                }


full CanStartAbility() method below:

C#:
        public override bool CanStartAbility()
        {
            // An attribute may prevent the ability from starting.
            if (!base.CanStartAbility()) {
                return false;
            }

            if (m_MinCeilingJumpHeight != -1) {
                // Ensure the space above is clear to get off of the ground.
                if (m_CharacterLocomotion.SingleCast(m_CharacterLocomotion.Up * (m_MinCeilingJumpHeight + m_CharacterLocomotion.SkinWidth + m_CharacterLocomotion.ColliderSpacing),
                                                        Vector3.zero, m_CharacterLayerManager.SolidObjectLayers, ref m_RaycastResult)) {
                    return false;
                }
            }

            if (m_CharacterLocomotion.Grounded) {
                // The character can't jump if they aren't on the ground nor if they recently landed.
                if (m_LandTime + m_RecurrenceDelay > Time.time) {
                    return false;
                }

                // The character can't jump if the slope is too steep.
                var slope = Vector3.Angle(m_CharacterLocomotion.Up, m_CharacterLocomotion.GroundRaycastHit.normal);
                if (slope > m_CharacterLocomotion.SlopeLimit) {
                    return false;
                }
            } else {
                // allow repeated jump even if the character did run off a ledge and did not jump
                // in the first place
                if (m_RepeatedJumpCount < m_MaxRepeatedJumpCount)
                {
                    m_JumpApplied = true;
                    return true;
                }
                // Allow the ability to start if the character is in the air before the grounded grace period. This allows the character to run off a ledge but still
                // be able to jump. The character may also be able to do a repeated jump even if the character isn't grounded.
                if ((!m_JumpApplied && m_InAirTime + m_GroundedGracePeriod <= Time.time) ||
                    (m_RepeatedJumpCount != -1 && m_RepeatedJumpCount > m_MaxRepeatedJumpCount) ||
                    (m_JumpTime != -1 && m_JumpTime + m_RecurrenceDelay > Time.time)) {
                    return false;
                }
            }
Awesome fix man. I may use it in future.
Makes me think of the jump behaviour in super smash bros.
 
Have you tried increasing the Grounded Grace Period float (also known as coyote time)? This should allow you to jump even after the character is in the air. With a larger grace period time it will play the regular jump force, not the repeated jump force.
 
Have you tried increasing the Grounded Grace Period float (also known as coyote time)? This should allow you to jump even after the character is in the air. With a larger grace period time it will play the regular jump force, not the repeated jump force.

Yes but it should use the repeated jump if he is falling for more than half a second, because when you can jump in mid air, no one expect a condition like "you have to jump to have a second jump" - therefor I wrote this quick fix to match the mechanics with other games out there. ^^ (Destiny 2, Spiderman, [PROTOTYPE], Doom, Battlefront, Star Wars the Force Unleashed, Devil May Cry, Sonic, Unreal Tournament, Risk of Rain 2, Rayman, ..)

PS: I'd like to see this change in the next update, thats why I wrote this, not to offend anyone of course.
 
Last edited:
Ah, I see. In that case what you could do is set GroundedGracePeriod to a really high value which would then allow you to perform the jump at any time after falling from a ledge. I'll make a change so that if the value is -1 then the grounded grace period will allow any jump (code below).

This should then get similar results, and I like it a bit better because JumpApplied isn't being set within CanStartAbility. Thank you for letting me know :)

Code:
                // Allow the ability to start if the character is in the air before the grounded grace period. This allows the character to run off a ledge but still
                // be able to jump. The character may also be able to do a repeated jump even if the character isn't grounded.
                if ((!m_JumpApplied && m_GroundedGracePeriod != -1 && m_InAirTime + m_GroundedGracePeriod <= Time.time) ||
 
Last edited:
JumpApplied isn't being set within CanStartAbility.
Well but when jumpApplied is not set within the CanStartAbility, it will take the wrong path inside AbilityStarted().
Because theres the IF:

C#:
            if (m_JumpApplied) {
                OnRepeatedJump();
            } else {
                if (!m_JumpEvent.WaitForAnimationEvent || m_ForceImmediateJump) {
                    Scheduler.ScheduleFixed(m_ForceImmediateJump ? 0 : m_JumpEvent.Duration, ApplyJumpForce);
                }
            }

And there isn't really a workaround, other than changing the AbilityStarted() method too.
Otherwise the wrong event will be sent (should be "OnJumpAbilityRepeatedJump") and the wrong settings applied (repeated jump could have a higher force for example)
 
Right - in this case I want it to go down the else path. This will allow it to use the initial jump force instead of the repeated jump force. I guess it's a question of is the after falling off of the ledge a repeated jump or an initial jump? It is the first jump so it should be an initial jump, but you may want to use some of the repeated jump properties. I guess repeated jump could be named something like AirborneJumpor something to be more accurate. I'll change the name and also add the changes that you mentioned.
 
Top