Hi,
In our upcoming android game we are adding some box2d joints and in this post we would be creating a revolute joint. We are using Libgdx engine to make the game. Below is a screenshot of what it looks like in game.
At the end of the post, you can find the source files for this revolute joint example attached.
Okay, a small description about revolute joint. It works with two bodies with one acting as the pivot while around revolves around it. With box2d we get the option to limiting the angle range in which the body revolves and also set the torque (how fast the body rotates about its origin) and motor speed (how fast the body rotates around the pivot).
Here is a snippet of the respective joint.
[sourcecode language=”java”]
public class RevoluteJoint {
RevoluteJointDef revoluteJointDef;
public RevoluteJoint(Body bodyA,Body bodyB,boolean collideConnected){
revoluteJointDef = new RevoluteJointDef();
CreateRevoluteJoint(bodyA,bodyB,collideConnected);
}
void CreateRevoluteJoint(Body bodyA,Body bodyB,boolean collideConnected){
revoluteJointDef.bodyA=bodyA;
revoluteJointDef.bodyB=bodyB;
revoluteJointDef.collideConnected=collideConnected;
}
public void SetAnchorA(float x,float y){
revoluteJointDef.localAnchorA.set(x,y);
}
public void SetAnchorB(float x,float y){
revoluteJointDef.localAnchorB.set(x,y);
}
public void SetAngleLimit(float min,float max){
revoluteJointDef.enableLimit=true;
revoluteJointDef.lowerAngle=min*MathUtils.degreesToRadians;
revoluteJointDef.upperAngle=max*MathUtils.degreesToRadians;
}
public void SetMotor(float torque,float speed){
revoluteJointDef.enableMotor=true;
revoluteJointDef.maxMotorTorque=torque;
revoluteJointDef.motorSpeed=speed*MathUtils.degreesToRadians;
}
public Joint CreateJoint(World world){
return world.createJoint(revoluteJointDef);
}
}
[/sourcecode]
Lets go through the above snippet. We first supply two box bodies which would form the revolute joint. Third argument (collideConnected) is to check if the two bodies associated with joint should be checked for collision.
SetAnchorA is to set the anchor point around which the revoluting body will rotate.
SetAnchorB is to set the other point where the second body will be positioned and will revolve around the pivot.
SetAngleLimit is to set the range in which the body should revolve around the pivot.
In SetMotor function we are setting the torque and motorSpeed for the joint. In our case we wanted the body to completely revolve around pivot every 1 second, so we give the speed of 360 (which is converted inside to radians as box2d expects the angles in radians).
Below is an image which (tries to) describes the revolute joint.
Below is a snippet to create a revolute joint using two bodies.
First a wrapper class to create box2d bodies.
[sourcecode language=”java”]
public class BoxBodyBuilder {
public static float WORLD_TO_BOX=0.01f;
public static float BOX_TO_WORLD=100f;
static float ConvertToBox(float x){
return x*WORLD_TO_BOX;
}
static float ConvertToWorld(float x){
return x*BOX_TO_WORLD;
}
public Body CreateCircleBody(World world,BodyType bodyType,float posx,float posy,
float radius){
BodyDef bodyDef = new BodyDef();
bodyDef.type = bodyType;
bodyDef.position.set(ConvertToBox(posx),ConvertToBox(posy));
bodyDef.angle=0;
Body body = world.createBody(bodyDef);
MakeCircleBody(body,radius,bodyType,1,1,0,0);
return body;
}
void MakeCircleBody(Body body,float radius,BodyDef.BodyType bodyType,
float density,float restitution,float angle,float friction){
FixtureDef fixtureDef=new FixtureDef();
fixtureDef.density=density;
fixtureDef.restitution=restitution;
fixtureDef.friction=friction;
fixtureDef.shape=new CircleShape();
fixtureDef.shape.setRadius(ConvertToBox(radius));
body.createFixture(fixtureDef);
fixtureDef.shape.dispose();
}
}
[/sourcecode]
In the above snippet we are creating a circle object. We are scaling the objects to ratio of 1:100. So if a world object is 50px wide then in box it would have a dimension of 0.5f. So while creating the body we convert the dimensions and location in box2d scale and in debugrenderer we scale the projection matrix by 100 to see the bodies in world dimensions.
Bodytype is to specify if a body is static, dynamic or kinematic. Our pivot will be static and other body will be dynamic.
Other properties are set to 1 or 0 but as for this example they were not that important.
Now the main code where we create the box2d bodies and revolute joint.
[sourcecode language=”java”]
//Creating the pivot and the rotating body
bodyFactory=new BoxBodyBuilder();
Body pivot=bodyFactory.CreateCircleBody(world, BodyType.StaticBody, 200, 200, 30);
Body spike=bodyFactory.CreateCircleBody(world, BodyType.DynamicBody, 200, 200, 20);
MakeJoint(); //the function below creates the joint
//Creating joint
void MakeJoint(){
//Using our custom class to create the revolute joint def
RevoluteJoint j=new RevoluteJoint(pivot,spike,false);
//Set Anchor A location
j.SetAnchorA(BoxBodyBuilder.ConvertToBox(0), BoxBodyBuilder.ConvertToBox(0));
//Set Anchor B location
j.SetAnchorB(BoxBodyBuilder.ConvertToBox(100), BoxBodyBuilder.ConvertToBox(0));
//Set revolution speed and torque
j.SetMotor(20, 360);
//This creates the joint
joint=j.CreateJoint(world);
}
[/sourcecode]
In the above snippet first we create the two box2d bodies which will form the revolute joint. Then we create the joint and set the pivot and other body apart by 100 px. Then we set the torque to 20 and motor speed to 360 degrees per second so it will complete one revolution per second.
Then all you need to do is call world.step in update function to update the box physics and the joint will work accordingly.
Here are the source files and the libgdx eclipse project. We have used debug renderer in the source provided.
|
|
If you have queries/suggestions, please post them in comments.
Thanks
Very clean – saved me some time – thanks