5

I'm using libgdx and box2d as my physics engine. Right now I just have a very simple box being controlled on a single flat surface:

enter image description here

Everything seems to be working well. I control the box with the arrow keys. If I press the right arrow the box will accelerate to the right. When I press the up arrow, the box will jump. Something that was unexpected though was that when the box jumps, it's x velocity slows down. Can anyone tell me why that is and how to fix it?

Player Object with just some Box2d setup:

public class Player extends Entity {
  private static BodyDef createBodyDef() {
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyDef.BodyType.DynamicBody;
    bodyDef.fixedRotation = true;
    bodyDef.position.set(100, 200);
    return bodyDef;
  }

  public Player(World world) {
    super(world, createBodyDef(), Textures.rectangle(Units.m2P(0.7f), Units.m2P(2f), Color.RED));
    FixtureDef fixtureDef = new FixtureDef();
    PolygonShape shape = new PolygonShape();
    shape.setAsBox(50, 50, new Vector2(50, 50), 0f);
    fixtureDef.shape = shape;
    fixtureDef.friction = 0.1f;
    getBody().createFixture(fixtureDef);
    MassData massData = new MassData();
    massData.mass = 90f;
    getBody().setMassData(massData);
  }
}

The Game Screen:

public class GameScreen extends BaseScreen implements InputProcessor {
  private final World world = new World(new Vector2(0, -200), false);
  private final GameView view = new GameView();
  private final List<Entity> entities = new ArrayList<Entity>();
  private final Player player = new Player(world);
  private final List<Integer> pressedKeys = new ArrayList<Integer>();

  public GameScreen() {
    entities.add(player);
    view.setFollowEntity(player);
    MapBodyBuilder.buildShapes(view.getTiledMap(), 1, world);
  }

  @Override public void show() {
    super.show();
    Gdx.input.setInputProcessor(this);
  }

  @Override public void render(float delta) {
    super.render(delta);

    float forceX = 0f;
    float forceY = 0f;
    float force = 15000;
    if (pressedKeys.contains(Input.Keys.LEFT)) {
      forceX -= force;
    }
    if (pressedKeys.contains(Input.Keys.RIGHT)) {
      forceX += force;
    }
    if (pressedKeys.contains(Input.Keys.DOWN)) {
      forceY -= force;
    }

    player.getBody().applyForceToCenter(forceX, forceY, false);

    world.step(delta, 5, 5);
    view.render(entities);
  }

  @Override public void resize(int width, int height) {
    super.resize(width, height);
  }

  @Override public void hide() {
    super.hide();
    Gdx.input.setInputProcessor(null);
  }

  @Override public void dispose() {
    super.dispose();
    world.dispose();
    for (Entity entity : entities) {
      entity.dispose();
    }
  }

  @Override public boolean keyDown(int keycode) {
    if (keycode == Input.Keys.UP) {
      Body body = player.getBody();
      body.applyLinearImpulse(new Vector2(0, 30000), body.getWorldCenter(), true);
    }

    pressedKeys.add(keycode);
    return false;
  }

  @Override public boolean keyUp(int keycode) {
    pressedKeys.remove((Integer) keycode);
    return false;
  }

  @Override public boolean keyTyped(char character) {
    return false;
  }

  @Override public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    return false;
  }

  @Override public boolean touchUp(int screenX, int screenY, int pointer, int button) {
    return false;
  }

  @Override public boolean touchDragged(int screenX, int screenY, int pointer) {
    return false;
  }

  @Override public boolean mouseMoved(int screenX, int screenY) {
    return false;
  }

  @Override public boolean scrolled(int amount) {
    return false;
  }

  public Player getPlayer() {
    return player;
  }
}
spierce7
  • 14,797
  • 13
  • 65
  • 106

1 Answers1

0

see how your moving mechanism works:

  1. Calculate forceX and forceY (due to what keys are pressed)
  2. Apply forceX and forceY

of course you cannot use it to jump to avoid "flying" so you are using applyLinearImpulse() to add force once (just push it to the top) but the tricky part is that you are cancelling forceX you added in 2. - remember that in Box2D all forces executes on the world.step(...) execution after all calculations

Instead of

    if (keycode == Input.Keys.UP) 
    {
        Body body = player.getBody();
        body.applyLinearImpulse(new Vector2(0, 30000), body.getWorldCenter(), true);
    }

do something like

    if (keycode == Input.Keys.UP) 
    {
        jumpForce = 30000; //jumpForce is variable of GameScreen class
    }

and then in the render method

    ...

    if (pressedKeys.contains(Input.Keys.DOWN)) 
    {
        forceY -= force;
    }

    forceY += jumpForce; //here you add the jump force

    player.getBody().applyForceToCenter(forceX, forceY, false);

    jumpForce = 0; //but only once - in next iteration od render it will be avoided till UP key will be pressed again

Of course you can think about your own mechanism but this is the right direction

m.antkowicz
  • 13,268
  • 18
  • 37