Box2D Polygon Bodies not rotating - java

I'm trying to create a game with "libGDX" and "Box2D".
I've several shapes in the game, so I created a BodyFactory class which creates my bodies using PolygonShape
The problem is, when I create a body, with Shape.setAsBox() method, everything works fine, but when I create bodies with PolygonShape.set(vertices), the position of bodies changes as I wish, but they won't rotate at all.
This is what I get (after stability) when I drop 3 bodies from the sky:
The square rotates and stays at the ground, bot the other shapes won't.
Also note that I tried adding
body.setFixedRotation(false);
to my code, but nothing changed.
Also friction, mass and density of shapes are at a reasonable amount.
This is the part of my code which creates a "PolygonShape" from a file:
...
Body body = world.createBody(bodyDef);
...
for (int i = 0; i < bodyConf.meshData.length; i++) {
PolygonShape polygonShape = new PolygonShape();
polygonShape.set(bodyConf.meshData[i]);
fixtureDef.shape = polygonShape;
body.createFixture(fixtureDef);
polygonShape.dispose();
}

I think the problem is that you are creating only one Body with three Fixtures attached to it.
What you actually want is three Bodys, with one Fixture attached to each of them. That way, each body can rotate independent from the others.
for (int i = 0; i < bodyConf.meshData.length; i++) {
BodyDef bodyDef = ...;
Body body = world.createBody(bodyDef);
PolygonShape polygonShape = new PolygonShape();
polygonShape.set(bodyConf.meshData[i]);
fixtureDef.shape = polygonShape;
body.createFixture(fixtureDef);
polygonShape.dispose();
}

Related

Jbox2d Issues with positioning platforms

I am working on developing a platformer, and everything's working fine, except, I seem to be unable to position the bodies for the static platforms.
// creating all the bodies
BodyDef bdef = new BodyDef();
bdef.position.set(x, y);
bdef.type = BodyType.STATIC;
Body body = world.createBody(bdef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width, height);
FixtureDef fdef = new FixtureDef();
fdef.friction = 0.3f;
fdef.shape = shape;
body.createFixture(fdef);
This is general code that's used to create every body in the map. The bodies work fine, but they don't line up with the width nor the coordinates of the map that I've set. I've noticed that I must specify the bottom left point as starting point for it to make body, but what else I am missing? Why bodies tend to be bigger and go past the starting point of X and Y?
Bodies in box2d are made from their center points. When you define it's position, you are setting it's center and when you define it's width/height, you are actually setting half the width/height (i.e. the size ends up double what you intended).

How to combine Box2d bodies?

I have a texture which is not just a box or circle and my body needs to be the same of this shape so I was thinking to combine multiple bodies to achieve my desired shape, is it even possible? or there are better ways to do it? I'm using java with libgdx framework.
The shape of body is being defined by Fixture instance. Since body can have multiple fixtures you can combine many shapes as you wish.
To create many fixtures you jest call createFixture method many times with others FixtureDef objects like
FixtureDef fd1 = new FixtureDef();
FixtureDef fd2 = new FixtureDef();
...
fd1.shape = shape1;
fd2.shape = shape2;
...
body.createFixture(fd1);
body.createFixture(fd1);
Although please notice that Box2D supports more than circles and rectangles by providing ChainShape that allows you to create any shape you want
ChainShape weird = new ChainShape();
weird.createLoop( new float[]{vertice1x, vertice1y, vertice2x, ...});
To join bodies there is Joint (take a look here) mechanism but I guess it's not what you want here
Yes you can do so by following steps below
There is an option of PolygonShape or ChainShape which suits your work
Step 1: Define a body.
BodyDef bd = new BodyDef();
Body body = box2d.world.createBody(bd);
Step 2: Define the Shape.
ChainShape chain = new ChainShape();
Step 3: Configure the Shape.
The ChainShape object is a series of connected vertices. To create the chain, we must first specify an array of vertices (each as a Vec2 object).
To create the chain with the vertices, the array is then passed into a function called
createChain().Vec2[] vertices = new Vec2[2];
vertices[0] = box2d.coordPixelsToWorld(0,150);
vertices[1] = box2d.coordPixelsToWorld(width,150);
chain.createChain(vertices, vertices.length);
A Shape is not part of Box2D unless it is attached to a body. Even if it is a fixed boundary and never moves, it must still be attached.
FixtureDef fd = new FixtureDef();
fd.shape = chain; A fixture assigned to the ChainShape
fd.density = 1;
fd.friction = 0.3;
fd.restitution = 0.5;
body.createFixture(fd);
Polygon Shape
PolygonShape ps = new PolygonShape();
ps.setAsBox(box2dW, box2dH);
Vec2[] vertices = new Vec2[4];
vertices[0] = box2d.vectorPixelsToWorld(new Vec2(-15, 25));
vertices[1] = box2d.vectorPixelsToWorld(new Vec2(15, 0));
vertices[2] = box2d.vectorPixelsToWorld(new Vec2(20, -15));
vertices[3] = box2d.vectorPixelsToWorld(new Vec2(-10, -10));
PolygonShape ps = new PolygonShape();
ps.set(vertices, vertices.length);
Official testbed examples
I strongly recommend that you go over all the Testbed examples on the GUI until you find the effect you are looking for.
By doing so, I was able to find the following examples:
multiple fixtures per body as mentioned at https://stackoverflow.com/a/35667538/895245 :
https://github.com/erincatto/Box2D/blob/f655c603ba9d83f07fc566d38d2654ba35739102/Box2D/Testbed/Tests/ShapeEditing.h#L61
https://github.com/erincatto/Box2D/blob/f655c603ba9d83f07fc566d38d2654ba35739102/Box2D/Testbed/Tests/CompoundShapes.h
This is the best approach I've seen so far.
ChainShape: https://github.com/erincatto/Box2D/blob/f655c603ba9d83f07fc566d38d2654ba35739102/Box2D/Testbed/Tests/CharacterCollision.h#L56 But it won't work if one of the edges of your shape is not a straight line, e.g. a circle.
WeldJoint: https://github.com/erincatto/Box2D/blob/f655c603ba9d83f07fc566d38d2654ba35739102/Box2D/Testbed/Tests/Cantilever.h
However, this does not make the two bodies completely joined, as can be seen on the example itself, and from the Box2D manual:
It is tempting to use the weld joint to define breakable structures. However, the Box2D solver is iterative
so the joints are a bit soft. So chains of bodies connected by weld joints will flex
So it is more like a revolute joint that attempts to leave the two bodies at a given angle.
Those examples are very simple, and will be supported as Box2D evolves.
To create different shapes you can get idea from these examples:
To create circle shape.
bodyDef.type = b2Body.b2_dynamicBody;
var fixDef = new b2FixtureDef;
fixDef.density = 1000;
fixDef.friction = 0.5;
fixDef.restitution = 0.5;
fixDef.shape = new b2CircleShape(0.5);
bodyDef.position.x = 1;
bodyDef.position.y = 16;
world.CreateBody(bodyDef).CreateFixture(fixDef);
To create box(Rectangle or Square) shape.
var fixDef = new b2FixtureDef;
fixDef.density = 100;
fixDef.friction = 5;
fixDef.restitution = 0.5;
bodyDef.type = b2Body.b2_dynamicBody;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsBox(0.2,1);
bodyDef.position.x =i;
bodyDef.position.y = 15.5;
world.CreateBody(bodyDef).CreateFixture(fixDef);
To create unbox shape(polygon).
bodyDef.type = b2Body.b2_dynamicBody;
fixDef.shape = new b2PolygonShape;
fixDef.shape.SetAsArray([
new b2Vec2(-1,0.5),//left vertex
new b2Vec2(3,-0.3),//top vertex
new b2Vec2(3,0.5),//right vertex
],3);
bodyDef.position.x =5;
bodyDef.position.y = 16;
world.CreateBody(bodyDef).CreateFixture(fixDef);

How to create infinite Platform with Box2d?

I'm making a side scrolling game and I wan't to know how can I create an infinite terrain, do I need to use a static body that keeps on increasing its width? Also since its an infinite world, is it a good idea to just create a body to be used as an obstacle and then remove it when not in range?
public Body createPlatform(){
Body body;
BodyDef def = new BodyDef();
def.type = BodyDef.BodyType.StaticBody;
def.fixedRotation = true;
def.position.set(0.6f, 1.6f);
body = world.createBody(def);
PolygonShape shape = new PolygonShape();
shape.setAsBox(2f, 1.5f);//have no Idea how to increase width infinitely or should I even be using a Body as ground.
FixtureDef fDef = new FixtureDef();
fDef.shape = shape;
fDef.density = 1f;
body.createFixture(fDef);
shape.dispose();
return(body);
}
Also I'm using Libgdx library and java of course.
It's best to split the world into chunks: once the player exits one chunk, load in one or more. You do not need to have the chunks pre-loaded; you load them in on the fly depending on the player's location.

Drawing rotated bodies using JBox2D and JavaFX

I'm doing some initial experiments for a CS course, where I'm trying to use JBox2D as a physics library and drawing using JavaFX. I have had some luck draw circles that fall from the top of the screen, but now I have issues doing the same with rectangles (or any other shape).
I'm able to both draw and simulate, but I cannot figure out how to rotate the drawn nodes in JavaFX using values from the Body objects.
Here's my code for the bodies using JBox2D:
#Override
public Body createBody() {
BodyDef bd = new BodyDef();
bd.type = BodyType.DYNAMIC;
bd.position.set(centerX, centerY);
PolygonShape ps = new PolygonShape();
ps.setAsBox(2.0f,4.0f);
FixtureDef fd = new FixtureDef();
fd.shape = ps;
fd.density = 0.9f;
fd.friction = 0.3f;
fd.restitution = 0.5f;
Body b = PhysicalScene.world.createBody(bd);
b.createFixture(fd);
return b;
}
}
This is drawn using nodes in JavaFX - as written here:
#Override
public Node create() {
Rectangle r = new Rectangle();
r.setHeight(20);
r.setWidth(40);
r.setStroke(Color.RED);
r.setLayoutX(Physics.toPixelX(centerX));
r.setLayoutY(Physics.toPixelY(centerY));
// THIS IS WHAT I'M MISSING
// r.setRotate(/* some value from Body */);
return r;
}
The code isn't pretty, but I hope you get the idea. I am able to rotate the nodes by inserting arguments in the method, but do not know how to get these values from the Body objects themselves.
I hope you can help, thanks!

Box2D static body collision performance issue

I'm using JBox2d to perform collision detection in a game project I'm working on.
I represent obstacles in the world with static bodies. Whenever a dynamic body (i.e. a game character) collides with one of these obstacles, there is a very noticeable drop in performance. Fps will drop from ~120 to ~5. This seems to happen more frequently when the corners of the static body are collided with.
When I set the body type of the world obstacles to be dynamic instead of static, with very high density(to prevent the body from moving when it is collided with), this issue disappears... This solution is not ideal for my situation however......
Any ideas as to what could be causing this huge fps drop?
Here's the code I use to create the static bodies:
BodyDef def = new BodyDef();
def.type = BodyType.STATIC; // If this line is commented and the other
//commented lines are uncommented, the issue goes away.
//def.type = BodyType.DYNAMIC;
def.position.set(worldBounds.getCenterX(), worldBounds.getCenterY());
Body staticBody = b2World.createBody(def);
PolygonShape box = new PolygonShape();
box.setAsBox(worldBounds.getWidth() * 0.5f, worldBounds.getHeight() * 0.5f);
FixtureDef fixture = new FixtureDef();
fixture.shape = box;
fixture.friction = 0.3f;
//fixture.density = 1000000000;
staticBody.createFixture(fixture);
//staticBody.setSleepingAllowed(true);
//staticBody.setFixedRotation(true);
I've tried using a CircleShape instead of a PolygonShape, but that doesn't help anything.
Thank you!
this is the code from the game im working on at the moment which works fine. hopefully if you copy and paste, change a few variable names and stuff it might sort your problem. im new to box2d so cant tell you exactly where the problem lies. hope it helps.
//bodydef
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(position);
body = world.createBody(bodyDef);
//shape
PolygonShape shape = new PolygonShape();
shape.setAsBox(dimension.x / 2, dimension.y / 2);
//fixture
FixtureDef fixture = new FixtureDef();
fixture.friction = 0.3f;
fixture.shape = shape;
body.createFixture(fixture);
shape.dispose();

Categories