I'm trying to code some breakout games with LibGDX and Box2D. But there is one point that I don't understand. There are must be two bricks only touch with edge. But on emulator I just saw two bricks nested.
Here's createBox method's code:
private void createBox(float posX, float posY, float boxW, float boxH) {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.set(posX, posY);
Body body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(boxW, boxH);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
Fixture fixture = body.createFixture(fixtureDef);
shape.dispose();
}
edit: That multiplied code.
createBox(CONS_HOLDER.BRICKS_LEFT_MARGIN + (i * CONS_HOLDER.BRICK_WIDTH * 2 ),
CONS_HOLDER.BRICK_TOP_SCREEN_MARGIN + (j * CONS_HOLDER.BRICK_HEIGHT * 2 ) + CONS_HOLDER.BRICKS_TOP_MARGIN,
CONS_HOLDER.BRICK_WIDTH / 2,
CONS_HOLDER.BRICK_HEIGHT / 2);
The documentation for setAsBox(float, float) states that the parameters are half-width and half-height. You should divide the dimensions of your boxes in half in order to get the correct size.
private void createBox(float posX, float posY, float boxW, float boxH) {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.set(posX, posY);
Body body = world.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(boxW / 2.f, boxH / 2.f);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1f;
Fixture fixture = body.createFixture(fixtureDef);
shape.dispose();
}
Documentation: https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/physics/box2d/PolygonShape.html#setAsBox-float-float-
Related
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;
}
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.
This happen when my Body object touching with wall and I hold right key. So it is stop as long I hold right key.
When I release my right key it dropped. How to fix this problem?
Here my script:
World Definition:
this.world = new World(new Vector2(0, -9.8f), true);
Create ground body from tilemap:
//create body and fixture variables
BodyDef bdef = new BodyDef();
PolygonShape shape = new PolygonShape();
FixtureDef fdef = new FixtureDef();
Body body;
//create ground bodies/fixtures
for(MapObject object : tileMap.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)){
rect = ((RectangleMapObject) object).getRectangle();
x = Static.toMeter(rect.getX() + rect.getWidth() / 2);
y = Static.toMeter(rect.getY() + rect.getHeight() / 2);
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(x, y);
body = world.createBody(bdef);
x = Static.toMeter(rect.getWidth() / 2);
y = Static.toMeter(rect.getHeight() / 2);
shape.setAsBox(x, y);
fdef.shape = shape;
fdef.filter.categoryBits = HookaHookaGame.GROUND_BIT;
body.createFixture(fdef);
}
Player body definition:
BodyDef bodyDef = new BodyDef();
bodyDef.position.set(Static.toMeter(128), Static.toMeter(HookaHookaGame.HEIGHT));
bodyDef.type = BodyDef.BodyType.DynamicBody;
body = world.createBody(bodyDef);
// Define mario shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(Static.toMeter(32) / 2, Static.toMeter(32) / 2);
FixtureDef fixture = new FixtureDef();
fixture.shape = shape;
body.createFixture(fixture);
// Define foot shape
shape = new PolygonShape();
shape.setAsBox(Static.toMeter(32 / 4) / 2, Static.toMeter(32 / 4) / 2, new Vector2(0, Static.toMeter((-32 + 8) / 2)), 0);
fixture = new FixtureDef();
fixture.shape = shape;
// Create filter
fixture.filter.categoryBits = HookaHookaGame.MARIO_BIT;
fixture.filter.maskBits = HookaHookaGame.GROUND_BIT;
body.createFixture(fixture).setUserData(this);
My ContactListener here my beginContact() method:
int cDef;
Fixture a, b;
MySprite spriteA, spriteB;
a = contact.getFixtureA();
b = contact.getFixtureB();
cDef = a.getFilterData().categoryBits | b.getFilterData().categoryBits;
switch (cDef) {
case HookaHookaGame.GROUND_BIT | HookaHookaGame.MARIO_BIT:
System.out.println("Foot with ground");
if(a.getUserData() != null) {
spriteA = (MySprite) a.getUserData();
spriteA.onHit();
}
if(b.getUserData() != null) {
spriteB = (MySprite) b.getUserData();
spriteB.onHit();
}
break;
}
Handling user input:
private void handleInput() {
//control our player using immediate impulses
if (Gdx.input.isKeyPressed(Input.Keys.D))
player.moveRight();
else if (Gdx.input.isKeyPressed(Input.Keys.A))
player.moveLeft();
else
player.stopMove();
if (Gdx.input.isKeyPressed(Input.Keys.SPACE))
player.jump();
}
I read his tutorial and it seem he didn't do anything about it and it works fine. His source code GitHub
The problem is that your linear impulse is to strong.
You can test this with the Mario project, if you increase the impulse you will get stuck at walls, too.
To solve this either lower the impulse, lower the friction (but then you might need code that stops Mario) or instead of applying an linear impulse you could apply a torch and use a circle shape to let the player "roll".
None of these solutions are perfect, but you can try and see which one suits you most.
I am developing a game with LibGdx. I am using scene2d actors in my game.
I have 2 arrows with this body
private void creatBody() {
BodyDef bd = new BodyDef();
bd.position.set(getX(), getY());
bd.type = BodyType.DynamicBody;
FixtureDef fd = new FixtureDef();
fd.density = 15f;
fd.friction = 0.6f;
fd.restitution = 0.02f;
if (body != null)
removeBodySafely(body);
body = world.createBody(bd);
body.setTransform(body.getWorldCenter(), MathUtils.degreesToRadians
* getRotation());
GameScreen.shapeLoader.attachFixture(body, type, fd, 1);
}
public void draw(SpriteBatch batch, float parentAlpha) {
setRotation(MathUtils.radiansToDegrees * body.getAngle());
setPosition(body.getPosition().x, body.getPosition().y);
TextureRegion keyFrame = GameScreen.getAtlas("arrows").findRegion(type);
batch.draw(keyFrame, getX(), getY(), 0, 0, getWidth(), getHeight(),
1, 1, getRotation());
}
Picture of the body
but, when I drop one arrow above another they overlap instead of colliding.
From description of body editor I found that there is a red mark which is the reference point.
How do I make the arrows collide?
I found the answer
GameScreen.shapeLoader.attachFixture(body, type, fd, 90);
where 90 is the width of arrow.
I am developing a game in which the user have to hit a high speed ball. To hit the ball I have joined a rectangular body with the actor using revolute joint and enabled its motor, to rotate it with a specified speed(motor speed). Now everything is perfect but sometime when ball`s velocity is high , it is bypassing the rectagular body. Using collision listner i found that collision is happening but ball is not getting reflected after collision.
As this is happening only when ball is on a high speed, is it bcoz of density of bodies that are colliding . Or its the motor of revolute joint that is responsible for it ?? Am i missing something here??
Here is the code for both bodies
// method for rectangular body
public Body createRectangleBodyPart(float x, float y, float width,
float height, short groupIndex) {
PolygonShape shape = new PolygonShape();
shape.setAsBox(width*WORLD_TO_BOX, height*WORLD_TO_BOX);
MassData massData = new MassData();
massData.mass = 15;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.KinematicBody;
bodyDef.position.y = y*WORLD_TO_BOX;
bodyDef.position.x = x*WORLD_TO_BOX;
body = world.createBody(bodyDef);
body.setMassData(massData);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 1;
fixtureDef.friction = 100f;
fixtureDef.restitution = 0.5f;
fixtureDef.filter.groupIndex=groupIndex;
body.createFixture(fixtureDef);
shape.dispose();
return body;
}
// method for ball body
public Body createRoundBodyPart2(float x, float y, float radius,
short groupIndex, float density, int mass) {
CircleShape shape = new CircleShape();
shape.setPosition(new Vector2(0, 0));
shape.setRadius(radius*WORLD_TO_BOX ); // *18
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.DynamicBody;
bodyDef.position.y = y*WORLD_TO_BOX;
bodyDef.position.x = x*WORLD_TO_BOX;
MassData massData = new MassData();
massData.mass = 8;
Body body = world.createBody(bodyDef);
body.setMassData(massData);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.5f;
fixtureDef.restitution=0.007f;
fixtureDef.filter.groupIndex = groupIndex;
body.createFixture(fixtureDef);
shape.dispose();
return body;
}
Try to use isBullet=true property on your ball body
Have you tried playing around with these properties: density, friction and restitution.
The ball could be moving so fast that on impact with the rectangular body, the force of the ball is to high for the rec body. Which means that the ball cannot be stopped by the rec body, that why it is passing through it.
Just a guess.
I managed to use box2d in libgdx. However the example code given here is for dynamic body only. I tried to use it and it works great but when i change the Dynamic to KinematicBody the code does not work. here is my code
#Override
public void create() {
// Create our body definition
BodyDef groundBodyDef =new BodyDef();
groundBodyDef.type = BodyDef.BodyType.StaticBody;
// Set its world position
groundBodyDef.position.set(new Vector2(0, 10));
// Create a body from the defintion and add it to the world
groundBody = world.createBody(groundBodyDef);
// Create a polygon shape
PolygonShape groundBox = new PolygonShape();
// Set the polygon shape as a box which is twice the size of our view port and 20 high
// (setAsBox takes half-width and half-height as arguments)
groundBox.setAsBox(camera.viewportWidth, 10.0f);
// Create a fixture from our polygon shape and add it to our ground body
groundBody.createFixture(groundBox, 0.0f);
// Clean up after ourselves
groundBox.dispose();
//endregion
BodyDef bodyDef = new BodyDef();
// We set our body to dynamic, for something like ground which doesnt move we would set it to StaticBody
bodyDef.type = BodyDef.BodyType.KinematicBody;
// Set our body's starting position in the world
bodyDef.position.set(bolaX, bolaY);
// Create our body in the world using our body definition
body = world.createBody(bodyDef);
// Create a circle shape and set its radius to 6
CircleShape circle = new CircleShape();
circle.setRadius(20f);
// Create a fixture definition to apply our shape to
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = circle;
fixtureDef.density = 20;
fixtureDef.friction = 0;
fixtureDef.restitution = 0.6f; // Make it bounce a little bit
// Create our fixture and attach it to the body
Fixture fixture = body.createFixture(fixtureDef);
// Remember to dispose of any shapes after you're done with them!
// BodyDef and FixtureDef don't need disposing, but shapes do.
circle.dispose();
Gdx.input.setInputProcessor(this);
}
#Override
public void render() {
world.step(1/60f, 6, 2);
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
camera.update();
//batch.getProjectionMatrix().set(camera.combined);
batch.begin();
textureBodies = body.getPosition();
float angle = MathUtils.radiansToDegrees * body.getAngle();
//batch.draw(ball,textureBodies.x ,textureBodies.y );
batch.draw(ball, textureBodies.x - (bola.getWidth() / 2) , textureBodies.y - (bola.getHeight()/2) , // the bottom left corner of the box, unrotated
1f, 1f, // the rotation center relative to the bottom left corner of the box
bola.getWidth(), bola.getHeight(), // the width and height of the box
1, 1, // the scale on the x- and y-axis
angle);
batch.end();
debugRenderer.render(world, camera.combined);
if(Gdx.input.isKeyPressed(Input.Keys.DPAD_UP)){
Gdx.app.log("Input Test", "key down: " + "aw ---- x" + body.getPosition().x + " y " + body.getPosition().y);
vel += 1;
//Gdx.app.log("vel","" + vel);
body.setLinearVelocity(0f,vel);
} else{
vel -= 1;
// Gdx.app.log("vel","" + body.getPosition().y);
body.setLinearVelocity(0f,vel);
}
int numContacts = world.getContactCount();
if (numContacts > 0) {
Gdx.app.log("contact", "start of contact list");
for (Contact contact : world.getContactList()) {
Fixture fixtureA = contact.getFixtureA();
Fixture fixtureB = contact.getFixtureB();
Gdx.app.log("contact", "between " + fixtureA.toString() + " and " + fixtureB.toString());
}
Gdx.app.log("contact", "end of contact list");
}
}
And here is the image.. You can see in the left side is the DynamicBody and the right side is the KinematicBody.
Getting the contacts works on Dynamic Body but not on Kinematic Body. Can you tell how to detect the collision in kinematic body?
Kinematic body dont collide with static body.
May be this will help you.
Kinematic Bodies are only influenced by velocities and not by forces
Static bodies have O displacement but are effected by forces i.e. they generate impulse upon collision whereas Dynamic Bodies have both