[box2D] how positioning and scaling work

Hello,
i start looking for some Box2D examples today and everything is working fine except that i don’t understand the creation of a simple rectangle inside Box2D (polygon), if am right the steps needed to create a box2D rectangle are the followings


       

		BodyDef polygonDef = new BodyDef();
		polygonDef.position.set(x, y);
		polygonDef.type = BodyType.DynamicBody;

		Body polygonBody = world.createBody(polygonDef);

		PolygonShape polygonShape = new PolygonShape();
		polygonShape.setAsBox(width, height);

		fixture.shape = polygonShape;
		polygonBody.createFixture(fixture);

		

and to create a Rectangle in libGdx we do this :



		shapeRenderer.begin(ShapeType.FilledRectangle);
		shapeRenderer.filledRect(x, y, width, height);
		shapeRenderer.end();

now supposing i create a libGdx rectangle with the following coordinates :
x =100, y=100, width=100, height=100
in order to have a Box2D rectangle in the same position with the same size, i had to use the following coordinates :
x = 30, y=30,width=10,height=10;

i tried to figure out the relation between them but i didn’t succeed, i know that box2D use meters instead of pixels but what i don’t know is 1meter=??pixels, and how i can use Box2D with “simple” coordination

thank you

Use debug renderer with camera that match with box2d coordinates. Meters are simple, pixels are evil. It’s easy to know how long car should be in meters but you cannot say that without context and screen size with pixels.

Everything is logical and easy when you plan game logic with meters and match rendering with physics size and let camera scale that to screen. Zero magic constant, faster and better precision math. No downsides.

Ps. One added bonus is that when you understand benefits of camera with 2d graphics then translation to 3d is lot easier.

box2d use meters? Whats the difference then?

Also, that positions could be a camera issue, right?

If I did not scale anything at all, this works for me:

sprite.setPosition(body.getPosition().x - sprite.getWidth() / 2, body.getPosition().y - sprite.getHeight() / 2);

About scaling, well this is also new for me. First thing to know about this is Box2D uses meter and its calculation are correct if the body dimensions are between 0.1 meters and 10 meters. So, if you don’t do any scaling, your 20x20 sprite will be 20 meters x 20 meters in Box2D.

Like I said, I am still experiencing about this. But people use some constants for this, which are:

static final float WORLD_TO_BOX = 0.01f;
	static final float BOX_TO_WORLD = 100f;

Before I started to think about scaling, I thought these are the standard scaling constants but they are not. I mean, you could set WORLD_TO_BOX to 0.1f or even 2f if that’s the thing that will make your game work.

Here is something I use to experiment. Do not assume these are correct, because I might encounter some problems with the way I do things later;
I have a class which creates bodies. You pass some variables to that class. The method parameters are like this:

boxFactory.charBody(position, halfX, halfY, density, friction, restitution)

position is a Vector2. The rest are float values. My WORLD_TO_BOX and BOX_TO_WORLD values are 0.1f and 10f. So I have a ship, and I have a body for that. This is my body:

shipBody = boxFactory.charBody(new Vector2(40, 30), 3.2f, 3.2f, 0.1f, 1f, 0f);

I probably should have multiplied 32*WORLD_TO_BOX instead of giving 3.2f but like I said, experimenting right now.

I have a 64x64 image as my ship sprite. So I scale it:

sprite.setScale(MyBox.WORLD_TO_BOX);

MyBox is my class which creates bodies and WORLD_TO_BOX is a static constant of that class.

I am not entirely sure about my camera setup, but this is how I did it:

camera = new OrthographicCamera();
	camera.setToOrtho(false, Gdx.graphics.getWidth() * MyBox.WORLD_TO_BOX, Gdx.graphics.getHeight() * MyBox.WORLD_TO_BOX);

I think this is not correct, because when I put this into resize() method, things are mixed up.

To sum up, 1 meter = (whatever you want) pixels.

This is the thread I tried to get help: http://www.java-gaming.org/topics/libgdx-box2d-scaling-between-world-and-box/29743/view.html
Philbedy has a different approach to that. You might try that as well.

EDIT: I think scaling is almost mandatory, because a 32x32 sprite will be 32x32 meters and this will mess up box2d simulation. I wasn’t able to find a good guide (well no guide at all) about how scaling should go. And I think the best way to experiment this is to build a working example without scaling, and then trying to implement scaling to it.
BTW, I just set up a InputProcessor and its touchDown method is like this:

	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
		System.out.println("X:" + screenX + " Y: " + screenY);
		System.out.println(world.getEnemyBody().getPosition());
		return true;
	}

And when I click on the enemy body, the output is like this:

[quote]X:800 Y: 376
[80.0:30.0]
[/quote]
This might help you (and me) understand the scaling thing better.

EDIT : i added “batch.setProjectionMatrix(camera.combined);” and it works

which am currently trying to do, the wiki example of the Orthographic Camera is a kinda hard, i really don’t understand why the guys from badLogic don’t want to keep it simple :-\ (am talking about the “mesh” thing which i have zero idea about)
anyway,
i tried to follow the wiki example, but i didn’t succeed to do the “camera.translate” and “camera.zoom”, however i was able to create the camera effect by changing the viewPort rectangle x,y,width and height, here is the codes,

package com.me.mygdxgame;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;

public class MyGdxGame implements ApplicationListener {
	// input
	private boolean leftPressed, rightPressed, upPressed, downPressed,
			wPressed, xPressed;

	// 2d graphics
	SpriteBatch batch; // used to draw textures
	Texture texture;// the texture
	TextureRegion region;// part of the texture

	// 2d camera
	OrthographicCamera camera;// camera
	float width, height;// width and height of the camera view port
	Rectangle glViewport;// camera view port
	

	@Override
	public void create() {
		// initilizing with and height
		width = 480;
		height = 320;

		// new SpriteBatch
		batch = new SpriteBatch();
		// loading texture file
		texture = new Texture("data/map.png");
		// drawing a part from the texture (startX,startY,endX,endY)
		region = new TextureRegion(texture, 0, 0, 100, 100);

		// setting the camera
		camera = new OrthographicCamera(width, height);
		camera.position.set(width / 2, height / 2, 0);
		glViewport = new Rectangle(0, 0, width, height);

	}

	@Override
	public void render() {

		update();

		GL10 gl = Gdx.graphics.getGL10();

		// Camera --------------------- /
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		gl.glViewport((int) glViewport.x, (int) glViewport.y,
				(int) glViewport.width, (int) glViewport.height);

		camera.update();
		camera.apply(gl);

		// Drawing -------------------/
		batch.begin();
		batch.draw(texture, 10, 10);
		// batch.draw(region, 10,10);
		batch.end();

	}

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

	@Override
	public void pause() {
	}

	@Override
	public void resume() {
	}

	@Override
	public void dispose() {

	}

	private void update() {
		control();
		controlCall();

	}

	private void controlCall() {

		if (rightPressed) {

			camera.zoom -= 1; //doesn't work
			glViewport.x -= 1;
		}

		if (leftPressed) {
			glViewport.x += 1;
		}

		if (upPressed) {
			glViewport.y -= 1;
		}

		if (downPressed) {
			glViewport.y += 1;
		}

		if (wPressed) {
			glViewport.height += 1;
			glViewport.width += 1;
		}

		if (xPressed) {
			glViewport.height -= 1;
			glViewport.width -= 1;
		}

	}

	private void control() {

		leftPressed = Gdx.input.isKeyPressed(Keys.DPAD_LEFT);

		rightPressed = Gdx.input.isKeyPressed(Keys.DPAD_RIGHT);

		upPressed = Gdx.input.isKeyPressed(Keys.DPAD_UP);

		downPressed = Gdx.input.isKeyPressed(Keys.DPAD_DOWN);

		wPressed = Gdx.input.isKeyPressed(Keys.W);

		xPressed = Gdx.input.isKeyPressed(Keys.X);

	}
}

i tried to use translate and zoom in this example but as i said, i failed, now my questions are :
-is it okay to manipulate the camera this way ??
-from this point, how to correctly start with box2D ??
a shared code example will be very appreciate it, but please keep it simple :stuck_out_tongue:

thank you very much