PulleyJoint odd behaviour Box2D - java

I am trying to build a lever in an android game using box2d and libgdx. When the game starts, the 2 platforms of the lever are balancing perfectly and when I move a box on one platform of the lever, it goes down as expected but when I move the body out, the 2 platforms doesn't balance again as before.
I am using this code to create the 2 platforms:
private Body setupShape(World world, float cx, float cy, float cw, float ch){
Body ptf;
PolygonShape shape = new PolygonShape();
shape.setAsBox(cw / 2, ch / 2);
FixtureDef fdef = new FixtureDef();
fdef.shape = shape;
fdef.density = 1.0f;
fdef.friction = 1.0f;
fdef.restitution = 0.0f;
BodyDef bd = new BodyDef();
//bd.allowSleep = false;
bd.position.set(cx, cy);
bd.fixedRotation = true;
ptf = world.createBody(bd);
//lever.setGravityScale(10);
ptf.createFixture(fdef);
ptf.setType(BodyDef.BodyType.DynamicBody);
ptf.setUserData("Lever");
shape.dispose();
return ptf;
}
And this code for creating the lever using "PulleyJoint":
PulleyJointDef pulleyDef = new PulleyJointDef();
Vector2 bodyoneanchor = new Vector2(Constants.Pixel2SIf(360), Constants.Pixel2SIf(400));
Vector2 bodytwoanchor = new Vector2(Constants.Pixel2SIf(660), Constants.Pixel2SIf(400));
pulleyDef.initialize(bodyA, bodyB, bodyoneanchor, bodytwoanchor, bodyA.getWorldCenter(), bodyB.getWorldCenter(), 1);
world.createJoint(pulleyDef);
I would like to know what's wrong with my code and how to make the lever re-balance again after moving out objects from it.
Here's a drawing to demonstrate my problem more clearly:
http://costheta.net/quest.png
It will be very much appreciated if you could help me fixing that problem.
Best regards!
UPDATE:
Here's my new code after adding Prismatic joints:
PulleyJointDef pulleyDef = new PulleyJointDef();
Vector2 bodyoneanchor = new Vector2(Constants.Pixel2SIf(360), Constants.Pixel2SIf(400));
Vector2 bodytwoanchor = new Vector2(Constants.Pixel2SIf(660), Constants.Pixel2SIf(400));
pulleyDef.initialize(bodyA, bodyB, bodyoneanchor, bodytwoanchor, bodyA.getWorldCenter(), bodyB.getWorldCenter(), 1);
world.createJoint(pulleyDef);
BodyDef bd0 = new BodyDef();
bd0.position.set(bodyoneanchor.x, bodyoneanchor.y);
Body ptf0 = world.createBody(bd0);
PrismaticJointDef pjd0 = new PrismaticJointDef();
pjd0.initialize(ptf0, bodyA, ptf0.getWorldCenter(), new Vector2(0, 1));
pjd0.motorSpeed = 200f;
pjd0.maxMotorForce = 30.0f;
pjd0.enableMotor = true;
pjd0.lowerTranslation = -Math.abs(bodyA.getWorldCenter().y - bodyoneanchor.y);
pjd0.upperTranslation = 0;//Math.abs(bodyA.getWorldCenter().y - bodyoneanchor.y);
pjd0.enableLimit = true;
world.createJoint(pjd0);
BodyDef bd1 = new BodyDef();
bd1.position.set(bodytwoanchor.x, bodytwoanchor.y);
Body ptf1 = world.createBody(bd1);
PrismaticJointDef pjd1 = new PrismaticJointDef();
pjd1.initialize(ptf1, bodyB, ptf1.getWorldCenter(), new Vector2(0, 1));
pjd1.motorSpeed = 200f;
pjd1.maxMotorForce = 30.0f;
pjd1.enableMotor = true;
pjd1.lowerTranslation = -Math.abs(bodyB.getWorldCenter().y - bodytwoanchor.y);
pjd1.upperTranslation = 0;//Math.abs(bodyB.getWorldCenter().y - bodytwoanchor.y);
pjd1.enableLimit = true;
world.createJoint(pjd1);

They shouldn't re-balance because the weight of each side is the same and the tensions cancel each other out, resulting in no movement (get some string and build the setup in real life).
If you want it to re-balance, add a spring on each platform with a length of zero placed on the initial position and center of the box.

Related

Different Box2D bodies act differently and unexpectedly with same mass

I have a box2d body which is simply a rectangle (the spaceship).
This ship flies around, affected by the gravity of planets (static circle bodies) just fine.
I have tried changing the ship fixture shape to both (1) a triangle fixture and also (2) two rectangular fixtures put together. Both of these body configurations are causing problems.
Given the change in volume, to make up for the difference in mass I calculated the necessary new densities so that these bodies have the same mass as the original rectangle body. However when launching the ship with the same linear impulse as before, the triangular body and multi-rectangular body both act differently than the original body and shoot forward much faster.
I have tried further tweaking the ship density as well as the linear impulse and also the planet gravity to return the ship to a normal pace of movement,
however when doing that the ship starts to act weird and will do things like suddenly switch direction in mid-air even though there's no collision. This collision-looking event does not happen when the density/gravity/linear impulse are all the same as before, however in that situation the ship is moving too fast for my needs.
Basically I don't know why these bodies are acting differently when there is no change in mass or anything besides shape and size. There's no linear damping or collisions happening. I don't know what else could possibly be affecting the ship.
Any help or ideas is greatly appreciated.
Here is the code that I believe is relevant:
public void createShipBody() {
density = 0.05f; //normal rectangle
//density = 0.06666667f; //density for the two rectangles together
restitution = 1.0f;
bodyDef.type = BodyDef.BodyType.DynamicBody;
setBodyDefPosition(bodyDef);
body = GameCore.world.createBody(bodyDef);
setShipShapeAndFixture();
}
// For with the original rectangle
private void setShipShapeAndFixture() {
PolygonShape shape = new PolygonShape();
shape.setAsBox(Utility.pixelsToMeters(bodyWidth / 2), Utility.pixelsToMeters(bodyHeight / 2));
createFixtureDef(shape);
shape.dispose();
}
// For with triangle fixture
private void setShipShapeAndFixture() {
Vector2[] vertices = new Vector2[3];
vertices[0] = new Vector2(0, 0);
vertices[1] = new Vector2(Utility.pixelsToMeters(bodyWidth), 0);
vertices[2] = new Vector2(Utility.pixelsToMeters(bodyWidth/2), Utility.pixelsToMeters(bodyHeight));
shape.set(vertices);
createFixtureDef(shape);
shape.dispose();
}
// For multi-rectangle body
private void setShipShapeAndFixture() {
PolygonShape shape = new PolygonShape();
shape.setAsBox(Utility.pixelsToMeters(bodyWidth / 2), Utility.pixelsToMeters(bodyHeight / 4));
PolygonShape shape2 = new PolygonShape();
shape2.setAsBox(Utility.pixelsToMeters(bodyWidth / 4), Utility.pixelsToMeters(bodyHeight / 4), new Vector2(0, Utility.pixelsToMeters(bodyHeight/2)), 0);
createShipMultiFixtureDef(shape, shape2);
shape.dispose();
shape2.dispose();
}
private void createFixtureDef(PolygonShape shape) {
FixtureDef polygonFixtureDef = new FixtureDef();
polygonFixtureDef.shape = shape;
polygonFixtureDef.density = density;
polygonFixtureDef.restitution = restitution;
body.createFixture(polygonFixtureDef);
}
private void createShipMultiFixtureDef(PolygonShape shape, PolygonShape shape2) {
FixtureDef polygonFixtureDef = new FixtureDef();
polygonFixtureDef.shape = shape;
polygonFixtureDef.density = density;
polygonFixtureDef.restitution = restitution;
FixtureDef polygonFixtureDef2 = new FixtureDef();
polygonFixtureDef2.shape = shape2;
polygonFixtureDef2.density = density;
polygonFixtureDef2.restitution = restitution;
body.createFixture(polygonFixtureDef);
body.createFixture(polygonFixtureDef2);
}
/**
* This is inside the Ship class
* #param x From world center of release
* #param y From world center of release
* #param distance The capped distance of release from shipCenter, to determine force of impulse
*/
protected void applyLinearImpulse(float x, float y, float distance, float maxDistance) {
float deltaX = x - getXinPixels();
float deltaY = y - getYinPixels();
float scale = 0.8f; // Have tried playing around with this with different bodies
float force = scale * (distance/maxDistance);
float angle = (float) Math.atan2(deltaY, deltaX);
bodyWrapper.body.applyLinearImpulse(new Vector2((float) Math.cos(angle) * force,
(float) Math.sin(angle) * force), getWorldCenter(), true);
}
// This is called on each planet every game update
protected void applyGravity() {
for (SpaceObject spaceObject:spaceObjects) {
float scalar = 2.334f;
if(spaceObject instanceof Ship) {
if (gameCore.shipInMotion) {
scalar = 2f; //Have tried playng with this for different bodies
}
else {
continue; //No gravity to ship until it's launched
}
}
Vector2 objectWorldCenter = spaceObject.getWorldCenter();
Vector2 planetWorldCenter = getWorldCenter();
float planetDiameter = Utility.pixelsToMeters(getWidth());
float distance = Utility.distance(planetWorldCenter.x, planetWorldCenter.y, objectWorldCenter.x, objectWorldCenter.y);
float xDistance = planetWorldCenter.x - objectWorldCenter.x;
float yDistance = planetWorldCenter.y - objectWorldCenter.y;
float x = (float) ((xDistance * planetDiameter * scalar) / (distance*distance));
float y = (float) ((yDistance * planetDiameter * scalar) / (distance*distance));
Vector2 gravity = new Vector2(x, y);
spaceObject.bodyWrapper.body.applyForceToCenter(gravity, true);
}
}

Libgdx - strange behavior of two Actors(hero and coins) after they collide

I'm currently creating an 2d infinite runner game. In my game, I have Two actors , the Hero and a Coins, both of their body's are set to dynamic, but everytime the Hero hits/collides the coins, the hero moved to left(the hero's get affected by the coins).
Here's my code, i dont know if whats wrong in my settings, Any help, will be appreciated.
public static Body createRunner(World world) {
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(new Vector2(Constants.RUNNER_X, Constants.RUNNER_Y));
PolygonShape shape = new PolygonShape();
shape.setAsBox(Constants.RUNNER_WIDTH / 2, Constants.RUNNER_HEIGHT / 2);
Body body = world.createBody(bodyDef);
body.setGravityScale(Constants.RUNNER_GRAVITY_SCALE);
body.setUserData(new RunnerUserData());
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.0f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution = 0.0f;
body.createFixture(fixtureDef);
body.resetMassData();
body.setUserData(new RunnerUserData(Constants.RUNNER_WIDTH, Constants.RUNNER_HEIGHT));
shape.dispose();
return body;
}
public static Body createCoins(World world) {
EnemyType enemyType = RandomUtils.getRandomEnemyType();
BodyDef bodyDef = new BodyDef();
//bodyDef used to set the enemy to make it not be affected when the runner hit
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(new Vector2(enemyType.getX(), enemyType.getY()));
PolygonShape shape = new PolygonShape();
shape.setAsBox(enemyType.getWidth() / 2, enemyType.getHeight() / 2);
Body body = world.createBody(bodyDef);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = -100.0f;
fixtureDef.friction = 0.0f;
fixtureDef.restitution = -50.0f;
body.createFixture(fixtureDef);
body.resetMassData();
EnemyUserData userData = new EnemyUserData(enemyType.getWidth(), enemyType.getHeight(), enemyType.getRegions());
body.setUserData(userData);
shape.dispose();
return body;
}
Thanks
I'd set the ContactFilter to your world instance via world.setContactFilter
This will give you a callback whenever you fixtures collide. Should you return false from this callback it should prevent Box2D from resolving your collision, which is likely what's pushing your hero left.
ContactListener listener = new ContactListneer(){
public boolean shouldCollide(Fixture fixtureA,
Fixture fixtureB){
Body bodyA = fixtureA.getBody();
Body bodyB = fixtureB.getBody();
/* !!! You'll need to implement this next part !!!*/
//figure out which body is hero, which body is coin
//if this is a collision between a hero and coin....
{
world.destroyBody(coinBody);
return false;
}
//else
return true;
}
};
world.setContactFilter(contactFilter);

How to construct and draw a nice rope with box2d

I created a rope in box2d with RevoluteJoint and a RopeJoint but I have several problems with it:
From time to time, the last segment rotates and it looks like it was disconnected from the rope.
How to draw this thing? I create a texture with the size of each link. If the rope isn't moving it looks good, but as soon as the rope moves and the different links start to rotate slightly, you see gaps between the links.
Code:
private void createChain(World world, Body anchorBody) {
Body previousBody = anchorBody;
FixtureDef fixtureDef = new FixtureDef();
PolygonShape robeLinkShape = new PolygonShape();
robeLinkShape.setAsBox(4 / PPM, 8 / PPM);
fixtureDef.shape = robeLinkShape;
fixtureDef.density = 0.1f;
// fixtureDef.friction = 1.0f;
fixtureDef.restitution = 0.1f;
fixtureDef.filter.maskBits = Box2DConst.BIT_PLAYER;
fixtureDef.filter.categoryBits = Box2DConst.BIT_GROUND;
float mapX = anchorBody.getPosition().x * PPM;
float mapY = anchorBody.getPosition().y * PPM;
BodyDef bodyDef = new BodyDef();
bodyDef.angularDamping = 1.0f;
bodyDef.linearDamping = 1.0f;
//create rope
for (int i = 0; i < 10; i++) {
Float robeX = mapX / PPM;
Float robeY = (mapY - (i * 16)) / PPM;
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(robeX, robeY);
final Body link = world.createBody(bodyDef);
link.createFixture(fixtureDef);
RevoluteJointDef jointDef = new RevoluteJointDef();
jointDef.initialize(previousBody, link, new Vector2(robeX, robeY));
//don't need the rope to collide itself
jointDef.collideConnected = false;
jointDef.enableLimit = false;
// because we don't collide with other bodies in the rope, limit rotation to keep the rope bodies from rotating too much.
jointDef.lowerAngle = -5.0f * MathUtils.degreesToRadians;
jointDef.upperAngle = 5.0f * MathUtils.degreesToRadians;
world.createJoint(jointDef);
links.add(link);
previousBody = link;
}
RopeJointDef ropeJointDef = new RopeJointDef();
ropeJointDef.localAnchorB.set(0, 0);
ropeJointDef.maxLength = 90.0f;
ropeJointDef.bodyB = previousBody;
ropeJointDef.bodyA = links.get(0);
ropeJointDef.collideConnected = false;
world.createJoint(ropeJointDef);
}
public void draw(final SpriteBatch batch) {
Texture texture = FipiGame.res.get("rope");
batch.begin();
for (Body link : links) {
float x = (link.getPosition().x * PPM) - 4;
float y = (link.getPosition().y * PPM) - 8;
float angleDeg = MathUtils.radiansToDegrees * link.getAngle();
batch.draw(texture, x, y, 0, 0, texture.getWidth(), texture.getHeight(), 1f, 1f, angleDeg, 0, 0,
texture.getWidth(), texture.getHeight(), false, false);
}
batch.end();
}
Instead of drawing based on body positions and rotations: Create a set of points by looping through the revolute joint positions (midpoint of anchorA and anchorB in world space). Then draw your sprites so they connect those positions. This will be somewhat inaccurate in that it won't perfectly line up with the positions of the rigid bodies, but it should look all right.

(Java, LibGDX, Box2D) Stuttering

I programed a basic Box2d-"Game": No textures and suchlike, Only a player(body), who jumps from one static groundbody to another.
The problem is that the ground respectively the playerbody, which is followed by the camera, stutters every few seconds.
(https://www.dropbox.com/s/llsg2q65lz828t6/stuttering.avi) (download this video, please, otherwise your flashplayer will show much more stuttering)
If you look between the groundelements, you can see this very good.
Binded textures stutters too.
Curiously: There aren't any stucks in fullscreen mode (config.fullscreen = true); Only on Android-Phones and in window mode.
Although it is only a small game, I have tried to use Interpolation and analysed the GC-actions: No result :\
Thanks in advance!
Some peaces of my code (I turned off the Interpolation):
private float step = 1.0f / 60.0f;
public void show()
{
//...
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(0, 0);
//...
ChainShape groundShape = new ChainShape();
float width = 20;
float height = 0.25f;
fixtureDef.restitution = 0.0f;
fixtureDef.friction = 0.5f;
fixtureDef.shape = groundShape;
fixtureDef.friction = .5f;
fixtureDef.restitution = 0;
groundShape.createChain(new Vector2[] { new Vector2(0, 0), new Vector2(width, 0), new Vector2(width, -height), new Vector2(0, -height), new Vector2(0, 0) });
fixtureDef.shape = groundShape;
world.createBody(bodyDef).createFixture(fixtureDef);
groundShape.dispose();
groundShape = new ChainShape();
bodyDef.position.set(25, 0);
groundShape.createChain(new Vector2[] { new Vector2(0, 0), new Vector2(width, 0), new Vector2(width, -height), new Vector2(0, -height), new Vector2(0, 0) });
fixtureDef.shape = groundShape;
world.createBody(bodyDef).createFixture(fixtureDef);
groundShape.dispose();
//...
}
public void render(float delta)
{
world.step(step, 8, 3);
input.update();
playCam.position.set(player.getBody().getPosition().x + 6.5f, 3.5f, 0);
playCam.update();
player.move();
debugRenderer.render(world, playCam.combined);
}
Player-Class:
move()
{
playerbody.setLinearVelocity(20f, 0);
}

Drawing using textureRegion

I'm trying to make a movable car in java, using libgdx and box2d;
I made a car, m_car, with position set in middle of the car.
In every step, i take take the current position of the m_car, decrese that values with the cars width/height, so i have the left bottom corner. When is on a straight ground, it shows well, the texture is where is should be, but when the ground have an angle, the texture position its under, or upper the car.
I don't understand how TextureRegion works, i think that when the angle is not 0, i dont take the point of drawing well, and i dont know how to solve it. help me pls :)
Ty.
Edit:
my code is a mess, its not an actual project, its an ideea, and i took pieces, and put them down to see how they work, so when il start the project, i would know what to do, this is my car declaration:
private void car2(){
m_hz = 5.0f;
m_zeta = 0.7f;
m_speed = 50.0f;
BodyDef bd = new BodyDef();
bd.type = BodyType.DynamicBody;
part1(bd);
part2(bd);
part3(bd);
wheels(bd);
m_car.setAwake(true);
}
private void part3(BodyDef bd) {
PolygonShape shape = new PolygonShape();
shape.setAsBox(0.01f, 0.35f,new Vector2(1.01f - 3, 4.85f - 4), 0);
m_car.createFixture(shape, 1.0f);
}
private void part1(BodyDef bd){
PolygonShape chassis = new PolygonShape();
Vector2 vertices[] = new Vector2[6];
vertices[0] = new Vector2(-2, -0.5f);
vertices[1] = new Vector2(-2, 0.5f);
vertices[2] = new Vector2(1.25f, 0.5f);
vertices[3] = new Vector2(2.5f, 0.15f);
vertices[4] = new Vector2(2.5f, -0.5f);
vertices[5] = new Vector2(-2, -0.5f);
chassis.set(vertices);
bd.position.set(new Vector2(3, 4));
m_car = m_world.createBody(bd);
m_car.createFixture(chassis, 1.0f);
}
private void part2(BodyDef bd){
PolygonShape chassis = new PolygonShape();
Vector2 vertices[] = new Vector2[5];
vertices[0] = new Vector2(3, 4.5f);
vertices[1] = new Vector2(3, 5.25f);
vertices[2] = new Vector2(3.80f, 5.25f);
vertices[3] = new Vector2(4.25f, 4.5f);
vertices[4] = new Vector2(3, 4.5f);
for (int i = 0; i < 5; ++ i){
vertices[i].x -= 3;
vertices[i].y -= 4;
}
chassis.set(vertices);
//m_car = m_world.createBody(bd);
m_car.createFixture(chassis, 1.0f);
}
private void wheels(BodyDef bd){
CircleShape circle = new CircleShape();
circle.setRadius(0.4f);
FixtureDef fd = new FixtureDef();
fd.shape = circle;
fd.density = 1.0f;
fd.friction = 0.9f;
bd.position.set(2f, 3.5f);
m_wheel1 = m_world.createBody(bd);
m_wheel1.createFixture(fd);
bd.position.set(4.5f, 3.5f);
m_wheel2 = m_world.createBody(bd);
m_wheel2.createFixture(fd);
WheelJointDef jd = new WheelJointDef();
Vector2 axis = new Vector2(1.0f, 0.5f);
jd.initialize(m_car, m_wheel1, m_wheel1.getPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 20.0f;
jd.enableMotor = true;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring1 = (WheelJoint) m_world.createJoint(jd);
jd.initialize(m_car, m_wheel2, m_wheel2.getPosition(), axis);
jd.motorSpeed = 0.0f;
jd.maxMotorTorque = 10.0f;
jd.enableMotor = false;
jd.frequencyHz = m_hz;
jd.dampingRatio = m_zeta;
m_spring2 = (WheelJoint) m_world.createJoint(jd);
}
some explenation: why i have for for vertices to decreese 3 and 4 ? i didnt know that if i set position to the bodydef, the vertices consider that point to be 0, 0, when i found out, was easyer to me to just decrese (cuz its just for test, to see how it works)
and this is how i draw:
float angle = (float) Math.toDegrees(m_car.getAngle());
batch.draw(textureRegion, x, y, 3f, 4f,
4.5f, 2.75f, 1f, 0.61f, angle);
For a realistic car in Box2D you might find this useful: http://www.iforce2d.net/b2dtut/top-down-car
About your problem with the angle: You need to supply the angle of the car to the spriteBatch. TextureRegion doesn't know ANYTHING about where or how it is supposed to be rendered. You need to tell the spriteBatch about those informations.
You can use a Sprite for that. A Sprite can be manipulated with setRotation(), setPosition() etc and then being draw with Sprite.draw(spriteBatch) instead of `spriteBatch.draw(sprite)
Furthermore, be careful with your PIXEL_TO_METER conversion and remember to update your Cameras properly.

Categories

Resources