Box2D 2.1a Tutorial – Part 2 (Joints)

Welcome to Part 2 of my Box2D tutorial series. In the last tutorial we looked at the very basics of creating a world and populating it with a box . While it was necessary to learn that first, it was not terribly exciting. In this tutorial topic, we will learn about joints, which will allow us to start creating some cool stuff!

Joints are actually relatively simple to construct and follow a similar creation processes as when we create bodies. The first step is to define a joint definition where we set various properties, such as the bodies it connects, range restrictions, max torque etc. Once that is done, we use the world to create a joint from this definition. Too easy right ;-)

There are in total eight different joints, each serving a different purpose in Box2D. We will have a look at all of them. As with the last tutorial, I am following the manual in Box2D closely, so for more detailed descriptions it is best to have a look at it.

Mouse Joint

The first joint that we will look at will be the mouse joint. The mouse joint simply allows us to click on, and manipulate the bodies in the world. This is useful for interacting with the Box2D world, so we will learn about it first.

The mouse joint is actually the hardest to set up since we have to write a lot more code for it to work compared to the other joints. Fortunately, the Test.as file in the TestBed folder under examples in the Box2D zip provides us with this code:

protected var _mouseJoint:b2MouseJoint;
protected var _input:Input;
protected var _mouseXWorldPhys:Number;
protected var _mouseYWorldPhys:Number;
protected var _mouseXWorld:Number;
protected var _mouseYWorld:Number;
protected var _mousePVec:b2Vec2 = new b2Vec2();

protected function update(e:Event):void
{
	var timeStep:Number = 1 / 30;
	var velocityIterations:int = 6;
	var positionIterations:int = 2;

	UpdateMouseWorld();
	MouseDestroy();
	MouseDrag();

	_world.Step(timeStep, velocityIterations, positionIterations);
	_world.ClearForces();
	_world.DrawDebugData();
	General.Input.update();
}

protected function GetBodyAtMouse(includeStatic:Boolean = false):b2Body
{
	_mousePVec.Set(_mouseXWorldPhys, _mouseYWorldPhys);
	var aabb:b2AABB = new b2AABB();
	aabb.lowerBound.Set(_mouseXWorldPhys - 0.001, _mouseYWorldPhys - 0.001);
	aabb.upperBound.Set(_mouseXWorldPhys + 0.001, _mouseYWorldPhys + 0.001);
	var body:b2Body = null;
	var fixture:b2Fixture;

	// Query the world for overlapping shapes.
	function GetBodyCallback(fixture:b2Fixture):Boolean
	{
	var shape:b2Shape = fixture.GetShape();
		if (fixture.GetBody().GetType() != b2Body.b2_staticBody || includeStatic)
		{
			var inside:Boolean = shape.TestPoint(fixture.GetBody().GetTransform(), _mousePVec);
			if (inside)
			{
				body = fixture.GetBody();
				return false;
			}
		}
		return true;
	}
	_world.QueryAABB(GetBodyCallback, aabb);
	return body;
}

protected function MouseDestroy():void
{
	if (!Input.mouseDown && Input.isKeyPressed(68/*D*/))
	{
		var body:b2Body = GetBodyAtMouse(true);

		if (body)
		{
			_world.DestroyBody(body);
			return;
		}
	}
}

protected function MouseDrag():void
{
	if (Input.mouseDown && !_mouseJoint)
	{
		var body:b2Body = GetBodyAtMouse();

		if (body)
		{
			var md:b2MouseJointDef = new b2MouseJointDef();
			md.bodyA = _world.GetGroundBody();
			md.bodyB = body;
			md.target.Set(_mouseXWorldPhys, _mouseYWorldPhys);
			md.collideConnected = true;
			md.maxForce = 300.0 * body.GetMass();
			_mouseJoint = _world.CreateJoint(md) as b2MouseJoint;
			body.SetAwake(true);
		}
	}

	if (!Input.mouseDown)
	{
		if (_mouseJoint)
		{
			_world.DestroyJoint(_mouseJoint);
			_mouseJoint = null;
		}
	}

	if (_mouseJoint)
	{
		var p2:b2Vec2 = new b2Vec2(_mouseXWorldPhys, _mouseYWorldPhys);
		_mouseJoint.SetTarget(p2);
	}
}

	protected function UpdateMouseWorld():void
	{
		_mouseXWorldPhys = (Input.mouseX) / PIXELS_TO_METRE;
		_mouseYWorldPhys = (Input.mouseY) / PIXELS_TO_METRE;

		_mouseXWorld = (Input.mouseX);
		_mouseYWorld = (Input.mouseY);
}

You are required to create an instance of the Input class since later on we call some static functions that rely on it being instantiated first. The original source code requires you to create a MovieClip that is attached to stage and pass it in as a reference. I did not really like this and would rather just pass in a reference to stage directly so I have modified the class a bit (see the source code file at the bottom).

public function MouseJointTutorial()
{
	addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
}

private function onAddedToStage(e:Event):void
{
	init();
	setup();
}

private function init():void
{
    //... other code. See end of blog for complete source code
    _input = new Input(stage);
    addEventListener(Event.ENTER_FRAME, update);
}

For this reason, all the code we write now will be triggered only once the class has been added to stage so that we don’t pass in a null reference to the Input class.

I won’t go through all the code, needless to say on each update frame it detects to see if the mouse is being pressed on a body, and if so, creates a mouse joint on it and applies a force to the body. It also cleans up after itself too avoid wasting memory.
So now you should be able to manipulate a box and see the physics engine at work!

Distance Joint

The next joint we will look at is the distance joint. It is pretty simple to create. All it does is maintain a distance between two bodies. For each of the two bodies we specify the anchor point in world coordinates. FYI wherever you see box1, box2 etc – those are dynamic bodies. _groundBody which I use later on is a static body.


var distanceJointDef:b2DistanceJointDef = new b2DistanceJointDef();
distanceJointDef.Initialize(box1, box2, box1.GetWorldCenter(), box2.GetWorldCenter());
_world.CreateJoint(distanceJointDef);

Rope Joint

Following on from the Distance Joint we have the Rope Joint. The Rope Joint is very similar to the distance joint. Both enforce a maximum distance between two bodies. The difference however is that there is no minimum distance that is enforced between the two bodies. This makes the joint suitable for using as a rope.

var ropeJointDef:b2RopeJointDef = new b2RopeJointDef();
ropeJointDef.bodyA = box1;
ropeJointDef.bodyB = box2;
ropeJointDef.localAnchorA = new b2Vec2(0,0);
ropeJointDef.localAnchorB = new b2Vec2(0,0);
ropeJointDef.maxLength = 6;
ropeJointDef.collideConnected = true;
_world.CreateJoint(ropeJointDef);

Revolute Joint

The next joint is the revolute joint. I find this one pretty useful. We attach this joint to two bodies. If one is a static body and the other is a dynamic body then the dynamic body will spin as if someone nailed a paper plate to a wall. Two dynamic bodies can also be attached together and will rotate around each other. There are various properties we can set such as limiting the range to revolve around. One thing you might like to do is add some friction to the joint. If you just create a bare bones revolute joint then if something causes it spin then it will never stop. By enabling the motor and setting a max torque to something like 1.0, then it will eventually come to a rest thus resembling friction.

var revoluteJointDef:b2RevoluteJointDef = new  b2RevoluteJointDef();
revoluteJointDef.Initialize(box1, _groundBody, box1.GetWorldCenter());

revoluteJointDef.maxMotorTorque = 1.0;
revoluteJointDef.enableMotor = true;

_world.CreateJoint(revoluteJointDef);

Prismatic Joint

The prismatic joint allows only one degree of freedom. For example, if we attached a dynamic body to a static body with a prismatic joint then we can slide it along an axis (similar to the moving levels in a platformer). If we attached a dynamic body to another dynamic body, then you will notice that both boxes rotate relative to each other.


var worldAxis:b2Vec2 = new b2Vec2(1.0, 0.0);

var prismaticJointDef:b2PrismaticJointDef = new b2PrismaticJointDef();
prismaticJointDef.Initialize(box1, _groundBody, box1.GetWorldCenter(), worldAxis);
prismaticJointDef.lowerTranslation = -5.0;
prismaticJointDef.upperTranslation = 2.5;
prismaticJointDef.enableLimit = true;
prismaticJointDef.maxMotorForce = 1.0;
prismaticJointDef.motorSpeed = 0.0;
prismaticJointDef.enableMotor = true;

_world.CreateJoint(prismaticJointDef);

Pulley Joint

Next up is the pulley joint. As the name suggests it is used for creating a pulley system. You can specify a ratio of how far one side changes compared to the other. The pulley does take a bit of tweaking to get it set up correctly for how you want it to function.


var anchor1:b2Vec2 = box1.GetWorldCenter();
var anchor2:b2Vec2 = box2.GetWorldCenter();

var groundAnchor1:b2Vec2 = new b2Vec2(anchor1.x, anchor1.y - (300 / PIXELS_TO_METRE)); var groundAnchor2:b2Vec2 = new b2Vec2(anchor2.x, anchor2.y - (300 / PIXELS_TO_METRE));

var ratio:Number = 1.0;

var pulleyJointDef:b2PulleyJointDef = new b2PulleyJointDef();
pulleyJointDef.Initialize(box1, box2, groundAnchor1, groundAnchor2, anchor1, anchor2, ratio);
pulleyJointDef.maxLengthA = 600 / PIXELS_TO_METRE;
pulleyJointDef.maxLengthB = 600 / PIXELS_TO_METRE;

_world.CreateJoint(pulleyJointDef);

Gear Joint

Gears are the next joint we will look at. A gear could be created by making a body in the shape of a gear and applying a motor, but a gear joint will be much more efficient and simpler to set up. Gear joints are created by using a mixture of either revolute or prismatic joints connected to a static body. As one body changes it subsequently affects the other body. Note, that in the initialization function the static body must be the first parameter .


var revoluteJointDef:b2RevoluteJointDef = new b2RevoluteJointDef();
revoluteJointDef.Initialize(_groundBody, box1, box1.GetWorldCenter());  //ground must be the first body
revoluteJointDef.lowerAngle = -0.5 * b2Settings.b2_pi; // -90 degrees
revoluteJointDef.upperAngle = 0.25 * b2Settings.b2_pi; // 45 degrees
revoluteJointDef.enableLimit = true;
revoluteJointDef.maxMotorTorque = 10.0;
revoluteJointDef.motorSpeed = 0.0;
revoluteJointDef.enableMotor = true;

var revoluteJoint:b2RevoluteJoint = _world.CreateJoint(revoluteJointDef) as b2RevoluteJoint;
var worldAxis:b2Vec2 = new b2Vec2(1.0, 0.0);

var prismaticJointDef:b2PrismaticJointDef = new b2PrismaticJointDef();
prismaticJointDef.Initialize(_groundBody, box2, box2.GetWorldCenter(), worldAxis);  //ground must be the first body
prismaticJointDef.lowerTranslation = -5.0;
prismaticJointDef.upperTranslation = 2.5;
prismaticJointDef.enableLimit = true;
prismaticJointDef.maxMotorForce = 1.0;
prismaticJointDef.motorSpeed = 0.0;
prismaticJointDef.enableMotor = true;

var prismaticJoint:b2PrismaticJoint = _world.CreateJoint(prismaticJointDef) as b2PrismaticJoint;

var gearJointDef:b2GearJointDef = new b2GearJointDef();

gearJointDef.joint1 = revoluteJoint;
gearJointDef.joint2 = prismaticJoint;
gearJointDef.bodyA = box1;
gearJointDef.bodyB = box2;
gearJointDef.ratio = 2.0 * b2Settings.b2_pi / (300 / PIXELS_TO_METRE);

_world.CreateJoint(gearJointDef);

Line Joint

If you are wanting to create a suspension for a model of a car then the line joint is what you will be after. It was created specifically for this purpose. It is like the prismatic joint but with the rotation restriction removed. For example, a wheel can slide along an axis (the shock absorber) while rotating. The spring portion of the shock absorber can be modelled by creating friction using the motor variables.


var worldAxis:b2Vec2 = new b2Vec2(0.0, 1.0);

var lineJointDef:b2LineJointDef = new b2LineJointDef();
/// Box2D source code:  A line joint. This joint provides one degree of freedom: translation along an axis fixed in body1. You can use a joint limit to restrict the range of motion and a joint motor to drive the motion or to model joint friction.
lineJointDef.Initialize(groundBody, box1, box1.GetWorldCenter(), worldAxis);
lineJointDef.lowerTranslation = -2.0;
lineJointDef.upperTranslation = 2.0;
lineJointDef.enableLimit = true;
lineJointDef.maxMotorForce = 200.0;
lineJointDef.motorSpeed = 10.0;
lineJointDef.enableMotor = true;

_world.CreateJoint(lineJointDef);

Weld Joint

Finally, we come to the last joint, the weld joint. The weld joint allows us to weld two bodies together. Pretty simple. If you are wanting to use it for setting up breakable structures then you should take note of the Box2D manual comment “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. Instead it is better to create breakable bodies starting with a single body with multiple fixtures. When the body breaks, you can destroy a fixture and recreate it on a new body.”


var weldJointDef:b2WeldJointDef = new b2WeldJointDef();
weldJointDef.Initialize(box1, box2, box1.GetWorldCenter());

 _world.CreateJoint(weldJointDef);

So that is the basics on creating different types of joints and their uses. You should now have learnt enough to start experimenting and making some cool worlds/contraptions. I have included the full source code files for creating each type of joint below. The next topic in this tutorial series will be custom shapes and textures. :)

Zipped project file here

  • Ben

    Nice tute Allan

  • Pingback: Box2D 2.1a Tutorial part 3. Custom shapes and textures | Allan Bishop's Developer Blog

  • http://twitter.com/yakovschatz Jacob Schatz

    I have to say that I send way too much time referencing this page.

  • Ivan

    Thanks for tutorial.
    But it’s hard to understand this all material first time.

  • Rick Walsh

    In this post you comment that the linejoint could be used to construct a suspension.

    How would you do this?

  • Anonymous

    Hi Rick, I have updated the code and example regarding the linejoint which should help make it clearer to understand (it wasn’t a terribly great example initially).

    So the first parameter that we pass into the initialize function is the body that determines the translation axis. So for a suspension system, the body will be the metal shock absorber itself. The second body will be the wheel which slides up and down this axis while rotating. Add in a motor to simulate friction and you will have a suspension system up and running.

    I think you could also achieve similar results using a prismatic joint and a revolute joint.

  • Anonymous

    haha thanks :)

  • Anonymous

    Yeah Box2D can be a bit tricky, but after a while it becomes easier. If there is anything you are struggling with, or feel needs to be explained better, let me know.

  • Ihor

    Hi! I am new to box2D but im trying to use a Line joint instead of Prismatic + Revolute ones. But get an error

    Description Resource Path Location Type
    1046: Type was not found or was not a compile-time constant: b2LineJointDef. .as //src/// line 75 Flex Problem

    I use adobe flash builder. Considering that i cant import Box2D.Dynamics.Joints.b2LineJointDef i wonder if i got the right sources. I also have a warning:

    Description Resource Path Location Type
    Design mode could not load FlexWorld.swc. It may be incompatible with this SDK, or invalid. (DesignAssetLoader.CompleteTimeout) .mxml //src Unknown Problem

    It seems i got an old swc file huh? If so can you help with finding latest one? :O

    p.s. sry for my english

  • Padilla Esteban

    Excellent tutorials really helped me understand box2d.
    Thanks a lot.
    EPadilla

  • Padilla Esteban

    Excellent tutorials really helped me understand box2d.
    Thanks a lot.
    EPadilla

  • Anonymous

    Unfortunatly I am not too familiar with FlashBuilder. Are you able to compile any of the Box2D code or is it just the LineJoint causing the problem? Also, are you building this as a Flex or pure AS3 project? The latest Box2D 2.1a by BorisTheBrave is here
    https://sourceforge.net/projects/box2dflash/files/box2dflash/Box2DFlashAS3_2.1a/Box2DFlashAS3%202.1a.zip/download

  • jp

    Very good post. I got a lot of help from this. Thanks.

  • Zerchan

    My own version of GetBodyAtMouse:

    private function GetBodyAtMouse(includeStatic:Boolean=false):b2Body {
    var realXmouse = _mouseXWorldPhys;
    var realYmouse = _mouseYWorldPhys;
    _mousePVec.Set(realXmouse, realYmouse);
    var body:b2Body = null;
    for(var currentBody:b2Body = world.GetBodyList(); currentBody; currentBody = currentBody.GetNext()){
    if(currentBody.GetType() != b2Body.b2_staticBody){
    var inside:Boolean = currentBody.GetFixtureList().GetShape().TestPoint(currentBody.GetTransform(),_mousePVec);
    if(inside){
    body = currentBody;
    break;
    }
    }
    }
    return body;
    }

  • http://profiles.google.com/jorgeenriquezm Jorge Enriquez

    How can I make a bidirectional prismatic joint? Imagine a platform movin horizontally from A -> B -> A looping all the time… It´s driving me crazy…

  • http://profiles.google.com/jorgeenriquezm Jorge Enriquez

    Well, I solved it with setLineraVelocity() and “manual” limits :)

  • http://profiles.google.com/afraa89 Afra Fotouhi

    Why is my box slacking when following my mouse? It is much slower and cant keep up with my mouse.. Your box follows so fast

  • Anonymous

    Sorry, your comment got lost in all my emails :S Glad to see you solved it though :)

  • Anonymous

    When you say slow, is it sort of not smooth? If so, check to make sure you are publishing your SWF at 60fps

  • uberTof

    The knowledge you’re passing along is priceless!
    Thanks so much for these clear and practical examples of Box2D.

  • eternity

    superb!! 

  • Rakshathkashyap

    hi,
    for some reason my box 2d has no b2fixture class.
    i am not able to run my code because of this.
    what do i do??

  • Spaceandrace

    Awsomw – very very very descriptive! Thanks for you hard work!

  • Lucas Reher

    hi, i know this tutorial is old but i have a question, in the beggining when you teach us hot to create the mouse joint, its kind oof unclear where to put the code, or if i have to make a new class. I know u said that we had to use the Test.as but it isfull of other stuff and im kind of coounfused… Sorry for my noobness but im kind of new to box2D :) Please Help Lucas

  • Anonymous

    Hi Lucas, the code goes in your main class where you have all your Box2D set up (where the world is created). Have a look at the full source code for this project. It has everything already set up so that should help you. Let me know if you still are having trouble :)

    http://blog.allanbishop.com/wp-content/uploads/2010/09/Box2DTutorialJoints.zip

  • Lucas Reher

    Thank you so much, I only have one question though, in the FLA, usually, to be able to acces the stage and properties like addChild and addEventListener, i have to create a main class and put in the “Class” in the right side of the FLA, but you dont, how can you acces the things on the FLA such as buttons and texts from the JointTutorial.as if it isnt liked to the stage? Cause ive been trying to make a main class and acces the MouseJoint Tutorial, but it wont let me unless it extends the MouseJointTutorial.as, the problem is if i extend MouseJointTutorial, i dont have acces to stage and addEventListener (which i need to make a wheel rotate).
    Thx Lucas

  • Anonymous

    To access properties like addChild a class must be added to the stage. So in my example, on the first frame of the timeline I create and add the Joint Tutorial class. Inside that class I then a specific tutorial like the MouseJointTutorial and add it to the Joint Tutorial class so it too is added to the stage.

    Alternatively (and generally better practise), is to create the Document class like you are wanting to do. The document class must extend a MovieClip, which MouseJointTutorial does, so you can use it as a document class (just make sure to clear the code on the main time line first). If you want to add code to access the stage make sure it occurs after the onAddedToStage event is fired so that we know we have access to the stage. Let me know how that goes :)

  • Anonymous

    Sorry for the huge delay in replying, didn’t notice your comment :/ You should have that class. Redownload it and make sure you grab the latest version from here http://www.box2dflash.org/download and get the 2.1a version.

  • Harilal K M

    hi,
    I am new to Box2d . I tried to create a rope using box2d following Emanuele Feronato blog.
    I am able to create it in box2d but the rope shows elasticity . I tried to change joints referncing this post.
    This is my code.. Will you please help me to find what went wrong?

  • Harilal K M

    i can’t add the link :(

  • Harilal K M

    sorry forget to add the link

  • Anonymous

    You should be able to post a link? Just that it will be flagged for moderation first and only displayed when it gets approved.

  • Anonymous

    Creating non elastic ropes are notoriously hard in Box2D (from first hand experience). Without seeing your code there are a few things you should try. 

    For starters I have found distance joints better than revolute joints for reducing elasticity and preventing ropes from glitching.

    Additionally, if you increase the the velocity and position iterations in the world.Step() function then that should help too (at the expense of performance).

    Lastly, the weight of the rope and the amount of segments has an effect. Let me know if that helps.

  • Duccloud

    Thanks! You save my day :D

  • Harilal K M

    hi allan i have already posted the link to my soyrce and awaiting your reply

  • Anonymous

    I can’t see your link?

  • Harilal K M
  • Harilal K M

    i have posted my link . This is my mail id harilalmkn@gmail.com 

  • Anonymous

    Ok so I improved it a bit. First, for games, I like a nice frame rate so bumped it up from 24fps to 60fps in the .FLA. Then, replace your existing relevant line of code with world.Step(1/60, 30, 20);

  • http://www.facebook.com/profile.php?id=100002331241781 Harilal Kreata

    Thanks alan it works great. If you don’t mind , can you tell me what’s real problem? Just curious and just wanted know more about it.

  • Anonymous

    Basically the solver in Box2D (the thing that actually calculates all the physics and figures out the collisions) is performed a variable amount of times depending on what values you type into the Step function. The more times it runs, the more accurate the simulation, but at the expense of performance.

  • Pingback: Gordon Wacker

  • Tomoy_9

    Allan this is excellent but i am having a problem, how can i dow to make a body connection with two others and then make them 3 to move together following de mouse position and colliding with dynamics bodys. Mi idea is to make a game where balls follow from the sky and you collect the with a kind of cup (the 3 bodys).
    Thanks in advance

    Tomas

  • Anonymous

    Hi Tomas,

    So do you mean you want the bodies to automatically join when they collide with each other? That being the case, see my tutorials: 
    http://blog.allanbishop.com/box2d-2-1a-tutorial-%E2%80%93-part-4-collision-detection/ 
    and
     http://blog.allanbishop.com/box-2d-2-1a-tutorial-part-4-extended-contact-point/

    You need to setup a listener for detecting the collisions so you can then create a joint when that happens. If you want to create a joint at the exact point they collided then follow the second tutorial link. 

    Then as long as one of the bodies is following the mouse, the others will be pulled along too.

  • Jazdaone

    Short article but really, really helpful.
    Thank u Allan

  • Edgar

     Hey Allan,

    Have you ever tried converting the mousejoint to touch (for mobile) instead of mouse? Im trying to achieve this based on your mouseJointTutorial class, but can’t get it to work. Any examples/snippets/resources would be awesome..

    Greets Edgar

  • allanbishop

    Hi Edgar,

    I have converted the mousejoint to HaXe and used it on mobile devices successfully. 

    With HaXe, I have a MultiTouchController class that I made that listens for TouchEvents. On each TouchEvent I create a Finger class the encapsulates the location that the screen was touched at. It then registers for  TouchMove and TouchEnd events.

    Then in my input system I create an instance of this MultiTouchController and on every enter frame inspect the touchController and check to see if a finger is down.

    When a finger is down I get the initial location of the touch from it and call the getBodyAtMousePosition() (although I have changed it to accept the location point as a parameter). I use these values instead of the _mouseXWorldPhys etc. Then, if a body is detected, I use the existing code above to create the joint.

    In the input system I also then listen for if a finger is dragged or released. Then if a finger is dragged I change the joint setTarget based on the current finger location as in the code above. Of course this means that you need a way of linking a joint to a particular finger…

    Hopefully that is enough to get you started. I will be soon working on a game tutorial in HaXe that has all the code for the above and will be easily portable to AS3 too

  • Simon

    Absolutely awesome tutorial !

  • J040p3d20

    Greatest intro to joints

  • Pixrael

    Thanks a lot for these tuts.