Creating a Box2D mouse joint
The name b2MouseJoint can be a little confusing. At first we might
think it’s a joint meant to be only used with the mouse. Well of course
we can implement easily drag functionality with this joint but what this
joint really does has virtually nothing to do with mouse interaction.
The b2MouseJoint allows you to set a destination position for a b2Body, and this b2Body will try to get there while still interacting with the Box2D world and be subject to any forces that apply. That means that if the path of that b2Body is going through a wall then the b2Body will be stuck behind the wall and won’t reach it’s destination. If there are other b2Body on the dragged b2Body path then this b2Body will try to push them aside. The reason this has nothing to do with a mouse is because setting the b2Body destination is done simply by passing a pair of value which could easily be done by code or by pressing keys on your keyboard. Of course passing as value the mouse position makes the b2Body try to follow the mouse. I guess my point here is, don’t limit this joint to only mouse interaction since it can do so much more.
There’s an important point to notice here, b2body have a method called SetPosition() with which you can easily set the position of your b2Body. So why can’t we use that to drag our b2Body? The SetPosition() method sets arbitrary the position of the b2Body regardless of the box2D world interaction, forces, and other b2Body. For that reason using SetPosition() can produce unwanted results like setting a dynamic b2Body inside a static b2Body. Box2D won’t like that and will probably stop handling your b2Body correctly or even in some cases crash the Flash Player. So use the SetPosition() method wisely and if what you really want if a dragging around a b2Body while still having this body interacting with the Box2D world just like any other b2Body, then b2MouseJoint is the joint you need.
Just a simple example now. A bunch of b2Body, click and hold the mouse and to drag a body, release the mouse and to release the b2Body:
The relevant code of course:
mousedef.bodyA = world.GetGroundBody();
mousedef.bodyB = currentbody;
var bodypos:b2Vec2 = currentbody.GetWorldCenter();
mousedef.collideConnected = true;
mousedef.maxForce = 300 * currentbody.GetMass();
mousejoint = world.CreateJoint(mousedef) as b2MouseJoint;
The first b2Body must be one of reference like a ground that you create or like here the convenient world.GetGroundBody() method. The second b2Body is the one you want to drag around. Then we set the b2Body starting position by simply calling currentbody.GetWorldCenter() and passing it as starting position. We want the b2Body to still collide with the ground so we set this to true. Finally we apply a maxForce which here is pretty strong. You want to set this strong enough so the b2mouseJoint can move around heavy objects easily. The smaller the value, the harder it will be for the b2Body to reach its destination which can create interesting effects of course. In the example I of course destroy the b2MouseJoint when you release the mouse.
Finally in the update method we add this after the world.step():
We simply pass the value pair of the current mouse position which sets the destination for our b2Body. We could as easily substitute this by a value pair controlled by the arrow key on your keyboard or even by random values generated by code.
To prove my earlier point here is an example where we use the b2MouseJoint without a mouse! Use your arrow keys on your keyboard to move the crosshair and watch the b2Body follow it:
Another really useful joint (they all are anyway) is the b2RevoluteJoint. Let see that now.