Box2D joints: Prismatic Joints

Time to learn something about Box2D prismatic joints.

A prismatic joint provides one degree of freedom: translation along an axis fixed relative to the first body. Relative rotation is prevented.

In other words, prismatic joints can be used to represent pistons and other sliding objects.

In this tutorial I am going to show how to create a prismatic joint, and later I’ll show you some real-world examples.

The script is the one you can find at Box2D joints: Revolute Joint – Building motors with some modifications in order to create prismatic joints.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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 prismatic_joint extends Sprite {
		var mouseJoint:b2MouseJoint;
		var mousePVec:b2Vec2 = new b2Vec2();
		var bd:b2BodyDef;
		var the_box:b2PolygonDef = new b2PolygonDef();
		var the_prism_joint:b2PrismaticJointDef = new b2PrismaticJointDef();
		public function prismatic_joint() {
			// 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);
			// box for the prismatic joint
			the_box.SetAsBox(0.5,0.5);
			the_box.density=0.01;
			the_box.friction=1;
			the_box.restitution=0.1;
			bd = new b2BodyDef();
			bd.position.Set(8.5,5);
			var prism_box:b2Body=m_world.CreateBody(bd);
			prism_box.CreateShape(the_box);
			prism_box.SetMassFromShapes();
			// prismatic joint
			the_prism_joint.Initialize(m_world.GetGroundBody(), prism_box, new b2Vec2(8.5,5),new b2Vec2(1,0));
			the_prism_joint.lowerTranslation=-6;
			the_prism_joint.upperTranslation=6
			the_prism_joint.enableLimit=true;
			the_prism_joint.maxMotorForce=100;
			the_prism_joint.motorSpeed=4.0;
			the_prism_joint.enableMotor=true;
			var joint_added:b2PrismaticJoint=m_world.CreateJoint(the_prism_joint) as b2PrismaticJoint;
			// 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();
			if (body) {
				var mouseJointDef:b2MouseJointDef=new b2MouseJointDef  ;
				mouseJointDef.body1=m_world.GetGroundBody();
				mouseJointDef.body2=body;
				mouseJointDef.target.Set(mouseX/30, mouseY/30);
				mouseJointDef.maxForce=30000;
				mouseJointDef.timeStep=m_timeStep;
				mouseJoint=m_world.CreateJoint(mouseJointDef) as b2MouseJoint;
			}
		}
		public function destroyMouse(evt:MouseEvent):void {
			if (mouseJoint) {
				m_world.DestroyJoint(mouseJoint);
				mouseJoint=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()==false||includeStatic) {
					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);
			if (mouseJoint) {
				var mouseXWorldPhys=mouseX/30;
				var mouseYWorldPhys=mouseY/30;
				var p2:b2Vec2=new b2Vec2(mouseXWorldPhys,mouseYWorldPhys);
				mouseJoint.SetTarget(p2);
			}
		}
		public var m_world:b2World;
		public var m_iterations:int=10;
		public var m_timeStep:Number=1.0/30.0;
	}
}

Line 15: Declaring the_prism_joint variable, b2PrismaticJointDef type. This is how I define prismatic joints.

Line 49: Initializing the prismatic joint. This is the most difficult and unclear part of the process. The first two parameters represent the objects tied by the joint, the third one is the point where to tie the joint and the fourth is a vector representing the movement allowed. In this case, being an horizontal vector, the movement allowed is horizontal

Notice about this 4th parameter that values inside b2Vec2() cannot be greater than 1 or you may experience strange results.

All in all, there is no need to write (100,0) to represent an horizontal vector, when you can just use (1,0)

Lines 50-51: upperTranslation and lowerTranslation represent the upper and lower translation limits, in meters. To avoid strange results, try to keep

lowerTranslation <= 0 <= upperTranslation

Line 52: Enabling the limits for upper and lower translations. If you don't set enableLimit to true, limits won't be considered.

Lines 53-55: Adding a simple motor. For a brief introduction about motors, refer to Box2D joints: Revolute Joint - Building motors.

Line 56: Adding the joint.

And this is the result. Try to drag the box

And this is the source code ready to be downloaded.

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (9 votes, average: 4.56 out of 5)
Loading ... Loading ...
Flash Templates provided by Template Monster are pre-made web design products developed using Flash technology.
They can be easily customized to meet the unique requirements of your project.
Be my fan on Facebook and follow me on Twitter! Exclusive content for my Facebook fans and Twitter followers

This post has 7 comments

  1. Gawd

    on February 3, 2009 at 4:52 pm

    First! :D

  2. Xavi

    on February 3, 2009 at 7:15 pm

    noooooooo
    !first
    :_(

  3. RedRail

    on February 3, 2009 at 7:24 pm

    In unrelated news: ‘My works’ page is still empty. Seems like a good place to showcase your games(I don’t see them listed anywhere else on the site).

    Now on topic, I’m sure those will be usefull when I’ll finally start makeing something box2d

  4. Ben

    on February 3, 2009 at 10:55 pm

    Is there a way to have it “spring” back with force instead of just a constant speed? Would that be the motor settings?

  5. LunaDrift

    on February 4, 2009 at 2:43 am

    Enjoyed reading your blog in general… I forget what bought me here in the first place… searching for something or other.

    Best of luck with your games :)

  6. Box2D breakout prototype : Emanuele Feronato

    on February 4, 2009 at 2:28 pm

    [...] are hanging by distance joints attached to the body Ground, the paddle is fixed on the x axis by a prismatic joint attached also to the [...]

  7. Dinkyfish

    on November 22, 2011 at 12:37 am

    Just wanted to stop by and say a massive thank you for all your tutorials. You’ve clearly put a huge amount of work into them and they’ve helped me out on many occasions. Keep up the good work!