LibGx Box2D Pixels to Meters only drawing large objects - java

Im trying to learn about the Box2D physics engine.
Im using it in LibGX, and im facing a problem.
When i convert from Pixels to Meters, only large objects are drawn..
say this:
public class GameScreen implements Screen{
static int PPM = 100;
Box2DDebugRenderer debugRenderer;
World w = new World(new Vector2(0,-0.981f),true);
OrthographicCamera cam;
public static Body createDynamicBody(World world, int x, int y, int w,
int h, int density, int scale) {
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.DynamicBody;
def.position.set(x/scale,y/scale);
Body b = world.createBody(def);
FixtureDef fdef =new FixtureDef();
PolygonShape shape = new PolygonShape();
shape.setAsBox((w/2)/scale,(h/2)/scale);
fdef.shape = shape;
b.createFixture(fdef);
return b;
}
// initialized when Screen is loaded
#Override
public void show() {
cam = new OrthographicCamera();
font = new BitmapFont();
debugRenderer = new Box2DDebugRenderer();
cam.setToOrtho(false,800,480);
debugRenderer = new Box2DDebugRenderer();
// this body is not drawn
Body b = createDynamicBody(w,200,200,150,150,5, PPM);
// this body is drawn
Body b2 = createDynamicBody(w,200,200,200,200,5, PPM);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(0.2f,0.1f,0.7f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
debugRenderer.render(w,camera.combined.cpy().scale(PPM,PPM,0));
w.step(1/60f,6,2);
}
}

In your createDynamicBody you are using an int for scale. This is causing you to loose precision when you divide. Simple replace your int scale with float scale and it should work.
public static Body createDynamicBody(World world, int x, int y, int w,
int h, int density, float scale)

Related

Libgdx box2d body overlaps with sprite

I have been puzzling my mind with the code and I've made a huge amount of progress from not doing pixel to meter to now having a body and sprite almost in line however ive reached another point where i can't seem to figure out where I have gone wrong.
As you can see from the image the body is off from the actual sprite, I have a hunch that it might be origin as it the difference is very slight but I can't seem to work out how to get it in line.
My Create method
public class Physics1 extends ApplicationAdapter implements InputProcessor {
SpriteBatch batch;
Sprite sprite;
Texture img;
World world;
Body body;
Box2DDebugRenderer debugRenderer;
Matrix4 debugMatrix;
OrthographicCamera camera;
Vector2 bodyOrigin;
float torque = 0.0f;
boolean drawSprite = true;
final float PIXELS_TO_METERS = 100f;
final float WORLD_WIDTH =100;
final float WORLD_HEIGHT=100;
#Override
public void create() {
Assets.instance.init(new AssetManager());
batch = new SpriteBatch();
bodyOrigin = new Vector2();
sprite = new Sprite();
sprite.setRegion(Assets.instance.tyre.tyre);
sprite.setSize(12,12);
sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
sprite.setPosition(50-sprite.getWidth()/2,25);
Gdx.app.log("Physics1", "Sprite positions"+ -sprite.getWidth()/2+ " ,"+ -sprite.getHeight()/2);
world = new World(new Vector2(0, 0f),true);
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
BodyEditorLoader load = new BodyEditorLoader(Gdx.files.internal("levels/pittstop.json"));
bodyDef.position.set(sprite.getX()/PIXELS_TO_METERS,sprite.getY()/PIXELS_TO_METERS);
Gdx.app.log("Physics1", "Body positions calculations"+ sprite.getX() +" "+ sprite.getWidth()/2);
Gdx.app.log("Physics1", "Body positions"+ bodyDef.position);
body = world.createBody(bodyDef);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.density = 0.1f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution = 0.0f;
float scale =0.2f;
load.attachFixture(body, "tyre", fixtureDef, scale);
Gdx.app.log("Physics1"," Orgin of body" +load.getOrigin("tyre", scale).cpy());
bodyOrigin = load.getOrigin("tyre", scale).cpy();
body.setUserData("tyre");
Gdx.input.setInputProcessor(this);
debugRenderer = new Box2DDebugRenderer();
camera = new OrthographicCamera(WORLD_WIDTH,WORLD_HEIGHT);
Gdx.app.log("Physics1", "camera "+ camera.viewportWidth+" "+camera.viewportHeight);
camera.position.set(WORLD_WIDTH / 2f, WORLD_HEIGHT / 2f, 0);
Gdx.app.log("Physics1", "camera "+ camera.viewportWidth+" "+camera.viewportHeight);
}
My render method
public void render() {
camera.update();
world.step(1f/60f, 6, 2);
body.applyTorque(torque,true);
sprite.setPosition((body.getPosition().x * PIXELS_TO_METERS),
(body.getPosition().y * PIXELS_TO_METERS))
;
sprite.setRotation((float)Math.toDegrees(body.getAngle()));
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
debugMatrix = batch.getProjectionMatrix().cpy().scale(PIXELS_TO_METERS,
PIXELS_TO_METERS, 0);
batch.begin();
if(drawSprite)
batch.draw(sprite, sprite.getX(), sprite.getY(),bodyOrigin.x,
bodyOrigin.y,
sprite.getWidth(),sprite.getHeight(),sprite.getScaleX(),sprite.
getScaleY(),sprite.getRotation());
batch.end();
debugRenderer.render(world, debugMatrix);
}
False alarm, turns out in physics editor you have the opportunity to change the origin of the body you are drawing up, just by clicking around I was able to move the origin to the centre and there you have it.

Box2DBody not rendering LibGDX

I am trying to render a body, but it is not working. Other bodies render but this one won't. Here is the code in the Core class.
#Override
public void create () {
cam = new OrthographicCamera();
cam.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
b2dCam = new OrthographicCamera();
b2dCam.setToOrtho(false, Gdx.graphics.getWidth() / PPM, Gdx.graphics.getHeight() / PPM);
world = new World(new Vector2(0, -9.81f), true);
rend = new Box2DDebugRenderer();
batch = new SpriteBatch();
entity = new CircleEntity(world, 100, 200, 10, BodyType.DynamicBody);
entity.initBodyVariables(.1f, .1f, .1f);
//entity.attachSprite("badlogic.jpg");
BodyFactory.createBox(world, -1, 1f, 10000, .01f, BodyType.StaticBody, 1, 0, 0, "");
RopeJoint j = new RopeJoint(200,300, world);
j.create(4, 30);
}
#Override
public void render () {
b2dCam.update();
cam.update();
world.step(1/60f, 6, 2);
entity.update();
batch.setProjectionMatrix(b2dCam.combined);
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
rend.render(world, b2dCam.combined);
batch.begin();
entity.render(batch);
batch.end();
}
Here is the code for the bodyFactory:
public static Body createBox(World world, float x, float y, float width,
float height, BodyType type, float density, float friction, float restitution, Object data){
bodyDef = new BodyDef();
bodyDef.type = type;
bodyDef.position.set(new Vector2(x, y));
body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width / Core.PPM, height / Core.PPM);
fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = density;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
fixture = body.createFixture(fixtureDef);
fixture.setUserData(data);
shape.dispose();
return body;
}
When creating the box using this code, it renders it. I tried creating another body like this (in the CircleEntity class):
public class CircleEntity extends EntityParent {
/**
*
* #param world
* of game
* #param x
* position
* #param y
* position
* #param type
* of body (static, kinematic, dynamic)
*/
public CircleEntity(World world, float x, float y, float radius, BodyType type) {
super(world, x, y, radius, type);
createBody();
}
public void createBody() {
bodyDef = new BodyDef();
bodyDef.type = type;
bodyDef.position.set(position);
body = world.createBody(bodyDef);
CircleShape entityShape = new CircleShape();
entityShape.setRadius(radius / Core.PPM);
fixtureDef = new FixtureDef();
fixtureDef.shape = entityShape;
fixtureDef.density = density;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
fixture = body.createFixture(fixtureDef);
entityShape.dispose();
}
#Override
public void attachSprite(String filePath) {
super.attachSprite(filePath);
if (entitySprite != null) {
fixture.setUserData(entitySprite);
body.setUserData(entitySprite);
entitySprite.setPosition(position.x - dimensions.x, position.y - dimensions.y);
entitySprite.setSize(dimensions.x, dimensions.y);
}
}
#Override
public void update() {
super.update();
if (entitySprite != null)
entitySprite.setPosition(position.x - dimensions.x, position.y - dimensions.y);
if (Gdx.input.isKeyPressed(Keys.D))
body.applyForce(10, 0, position.x, position.y, true);
if (Gdx.input.isKeyPressed(Keys.A))
body.applyForce(-10, 0, position.x, position.y, true);
}
#Override
public void render(SpriteBatch batch) {
if (entitySprite != null)
entitySprite.draw(batch);
}
}
When I call this(I called it in the first set of code) it doesn't work. I can't figure out why only this entity won't render the circle. The collision still works with the body, so it is in the world but the circle itself I can't see. Any help with this is extremely appreciated.
To be clear, the Box2DBody isn't rendering, the Sprite is irrelevant.

libGDX orthographic camera view size (with Box2D)

I have next easy class with one ball and four walls around screen:
SpriteBatch batch;
Box2DDebugRenderer debugRenderer;
World world;
OrthographicCamera camera;
public float VIRTUAL_WIDTH = 720f;
public float VIRTUAL_HEIGHT = 1280f;
#Override
public void create () {
batch = new SpriteBatch();
camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT);
world = new World(new Vector2(0, -9), true);
debugRenderer = new Box2DDebugRenderer();
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
CircleShape circleShape = new CircleShape();
circleShape.setRadius(50);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.restitution = 1;
Body body = world.createBody(bodyDef);
body.createFixture(fixtureDef);
createWall(0f, -VIRTUAL_HEIGHT/2, VIRTUAL_WIDTH/2, 30f);
createWall(0f, VIRTUAL_HEIGHT/2, VIRTUAL_WIDTH/2, 30f);
createWall(-VIRTUAL_WIDTH/2, 0f, 30f, VIRTUAL_HEIGHT/2);
createWall(VIRTUAL_WIDTH/2, 0f, 30f, VIRTUAL_HEIGHT/2);
}
private void createWall(float x, float y, float hx, float hy){
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.set(x, y);
PolygonShape polygonShape = new PolygonShape();
polygonShape.setAsBox(hx, hy);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = polygonShape;
world.createBody(bodyDef).createFixture(fixtureDef);
}
#Override
public void render () {
camera.update();
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
world.step(1 / 60.0f, 8, 3);
batch.setProjectionMatrix(camera.combined);
batch.begin();
debugRenderer.render(world, camera.combined);
batch.end();
}
And it's do next screen on my device (maybe not perfect screenshot):
The screen is slightly shifted to the left, it's because rounding errors?
UPDATE:
Instead of this
public float VIRTUAL_WIDTH = 720f;
public float VIRTUAL_HEIGHT = 1280f;
Try this
public float VIRTUAL_WIDTH = Gdx.graphics.getWidth();
public float VIRTUAL_HEIGHT = Gdx.graphics.getHeight();

JBox2D + Slick2D - Doesn't collide

UPDATE
I have a hint. That is because the center of the screen in JBox2D is (0, 0). This is so weird because x and y are not from -1 to 1, it depends of the screen size.
This means the Util class I copied from the internet (everybody shared this code) is not up to date. I still need help because I can't find any 'algorithm' to have aspect ratio + screen size dependency.
BASE QUESTION
Since I have added the "slick2D to jbox2D position" and vice versa (it's like position in screen = position in screen / 100 for JBox), I don't get a good result. Screenshots below
I'm explaining with code:
public class Util {
private static final float SCALE = 0.01f; // 1/100 pixels
public static float toPosX(float posX) { return (posX * SCALE); }
public static float toPosY(float posY) { return (-posY * SCALE); }
public static float toScreenX(float posX) { return (posX / SCALE); }
public static float toScreenY(float posY) { return (-posY / SCALE); }
}
Square.java :
public class Square {
private Body body;
private Rectangle rectangle;
Square(World world, BodyType type, Vec2 pos, Vec2 size) {
float x = Util.toPosX(pos.x);
float y = Util.toPosY(pos.y);
float sx = Util.toPosX(size.x);
float sy = Util.toPosY(size.y);
//body definition
BodyDef bd = new BodyDef();
bd.position.set(x, y);
bd.type = type;
//define shape of the body.
PolygonShape cs = new PolygonShape();
cs.setAsBox(sx, sy);
//define fixture of the body.
FixtureDef fd = new FixtureDef();
fd.shape = cs;
fd.density = 1f;
fd.friction = 0.3f;
fd.restitution = 1.0f;
//create the body and add fixture to it
body = world.createBody(bd);
body.createFixture(fd);
rectangle = new Rectangle(0, 0, size.x, size.y);
rectangle.setLocation(pos.x, pos.y);
}
public Body getBody() { return this.body; }
public Rectangle getRectangle() { return this.rectangle; }
}
And finally my display class:
public class DisplayManager extends BasicGame {
private GameManager gameManager;
private Body b1, b2;
private Rectangle r1, r2;
private World world;
public DisplayManager(GameManager game) {
super("Title");
this.gameManager = game;
}
#Override
public void init(GameContainer container) throws SlickException {
this.gameManager.initPlayersSprites();
world = new World(new Vec2(0, -10));
Square s1, s2;
s1 = new Square(world, BodyType.STATIC, new Vec2(10, 800), new Vec2(1900, 30));
b1 = s1.getBody();
r1 = s1.getRectangle();
s2 = new Square(world, BodyType.DYNAMIC, new Vec2(945, 200), new Vec2(30, 30));
b2 = s2.getBody();
r2 = s2.getRectangle();
}
public void render(GameContainer container, Graphics g) throws SlickException {
float step = 1.0f / 600.0f;
world.step(step, 6, 2);
r1.setLocation(Util.toScreenX(b1.getPosition().x), Util.toScreenY(b1.getPosition().y));
r2.setLocation(Util.toScreenX(b2.getPosition().x), Util.toScreenY(b2.getPosition().y));
g.draw(r1);
g.draw(r2);
}
}
Here is the result :
first frame :
http://i.stack.imgur.com/WgQPK.png
some frames later :
http://i.stack.imgur.com/a1XyL.png
(the ground didn't move, it's just another screenshot took from my hand)
In other words, the cube falls down like for ever. I debugged the position of the cube and it doesn't stop to go down.
With Slick2D DebugDraw it doesn't help because the cube goes through the ground anyway.
Please note that in JBox2D, it worked with pixels measurements (that was not accurate at all but collisions worked well)
That was because of the negative size. (toPoxY reverse the y pos)

Correct way to extend org.jbox2d.dynamics.Body

I'm having a problem trying to extend org.jbox2d.dynamics.Body
I've set Rectangle to extend org.jbox2d.dynamics.Body and set it to be DYNAMIC, but the Rectangle will not move.
And if I create multiple Rectangle's, they're all positioned in the same position i.e (0.0f, 0.0f), why?
Rectangle is defined as:
public class Rectangle extends Shape {
private PolygonShape blockShape;
private Body body;
private float width;
private float height;
public Rectangle (
Vec2 centerPoint,
float angle,
float width, float height,
BodyType bt,
float density, float friction, float restitution,
World world,
BodyDef bd){
super(bd,world);
this.width = width;
this.height = height;
blockShape = new PolygonShape();
blockShape.setAsBox(this.width, this.height);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = blockShape;
fixtureDef.density = density;
fixtureDef.friction = friction;
fixtureDef.restitution = restitution;
this.bodydef.type = BodyType.DYNAMIC;
this.bodydef.position.set(centerPoint.x, centerPoint.y);
this.bodydef.angle = angle;
world.createBody(this.bodydef);
createFixture(fixtureDef);
setType(bt);
};
Shape has follow definition:
public abstract class Shape extends org.jbox2d.dynamics.Body{
protected World world;
protected BodyDef bodydef;
public Shape(BodyDef bd, World w) {
super(bd, w);
this.world = w;
this.bodydef = bd;
}
protected abstract void update();
protected abstract void draw(GLAutoDrawable gLDrawable);
}
In Level.java which extends org.jbox2d.dynamics.World
I create a Rectangle and call Rectangle.draw(gLDrawable)
new Rectangle(
new Vec2(1.0f,1.0f),//Vec2(x,y)
0.0f, //angle
2.0f, //width
2.0f, //height
BodyType.DYNAMIC, //bodyType
0.5f, //density
0.5f, //friction
0.5f, //restitution
this, //world
new BodyDef())); //BodyDef
Decided to use UserData of org.jbox2d.dynamics.Body
Example:
org.jbox2d.dynamics.Body body = level.createBody(bodydef);
body.setUserData(
new Shape(parameters)
);

Categories