4
\$\begingroup\$

I'm using libgdx and its physic engine Box2d. My question is : how could I make my box2d body go through a block , ignore the first collison than make the block active so the ball can fall onto it. A good example is doodle jump.

enter image description here

\$\endgroup\$
2
\$\begingroup\$

Set a flag whenever collisions are detected.

Something like this:

method Ball.onCollisionWith(block) {
    if (block == self.dontCollide) {
        self.dontCollide = block
        -- Do nothing else, passing through collision
    } else {
        -- Reset flag so next collision will pass again
        self.dontCollide = nil
        resolveCollision(self, block)
    }
}

The Ball will then ignore every second collision due to its dontCollide flag being set.

\$\endgroup\$
  • \$\begingroup\$ If I'm not wrong this is C or C++, programming languages that I don't know and I don't have any chance to translate it into java/libgdx code :( could you please translate it ? \$\endgroup\$ – Ion Farima Mar 12 '13 at 14:19
  • 1
    \$\begingroup\$ It was only really pseudocode to begin with -- really just meant to illustrate a solution. I've converted it to look more like C though. Programming is a prerequisite for game programming. You should read an an introductory programming book. \$\endgroup\$ – Anko Mar 12 '13 at 17:30
1
\$\begingroup\$

I've had a similar problem in the past, have a look at this Tutorial. I found it answered my question. Its not for java but the code was very easy to copy over

\$\endgroup\$
1
\$\begingroup\$

I finally made it :)

Here's my code :

public void preSolve(Contact contact, Manifold oldManifold) {
        fixtureA = contact.getFixtureA();
        fixtureB = contact.getFixtureB();
          if(fixtureA.getBody().getUserData() == "platform" && fixtureB.getBody().getUserData() == "ball"|| fixtureA.getBody().getUserData() == "ball" && fixtureB.getBody().getUserData() == "platform"){
              if (fixtureA.getBody().getUserData() == "platform") { 
                  platform_y = fixtureA.getBody().getPosition().y;
                  ball_y = fixtureB.getBody().getPosition().y;
              } else if(fixtureA.getBody().getUserData() == "ball") {
                  ball_y = fixtureA.getBody().getPosition().y;
                  platform_y = fixtureB.getBody().getPosition().y;
              }
                 if(ball_y < platform_y + 1.5F) {             //the ball is below
                     contact.setEnabled(false);
                 }
          }

    }
\$\endgroup\$
  • \$\begingroup\$ I've added my solution below, based on yours but using Category bits to define the objects which can collide etc. Hope it helps \$\endgroup\$ – James Stoddern Aug 20 '16 at 7:55
0
\$\begingroup\$

I used your solution but instead of using getUserData I set up category bits on my platforms and player. The ground has different category bits to platforms so that only the platforms can be passed through. You can define category bits in your main game class as follows:

public static final short GROUND_BIT = 1;
public static final short PLATFORM_BIT = 2;
public static final short PLAYER_BIT = 4;

Next, in your Presolve we only want to pass through platforms, so we add this code to check if Fixture A and B are either the Player or Platforms:

@Override
public void preSolve(Contact contact, Manifold oldManifold) {

    //THIS SHOULD ALLOW PLAYER TO PASS THROUGH PLATFORMS AND COLLIDE ON THE WAY DOWN
    Fixture fixtureA = contact.getFixtureA();
    Fixture fixtureB = contact.getFixtureB();

    float platform_y;
    float player_y;

    platform_y = fixtureA.getBody().getPosition().y;
    player_y = fixtureB.getBody().getPosition().y;

    if(fixtureA.getFilterData().categoryBits == Engine.PLAYER_BIT
            && fixtureB.getFilterData().categoryBits == Engine.PLATFORM_BIT ||
            fixtureA.getFilterData().categoryBits == Engine.PLATFORM_BIT
                    && fixtureB.getFilterData().categoryBits == Engine.PLAYER_BIT ) {

        //Gdx.app.log("Player Y ", "" + player_y);

        if (fixtureA.getBody().getUserData() == "platform") {
            platform_y = fixtureA.getBody().getPosition().y;
            player_y = fixtureB.getBody().getPosition().y;
        } else if(fixtureA.getBody().getUserData() == "player") {
            player_y = fixtureA.getBody().getPosition().y;
            platform_y = fixtureB.getBody().getPosition().y;
        }

        if(player_y < platform_y + 0.22f) {  //the player is below platform
            contact.setEnabled(false);
        } else {
            contact.setEnabled(true);
        }
    }
}

When I build my level the Platforms use this loop to build them from a Tiled map, and set the Category bits to the fixtures:

//////////////////////////////////////////////////////////////////////////
    //Platform Layers - with category bit PLATFORM_BIT
    for(MapObject object : map.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)) {
        Rectangle rect = ((RectangleMapObject) object).getRectangle();
        bdef.type = BodyDef.BodyType.StaticBody;
        bdef.position.set((rect.getX() + rect.getWidth() / 2)  / Engine.PPM, (rect.getY() + rect.getHeight() / 2) / Engine.PPM);

        body = world.createBody(bdef);
        shape.setAsBox(rect.getWidth()/2 / Engine.PPM, rect.getHeight()/2 / Engine.PPM);
        fdef.shape = shape;

        //Set the category Bits to Platform
        fdef.filter.categoryBits = Engine.PLATFORM_BIT;
        body.createFixture(fdef);
    }

My Player also has category bits set and the maskBits define what he can collide with:

fdef.filter.categoryBits = Engine.PLAYER_BIT;
    fdef.filter.maskBits = Engine.GROUND_BIT | Engine.PLATFORM_BIT;

This should be all you need to get it working.

The only issue is trying to work out what the value here should be:

if(player_y < platform_y + 0.22f) {             //the player below

The 0.22f in my case makes sure tht the player gets a certain height above the platform before checking. If you set this too high or too low, the player may not land on the platform at all. I have not worked out what the .22f is in relation to my world coordinates or sprite size yet, but will update if I can replace this with a value derived from the Player's height for example.

Hope this helps a little.

GIT

https://github.com/stoddsie/8-Bit-Platform-Engine

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.