Search code examples
javalibgdxbox2d

Java LibGDX cannot move with physics bodies and gravity enabled


I could really use some help I'm stuck on this. I'm trying to make a block in a simple game be the ground and another block fall onto it and then possibly bounce a little but be able to move the box left or right to fall off of that first block. Can anyone help me with this please?

For anyone interested in the answer thanks to PoprostuRonin and dermetfan's YouTube videos I was able to get the results I was looking for, you can try the below code in your project and just change the sprite textures.

private Box2DDebugRenderer debugRenderer;
private OrthographicCamera camera;
private float spriteSpeed = 500000;
private World world;
private Sprite playersprite;
private Sprite groundsprite;
private Body playerBody;
private Body groundbody;
private Vector2 movement = new Vector2();
private Array<Body> tmpBodies = new Array<Body>();

public TestState(GameStateManager gsm) {
    super(gsm);

    Gdx.input.setInputProcessor(this);

    batch = new SpriteBatch();

    debugRenderer = new Box2DDebugRenderer();
    camera = new OrthographicCamera();

    // Sprites
    playersprite = new Sprite(new Texture("badlogic.jpg"));
    groundsprite = new Sprite(new Texture("ground-tiles-01.gif"));

    // World
    world = new World(new Vector2(0, -9.8f), true);

    // Player Sprite
    // Body definition
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyType.DynamicBody;
    bodyDef.position.set(0, 200); //1m

    PolygonShape shape = new PolygonShape();
    shape.setAsBox(10, 10);

    // Fixture definition
    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = shape;
    fixtureDef.density = 2.5f; //2.5kg
    fixtureDef.friction = 0; //0-1
    fixtureDef.restitution = .75f; //0-1

    playerBody = world.createBody(bodyDef); 
    playerBody.createFixture(fixtureDef);
    playerBody.setUserData(playersprite);
    playersprite.setSize(20, 20);
    playersprite.setOrigin(playersprite.getWidth() / 2, playersprite.getHeight() / 2);
    shape.dispose();

    // Ground Sprite
    // Body definition
    BodyDef groundbodyDef = new BodyDef();
    groundbodyDef.type = BodyType.StaticBody;
    groundbodyDef.position.set(0, 0); //1m

    PolygonShape groundshape = new PolygonShape();
    groundshape.setAsBox(groundsprite.getHeight() / 2, groundsprite.getWidth() / 2);

    // Fixture definition
    FixtureDef groundfixtureDef = new FixtureDef();
    groundfixtureDef.shape = groundshape;
    groundfixtureDef.density = 100; //2.5kg
    groundfixtureDef.friction = .25f; //0-1
    groundfixtureDef.restitution = 0; //0-1

    groundbody = world.createBody(groundbodyDef); 
    groundbody.createFixture(groundfixtureDef);
    groundbody.setUserData(groundsprite);
    groundsprite.setSize(groundsprite.getHeight(), groundsprite.getWidth());
    groundsprite.setOrigin(groundsprite.getWidth() / 2, groundsprite.getHeight() / 2);

    groundshape.dispose();
}

@Override
public void update(float delta) {
    camera.viewportWidth = Gdx.graphics.getWidth();
    camera.viewportHeight = Gdx.graphics.getHeight();
}

@Override
public void render() {
    Gdx.gl.glClearColor(50 / 255f, 213 / 255f, 237 / 255f, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    debugRenderer.render(world, camera.combined);
    batch.setProjectionMatrix(camera.combined);
    world.step(Gdx.graphics.getDeltaTime(), 6, 2);

    playerBody.applyForceToCenter(movement, true);

    batch.begin();
    world.getBodies(tmpBodies);
    for (Body body : tmpBodies){
        if (body.getUserData() != null && body.getUserData() instanceof Sprite) {
            Sprite sprite = (Sprite) body.getUserData();
            sprite.setPosition(body.getPosition().x - sprite.getWidth() / 2, body.getPosition().y - sprite.getHeight() / 2);
            sprite.setRotation(body.getAngle() * MathUtils.radiansToDegrees);
            sprite.draw(batch);
        }
    }
    batch.end();

    camera.position.set(playerBody.getPosition().x, playerBody.getPosition().y, 0);
    camera.update();

}

@Override
public void dispose() {
    world.dispose();
    playersprite.getTexture().dispose();
    groundsprite.getTexture().dispose();
}

@Override
public boolean keyDown(int keycode) {
    switch (keycode) {
    case Keys.DPAD_LEFT:
        movement.x = -spriteSpeed;
        break;
    case Keys.DPAD_RIGHT:
        movement.x = spriteSpeed;
        break;
    case Keys.DPAD_UP:
        movement.y = spriteSpeed;
        break;
    case Keys.DPAD_DOWN:
        movement.y = -spriteSpeed;
    }
    return true;
}

@Override
public boolean keyUp(int keycode) {
    switch (keycode) {
    case Keys.DPAD_LEFT:
    case Keys.DPAD_RIGHT:
        movement.x = 0;
        break;
    case Keys.DPAD_UP:
    case Keys.DPAD_DOWN:
        movement.y = 0;
    }
    return true;
}

Solution

  • You code is valid, the problem are numbers.

    Mass of your body is big, 20480kg. Gravity is inverted because you ask for it:

    world = new World(new Vector2(0, -1000f), true);
    

    -1000, it is under 0 so it is inverted and big number (1000 on your "planet" and 9.8 on Earth) cause object to by less controllable.

    Changes values:

    float spriteSpeed = 60000;
    ...
    world = new World(new Vector2(0, 9.8F), true);
    ...
    fixtureDef.density = 1;
    fixtureDef2.density = 1;
    

    You will notice that now the body is controllable (it can even fly). Play with these numbers and learn some basic physics rules to have idea what are you doing.

    The sprite and body position are synced, but are not aligned properly. Use this code to make the first step to make aligned texture with body.

    sprite.setCenter(body.getPosition().x, body.getPosition().y);
    groundsprite.setCenter(ground.getPosition().x, ground.getPosition().y);
    

    But what about rotation

    groundsprite.setOriginCenter();
    sprite.setOriginCenter();
    
    groundsprite.setRotation(ground.getAngle() * MathUtils.radDeg);
    sprite.setRotation(body.getAngle() * MathUtils.radDeg);
    

    This is simple as your object is single texture and we can simply align it at center, but as objects become more complicated code need to be changed.