简体   繁体   中英

Box2d libgdx, a bit confused about the pixels to meters stuff

So I understand the concept. The idea is that box2d more or less works in meters, so you need to do a conversion from pixels to it. Makes sense. I was following the tutorial/intro to box2d here . It mentions to do the conversion and gives you some example amounts to use. Now, that's all well and good, but I find when I'm using such techniques, the debugger box doesn't seem to render where they should. The collision does work as expected however.

In my GameScreen class, here's how I initialize the ground:

ground = new BodyDef();
// set the position half way up the ground
ground.position.set(0,16 * GameScreen.WORLD_TO_BOX);
groundBody = world.createBody(ground);
groundShape = new PolygonShape();
// make the height 16px so it doubles to 32
groundShape.setAsBox(Gdx.graphics.getWidth() * GameScreen.WORLD_TO_BOX, 16.0f * GameScreen.WORLD_TO_BOX);
groundBody.createFixture(groundShape, 0.0f);

My render method in that screen is like so:

public void render(float delta) {
    Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
    camera.update();
    stateTime += Gdx.graphics.getDeltaTime();

    batch.begin();
    batch.draw(background, 0, Gdx.graphics.getHeight() - 512, 512, 512);
    batch.draw(trailingBackground, 512, Gdx.graphics.getHeight() - 512);
    int heightToCover = Gdx.graphics.getHeight() - 512;
    int widthToCover = Gdx.graphics.getWidth();
    for(int w = 0; w < widthToCover; w += 32) {
        for(int h = 0; h < heightToCover; h += 32) {
            batch.draw(lightBackgroundTile, w, h, 32, 32);
        }
    }
    player.update();
    player.render(stateTime, batch);
    batch.end();
    levels.get(currentLevel).render(camera);

    // physics updates
    world.step(1/60f, 6, 2);
    debugRenderer.render(world, camera.combined);
}

Here's the constructor of the player class, so you can see how im setting up its collision box2d objects. I also pasted the update method which is called in the above render loop to adjust the sprites position.

public Player(int x, int y, World world) {
    super();
    playerTexture = new Texture(Gdx.files.internal("assets/hero.png"));
    init(x, y, 128, 128, playerTexture, false, world);

    bodyDef = new BodyDef();
    bodyDef.type = BodyType.DynamicBody;
    bodyDef.position.set(x * GameScreen.WORLD_TO_BOX, y * GameScreen.WORLD_TO_BOX);
    body = getWorld().createBody(bodyDef);
    collisionBox = new PolygonShape();
    collisionBox.setAsBox(32 * GameScreen.WORLD_TO_BOX, 64 * GameScreen.WORLD_TO_BOX, new Vector2(64 * GameScreen.WORLD_TO_BOX, 64 * GameScreen.WORLD_TO_BOX), 0.0f);

    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = collisionBox;
    fixtureDef.density = 10f; 
    fixtureDef.friction = 0.4f;
    fixtureDef.restitution = 0f;

    body.createFixture(fixtureDef);
    collisionBox.dispose();

    addFrame(0, 0, 128, 128);
}

public void update() {
    this.setX((int) ((body.getPosition().x) * GameScreen.BOX_TO_WORLD));
    this.setY((int) ((body.getPosition().y) * GameScreen.BOX_TO_WORLD));
}

Now, when I remove the multiplication of those static floats in the various calculations, sizes, etc, the collision remains correct and the debugger box shows up. However passing the raw pixels to box2d feels wrong. Is there something I'm missing here as to why the debugging boxes don't show up as is?

I do like you are doing but might be a little different.

Might be a little overkill but here's my jucl port

jucl/Android - pastebin

Then I just have utility classes ie:

public class Pixel {

    public static float toMeter(float pixels) {
        return (float)LengthConversions.Pixel2SIf(pixels);
    }

    public static Vector2 toMeter(Vector2 vecPixel) {
        return new Vector2(Pixel.toMeter(vecPixel.x), Pixel.toMeter(vecPixel.y));
    }
}

public class Meter {

    public static final float METERS_PER_PIXEL = (float) LengthConversions.SI_PIXEL;

    public static float toPixel(float meter) {
        return (float)LengthConversions.SI2Pixelf(meter);
    }
}

In my initialize:

int graphicsWidth = Gdx.graphics.getWidth();
int graphicsHeight = Gdx.graphics.getHeight();

CAMERA_WIDTH_METERS = Pixel.toMeter(graphicsWidth);
CAMERA_HEIGHT_METERS = Pixel.toMeter(graphicsHeight);

Then in my game classes (like your Player class). In my case it was a pinball game so i have Flipper, Ball, Bumper, etc. I have a @Override render() method where I sync up the sprite with the physics body.

Here's an example file..sry it's messy but might be helpful.

Pinball Engine Class file

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM