Talking about Actionscript 3, Box2D and Flash.
In most Box2D projects you can see how to render bodies or attach objects to them, but I couldn’t see any tutorial about rendering joints.
If you look at the classic rendering loop it’s something like this one
for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
if (bb.m_userData is Sprite) {
bb.m_userData.x = bb.GetPosition().x;
bb.m_userData.y = bb.GetPosition().y;
bb.m_userData.rotation = bb.GetAngle() * (180/Math.PI);
}
}
but as you can see, it only renders bodies.
The following script is the same you can find at Simulating a hook with Box2D but I will render the joints with lines.
package {
import flash.display.Sprite;
import flash.events.Event;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
import flash.events.MouseEvent;
public class distance_joint extends Sprite {
var mouseJoint:b2MouseJoint;
var mousePVec:b2Vec2 = new b2Vec2();
var bd:b2BodyDef;
var the_circle:b2CircleDef = new b2CircleDef();
var circle:b2Body;
var the_box:b2PolygonDef = new b2PolygonDef();
var the_joint:b2DistanceJointDef = new b2DistanceJointDef();
var joint:b2DistanceJoint;
//
public var m_world:b2World;
public var m_iterations:int=10;
public var m_timeStep:Number=1.0/30.0;
//
var my_canvas:Sprite = new Sprite();
public function distance_joint() {
addChild(my_canvas);
// world setup
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);
var gravity:b2Vec2=new b2Vec2(0.0,10.0);
var doSleep:Boolean=true;
m_world=new b2World(worldAABB,gravity,doSleep);
// debug draw
var m_sprite:Sprite;
m_sprite = new Sprite();
addChild(m_sprite);
var dbgDraw:b2DebugDraw = new b2DebugDraw();
var dbgSprite:Sprite = new Sprite();
m_sprite.addChild(dbgSprite);
dbgDraw.m_sprite=m_sprite;
dbgDraw.m_drawScale=30;
dbgDraw.m_alpha=1;
dbgDraw.m_fillAlpha=0.5;
dbgDraw.m_lineThickness=1;
dbgDraw.m_drawFlags=b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit;
m_world.SetDebugDraw(dbgDraw);
// ground
the_box.SetAsBox(9,0.5);
the_box.density=0;
the_box.friction=0.4;
the_box.restitution=0.1;
bd = new b2BodyDef();
bd.position.Set(8.5, 13);
var ground:b2Body=m_world.CreateBody(bd);
ground.CreateShape(the_box);
ground.SetMassFromShapes();
// roof
the_box.SetAsBox(9,0.5);
the_box.density=0;
the_box.friction=0.4;
the_box.restitution=0.1;
bd = new b2BodyDef();
bd.position.Set(8.5, 0);
var roof:b2Body=m_world.CreateBody(bd);
roof.CreateShape(the_box);
roof.SetMassFromShapes();
// circle
the_circle.radius=2;
the_circle.density=1.0;
the_circle.friction=0.4;
the_circle.restitution=0.3;
bd = new b2BodyDef();
bd.position.Set(6, 2);
circle=m_world.CreateBody(bd);
circle.CreateShape(the_circle);
circle.SetMassFromShapes();
// square
the_box.SetAsBox(1.5,1.5);
the_box.density=1.0;
the_box.friction=0.4;
the_box.restitution=0.1;
bd = new b2BodyDef();
bd.position.Set(2, 2);
var box:b2Body=m_world.CreateBody(bd);
box.CreateShape(the_box);
box.SetMassFromShapes();
// listeners
stage.addEventListener(MouseEvent.MOUSE_DOWN, createMouse);
stage.addEventListener(MouseEvent.MOUSE_UP, destroyMouse);
addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
}
public function createMouse(evt:MouseEvent):void {
var body:b2Body=GetBodyAtMouse(true);
if (body) {
the_joint.Initialize(circle, body, circle.GetWorldCenter(),new b2Vec2(mouseX/30,mouseY/30));
the_joint.collideConnected=true;
joint=m_world.CreateJoint(the_joint) as b2DistanceJoint;
}
}
public function destroyMouse(evt:MouseEvent):void {
if (joint) {
m_world.DestroyJoint(joint);
joint=null;
}
}
public function GetBodyAtMouse(includeStatic:Boolean=false):b2Body {
var mouseXWorldPhys = (mouseX)/30;
var mouseYWorldPhys = (mouseY)/30;
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 k_maxCount:int=10;
var shapes:Array = new Array();
var count:int=m_world.Query(aabb,shapes,k_maxCount);
var body:b2Body=null;
for (var i:int = 0; i < count; ++i) {
if (shapes[i].GetBody().IsStatic()) {
var tShape:b2Shape=shapes[i] as b2Shape;
var inside:Boolean=tShape.TestPoint(tShape.GetBody().GetXForm(),mousePVec);
if (inside) {
body=tShape.GetBody();
break;
}
}
}
return body;
}
public function Update(e:Event):void {
m_world.Step(m_timeStep, m_iterations);
my_canvas.graphics.clear();
my_canvas.graphics.lineStyle(4,0x000000,1);
for (var j:b2Joint=m_world.GetJointList(); j; j=j.GetNext()) {
my_canvas.graphics.moveTo(j.GetAnchor1().x*30,j.GetAnchor1().y*30);
my_canvas.graphics.lineTo(j.GetAnchor2().x*30,j.GetAnchor2().y*30);
}
}
}
}
The key is in the loop at lines 134-137 and its GetJointList()
function that gets the world joint list. With the returned joint, using GetNext()
I get the next joint in the world list. A NULL
joint indicates the end of the list.
Then, GetAnchor1
and GetAnchor2
return me the anchor point of both bodies linked by the joint in world coordinates.
And that's it... that easy...
Click on a static object (green) to create a joint on the fly and have it rendered
No need to include the source code, just replace the script at Box2D joints: Distance Joint with this one.
Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.