Skip to main content
GameDev.net gamedev.net
🔒 Locked

Hold up to jump

Started by P0jahn Mar 2, 2013 at 6:45 PM 7 replies 2k views
Original Post
P0jahn
P0jahn

So in my 2D game, you can just hold up and the character will jump as soon as he hit the ground.

It looks like the character is bouncing :/

What i want to achieve is to make it behave like any other 2D game, if you hold up and land, you wont jump again until you repress the jump button.

This is a simple thing I want to achieve, but hard as hell to implement, as I my game have wall jumping and short-jumps.

Here is the code, I will hide unnecessary code to avoid confusion:


        boolean upInput    = in.isKeyDown(KEY_UP); //If the jump button is pressed

        if(cant move down && vy <= 0)
            reset();
        else
        {
            vy *= 1.0 - (damping * DELTA);
            float force = mass * gravity;
            vy += (force / mass) * DELTA;
        }
        if(jumpAllowed && upInput)
        {
            if(++counter > maxY)
            {
                jumpAllowed = false;
                counter = 0;
            }
            else
                vy = upSpeed;
        }
        else
            jumpAllowed = false;
        
        boolean falling = vy < 0; 
        float nextY = currY - vy * DELTA;

        if(vy != 0)
        {
            /**
             * Do not change these codes!
             * It allow us to jump up, fall down and run down from slopes!!!
             */
            if(!falling)
            {
                if(canGoToUp(nextY))
                    moveTo(currX, nextY);
                else
                    vy = 0;    //If we jump into an ceiling, we start falling down.
            }
            else if(falling && canGoToDown(nextY))
                moveTo(currX, nextY);
            else
            {
                tryDown(10);
                jumpAllowed = true;
            }
        }

    protected void reset()
    {
        jumpAllowed = true;
        vy = counter = 0;
    }

The jumping occur in if(jumpAllowed && upInput).

Ludus
Ludus

Quite simply, you need to implement a kind of "reset" that occurs when the up key is released. The ability to jump is disabled after the player initially jumps by pressing up and is re-enabled by releasing up.

Edit: I just realised a problem with this solution. The "bouncing" effect will still occur if you let go of up in midair and then hold it down before touching the ground. What you need to do is re-enable jumping only when the player isn't holding up AND is touching the ground (in your case, touching the ground is indicated by "jumpAllowed" being true). It seems the most elegant way to implement this would be to change the line near the bottom of your code in the first section to " if (!upInput) jumpAllowed = true; " No other changes are required.

stitchs_login
stitchs_login

Correct me if I am wrong, but setting the upInput variable to that of the isKeyDown function on every loop going to cause the problem here; that a jump is able to successfully occur without needing to check for it again. This is because a key release is never checked for.

Something along the lines of checking for a change in key state, from the last loop to the next, should solve the issue? That way, you only ever need to execute the jump code when you are able to (touching the ground), and multiple presses during a jump won't cause another jump. And a check for change could bypass the jump execution, if the change is false.

Please ask if this needs more clarification as it might be a tad on the 'waffle' side.

Regards,

Stitchs.

Khatharr
Khatharr

 else {
   tryDown(10);
   jumpAllowed |= !upInput;
 }

Edit - Actually, let me look at this for a minute. I'm not sure yet what you're doing here.

Edit - Okay. This is a good start, but there's a couple things to consider:

The best pattern here is to determine what your character is doing and then apply it. By that I mean, determine whether he's on the ground, then whether he's jumping. Apply forces after that, then check for issues (collisions), then correct them.

You apply gravitation as a force, but you apply jumping as a speed. You won't get a natural jump curve from that. Why not apply both of them as forces?

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
blueshogun96
blueshogun96

The simplest way around this is to use what's called a "timestamp" feature. When I was a newbie, I had problems with this too, but the timestamp feature saved me from lots of trouble in the future. Here's an example of what I'm talking about (using C-style code for clarity).


/* Key press information structure */
struct key_t
{
    bool is_down;
    int time_stamp;
};

/* Keyboard array */
struct key_t keys[256];

void on_key_down( unsigned char key )
{
    /* Mark this key as pressed */
    keys[key].is_down = true;
}

void on_key_up( unsigned char key )
{
    /* Mark this key as released */
    keys[key].is_down = false;

    /* Reset the timestamp counter */
    keys[key].time_stamp = 0;
}

void check_keys()
{
    unsigned char i = 0;

    /* Go through the entire keyboard and check for key presses */
    while( i < 256 )
    {
        unsigned char key_down = GetAsyncKeyState( i );
    
        if( key_down )
            on_key_down(i);
        else
            on_key_up(i);

        i++;
    }
}

void update_keys()
{
    int i = 0;

    /* Go though each key and update the timestamp counter for keys that are being pressed */
    while( i < 256 )
    {
        if( keys[i].is_down )
            keys[i].time_stamp++;

        i++;
    }
}

void game_input()
{
    /* Check for user input, but don't do anything unless this is the first frame that the enter button (or whatever button you use) is pressed down! */
    if( keys[VK_ENTER].is_down && keys[VK_ENTER].time_stamp == 0 )
    {
        /* Make user jump! */
    }
}

void game_update()
{
    /* Check key presses before processing input */
    check_keys();

    /* Do game logic here ... */

    /* Call after input has been handled for this frame */
    update_keys();
}

This is a really basic frame based keyboard timestamp implementation where each and every key has it's own timestamp so you know how long it's been down. When the key is released, the timestamp is reset to 0. Every frame the button is being held down, the timestamp counter increases so you know it's been pressed down for longer than one frame! This is also easy enough to expand on if this is too simple for you. I recommend you don't create one timestamp variable for the entire keyboard, I tried that and it made my game's controls sometimes unresponsive because I was accounting for a timestamp initiated by another button.

A more advanced implementation could use actual time based timestamps (which is an easy thing to add; just record the start time with GetTickCount() assuming you're using windows and get the difference from the current time to get your delta time, then add it to the key_t::time_stamp variable), but I didn't want to risk overcomplicating the example.

Hopefully this helps ^^

Shogun

EDIT: Forgot a few things, sorry >.<

Khatharr
Khatharr

Q: What is 2 + 2?

A: The capital of Texas is Austin.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.
P0jahn
P0jahn


Edit: I just realised a problem with this solution. The "bouncing" effect will still occur if you let go of up in midair and then hold it down before touching the ground. What you need to do is re-enable jumping only when the player isn't holding up AND is touching the ground (in your case, touching the ground is indicated by "jumpAllowed" being true).

Thanks all. This made me solve it :)

P0jahn
P0jahn


?You apply gravitation as a force, but you apply jumping as a speed. You won't get a natural jump curve from that. Why not apply both of them as forces?

How do I do that?

Btw, I do get the curve with my current way.

I have asked a couple of people, and they told me that they love the controller and it feels like of an mix between Super Meat Boy and N+.

Khatharr
Khatharr
Now that I'm thinking about it you may be better off without it. The method I used back when I was messing with platformers was to have a 'pool' of force when the character was on the ground. A majority portion of the force would be removed from the pool and applied for every frame that the button was held until the pool was empty.

On reflection, if your constant speed override is balanced against gravity to where it's giving you good behavior then I'd stick with that, as it's certainly more elegant. Reading through it again I can see how it would work out alright.

It's been quite a while since I messed with platformers. I think I tried to drag too much real-world physics into an unreal-world situation and never went back to revisit it. My bad.

Glad you sorted out the bounce.
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.