Get the full commented source code of

HTML5 Suika Watermelon Game

Talking about Actionscript 3, Box2D and Flash.

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.

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.

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.