3
votes

I'm programming a ball game and I want the ball can't jump twice, or jump without having contact with the floor.

I'm using the methods beginContact() and endContact() from ContactListener for detect when the ball is touching the floor. I implemented a state (FLYING or LANDED) and I set the ball state to LANDED in the beginContact() method, and reset it to FLYING in the endContact() method. I check this state before apply the jump force.

The problem is that the jump() method is called in the main render loop and box2D sometimes spends two loop iterations before call endContact() method. So the jump() method is called twice before that box2D simulates that the contact with the floor has ended.

Part of the code of ContactListener (This isn't the ContactListener of libGDX, but the methods beginContact() and endContact() call these methods directly, passing the object which it was collide):

@Override
public void beginContact(Contact contact, Object objetB) {
    if(objetB instanceof Floor){
        System.out.println("Begin");
        ball.floorBeginContact(contact);
    }
}

@Override
public void endContact(Contact contact, Object objetB) {
    if(objetB instanceof Floor){
        System.out.println("End");
        ball.floorEndContact(contact);
    }       
}

Part of the code of the ball Actor:

public void floorBeginContact(Contact contact){
    state = State.LANDED;
}

public void floorEndContact(Contact contact){
    state = State.FLYING;
}

private void jump(){
    if(state == State.LANDED){
        body.applyForceToCenter(0f, 30f);
        System.out.println(i++ + " - Jump!");
    }
}

public void act(float delta){
    ...

    if(Gdx.input.isKeyPressed(Keys.SPACE)){
        jump();
    }
}

And the console output is some like this:

Begin
0 - Jump!
1 - Jump!
End
Begin
2 - Jump!
End

I don't know why this happens and neither if this is the best way to do it.

1
How about having a timeout of say, 0.2 seconds or something, before allowing another jump.iforce2d
Solution from ifroce2d: iforce2d.net/b2dtut/jumpabilityPavel

1 Answers

2
votes
public void floorBeginContact(Contact contact){
state = State.LANDED;
 canApplyForce = true;
}

public void floorEndContact(Contact contact){
state = State.FLYING;
}

boolean canApplyForce = true;

private void jump(){
if(state == State.LANDED){
    if(canApplyForce)
    body.applyForceToCenter(0f, 30f);
   canApplyForce = false;
    System.out.println(i++ + " - Jump!");
}
}

public void act(float delta){
...

if(Gdx.input.isKeyPressed(Keys.SPACE)){
    jump();
 }
   }

I think this should solve your problem.