Triple Jump and Double Midair Dodge (plus more)

Hi!

I finished the course a little bit ago and wanted to expand on what it taught me to build. I posted in the video below what I just finished implementing: they’re the bare essentials of a jump and midair dodge dash and everything else I have so far. I’ve also put in a forward roll for the FreeLookDodge, and the normal dodge rolls for TargetingDodge.

I have several questions and how I can improve my player’s mobility in the air. This is my laundry list of acrobatic features I’d like to put in my game.

How can I set the number of times my player can jump once they’re off the ground? I’d like to count from the moment their feet leave the ground, so if they walk off a ledge they can still jump 3 times.

How could I set a limit for how many times my player can dodge in midair?

How can I reduce the momentum coming from my midair dodges?

How can I make it so my FreeLook dodge can only do its forward roll, and have it always move the player forward?

How can I control my airborne mobility more? When I jump right now, I feel like I’m floating on the moon and have little control in the air.

I’m trying to make an RPG platformer, so having precise and fluid control in the air is crucial to me. I feel like I’ve made some good progress so far (I posted what I have so far on Reddit). My biggest inspiration for the game is Blue Fire, and my goal is to make something similar, but weightier.

You could save the number of times the character has jumped in midair in the PlayerStateMachine, and reset it when the character is grounded.

momentum *= dodgeReduction; //Make dodgeReduction between 0 and 1

Forward is the equivalent of the InputReader.Movement being (0,1), or a Vector3 of (0,0,1).

There is a recent topic on this very thing…

Thank you for taking the time to address my questions, I acknowledge it was a lot.

On how to reduce the momentum from my dodges, I put

public override void Enter()
    {
        momentum = stateMachine.Controller.velocity * dodgeReduction;
        momentum.y = 0;
        stateMachine.Animator.CrossFadeInFixedTime(FallHash, CrossFadeDuration);

in my PlayerFallingState, since both my TargetingAirDodge and AirDodge use the same movement code from their ground counterparts. (I’ll likely change this, it seemed easier at the time to copy/paste the same code for similar movement)

This is giving me the desired effect for air dodging, however it’s affecting normal jumps too because the FallingState starts out with momentum not built up from the jump.

What could I write to make it so the FallingState knows its entering from an AirDodgeState, so I can adjust its starting momentum accordingly?

(note, before I put in dodgeReduction, when I would dodge in the air, the momentum from the dodge continued into the fall, rocketing me in that same direction. Hope this added context helps).

You could create an alternate constructor that sets a flag to reduce the momentum. You can actually have as many constructors as you need, provided each has a different signature (and of course, they all must call the base constructor).

Hi!

Here after fixing the original issue where my player couldn’t control themselves in midair. Now that that’s fixed, it seems the momentum issues with the Midair Dodge rocketing forward has also been solved.

Now it seems the main issue is gravity, and how to reset it.

My intention is to have every midair jump reach the same height no matter how fast they’re falling, and to have the midair dodges go straight, and not sink down until after the dodge is done.

To fix what’s in the video, I tried putting something like Physics.gravity *= gravityReduction; and set that to 0 in my AirDodging Tick, but that only made the player float up when I jumped after the first midair dodge (which also didn’t dodge in a straight line.) If I set it to 1 the player behaves as before.

At a certain point, your jumps are going to be so matrix like that you have to insert particle effects to show the badly hidden wires… :stuck_out_tongue:

I have a number of ideas, but making them work smootly… that’s another issue…

I have no idea how you’re going to enforce the same height… because there is too much ambiguity in that statement… but it looks like you’re wanting any dodge states not to be affected by Gravity until they are finished…

You could set a bool for this in ForceReceiver…

private bool applyGravity = true;

pubilc void ApplyGravity(bool state)
{
    applyGravity = state;
}

When entering a dodge state, you could then tell the ForceReceiver ApplyGravity(false);, and when exiting, tell it ApplyGravity(true);

Then have ForceReciever only modify and include the y when applyGravity is true.

I have no idea how you’re going to enforce the same height… because there is too much ambiguity in that statement…

Here’s a video better explaining my jumping height dilemma. If I jump from the ground, I can effortlessly cross the first bar. However, if I jump while I’m falling, I jump less high. It seems the faster I’m falling, the lower I jump. (note, I also only have a call to the Jumping State from my Falling States, and not within the Jumping State itself.)

AH, you mean that you want each jump to have the same effect, as if you were standing still when you made the second jump…

The problem lies in your ForceReciever’s Jump method…

public void Jump(float jumpForce)
{
    verticalVelocity += jumpForce;
}

When you make that second jump, verticalVelocity is already going negative because… well… gravity… When you’re grounded, jumpforce is capped at Physics.gravity.y * Time.deltaTime;, but when you’re already falling, jumpforce is much much lower than that because… gravity adds up…

There are a couple of options here… the easiest would be to simply set verticalVelocity to jumpforce instead of adding it to verticalVelocity… Of course, this would mean that if you double jumped while still moving in the positive direction, it still wouldn’t be double in height… so… perhaps:

    public void Jump(float jumpForce)
    {
        if(verticalVelocity<0) 
        {
             verticalVelocity = jumpforce;
        } else
        {
             verticalVelocity += jumpForce;
        }
    }
1 Like

Woohoo! That takes care of the jumping consistency. Who knew just a few lines could make such a difference? (hint: everyone)

Now onto solving the midair dodges. I put the bool in the ForceReceiver and then put stateMachine.ForceReceiver.ApplyGravity(false); in my AirDodging Enter, and stateMachine.ForceReceiver.ApplyGravity(true); in my Exit. So far no changes. Time for the last step.

I’m looking at the ForceReceiver and trying to figure out how to tell it to

only modify and include the y when applyGravity is true.

I’ve tried putting this in my private void Update() in ForceReceiver

but Unity didn’t like that.

10 points to RavenClaw

20 points FROM RavenClaw…

if(applyGravity)
{
   if (verticalVelocity < 0f && controller.isGrounded)
       {
           verticalVelocity = Physics.gravity.y * Time.deltaTime;
       }
       else
       {
           verticalVelocity += Physics.gravity.y * Time.deltaTime;
       }
}
1 Like

After fiddling around with this script and ADDING it onto the private void Update() I had some issues. Then I had a brain blast moment and thought “What if I simply added the if(applyGravity) on top of the existing one?” and poof, the issue got better.

Then I found another issue. It seems this solution works too well, as the character will dodge in the direction they’re going, diagonality taken into account. This video shows what I’m talking about.

So charging… :stuck_out_tongue:
What are you applying to Momentum? stateMachine.transform.forward? Momentum? perhaps statemachine.transform.right * the x component of the input?

For AirDodges, I’m using roughly the same methods as the ground dodges.

My tick for TargetingAirDodging

public override void Tick(float deltaTime)
    {
        Vector3 movement = new Vector3();

        movement += stateMachine.transform.right * dodgingDirectionInput.x * stateMachine.DodgeLength / stateMachine.DodgeDuration;
        movement += stateMachine.transform.forward * dodgingDirectionInput.y * stateMachine.DodgeLength / stateMachine.DodgeDuration;

        Move(movement, deltaTime);

        remainingDodgeTime -= deltaTime;

        if(remainingDodgeTime <= 0f)
        {
            stateMachine.SwitchState(new PlayerTargetingFallingState(stateMachine));
        }

and the one for AirDodging

public override void Tick(float deltaTime)
    {
        Vector3 movement = new Vector3();
        
        movement += stateMachine.transform.forward * stateMachine.DodgeLength / stateMachine.DodgeDuration;

        Move(movement, deltaTime);

        remainingDodgeTime -= deltaTime;

        if(remainingDodgeTime <= 0f)
        {
            stateMachine.SwitchState(new PlayerFallingState(stateMachine));
        }
    }

So it’s doing exactly what you told it to… to charge…
You need to start your AirDodge with the direction you want to charge (in this case I think a positive or negative number, like dodgingDirectionInput.x?
Then apply that number to stateMachine.transform.right…

I got rid of the original dodgingDirectionInput.y in my Freelook Dodging and AirDodging States because it was making the freelook dodge not work if the player was facing the camera or to the side.

I kept the dodgingDirectionInput.x and dodgingDirectionInput.y on the AirTargetingDodge State, and the same issues occur.

Keep playing with it… just remember input.x * transform.right, and input.y * transform.forward. It looked in this video like there was nothing being applied from the x input * transform.right

Interesting, I thought x in this case only meant left/right and y was forward/backward. X in this case means all horizontal movement I guess?

X means left/right
Y means forward/backward

This depends on your definition of Horizontal…
If you are thinking Horizontal as in looking from the top down, then yes (as horizontal is left/right in this case).
If you mean all the left/right/forward/backward while dodging, then no.

I’ve been playing around with the order of the

movement += stateMachine.transform.right * dodgingDirectionInput.x * stateMachine.DodgeLength / stateMachine.DodgeDuration;
        movement += stateMachine.transform.forward * dodgingDirectionInput.y * stateMachine.DodgeLength / stateMachine.DodgeDuration;

and the other for the freelook Dodge state for a bit, and so far I’ve come up with nothing. Anything I try either repeats the same problems I had before or does nothing (and leaves the charging intact).

You’d think telling Unity “if at this elevation, stay at this elevation until your state is over” would be easier haha.

Update

Charging is growing on me. I’ll still try and figure out how to maintain elevation during midair dodges, but this is looking pretty fun atm.

Since when have bugs been turned into features? (the answer: a lot)

Update 2 Video 2, I made the tower bigger.

Hi! Here with yet another question.

I’ve tried to do this on my own and I think I’m almost there. I added

[field: SerializeField] public int MaxJumps { get; private set; } //3
    [field: SerializeField] public int MaxMidAirDodges { get; private set; } //2

and

public int CurrentJumps = 0;
    public int CurrentMidAirDodges = 0;

to my PlayerStateMachine.

I then made my PlayerFallingState’s Jump call look like this

private void OnJump()
    {
        if (stateMachine.CurrentJumps < stateMachine.MaxJumps)
        {
            stateMachine.SwitchState(new PlayerJumpingState(stateMachine));
        }

        if (stateMachine.CurrentJumps == stateMachine.MaxJumps)
        { return; }
    }

and edited my TargetingFallingState accordingly. I also added similar stuff to my Dodge calls in the JumpingState, TargetingJumpingState, etc.

I guess the parts I’m stuck on now are how to tell the PlayerStateMachine to add 1 to CurrentJumps/CurrentMidAirDodges after each jump/midair dodge, how to tell the game to stop allowing jumping/midair dodging until they’re grounded again, and how to reset the counter when grounded?

What would be the best way to implement these Jumping and MidAirDodging countdown systems?

Privacy & Terms