Creating a sling with Box2D using joints

This is an example about the creation of a sling using joints and motors.

Click the mouse to break the joint and release the bullet. Try to hit the stack of boxes.

I used a distance joint, a revolute joint and a motor. The code does not need to be commented because there is nothing new, just look how I destroy the joint to launch the bullet at lines 122-123

This is the source:

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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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 sling extends Sprite {
		var mouseJoint:b2MouseJoint;
		var mousePVec:b2Vec2=new b2Vec2;
		var bd:b2BodyDef;
		var the_box:b2PolygonDef=new b2PolygonDef;
		var the_pivot:b2CircleDef=new b2CircleDef;
		var the_rev_joint:b2RevoluteJointDef=new b2RevoluteJointDef;
		var the_dist_joint:b2DistanceJointDef = new b2DistanceJointDef();
		var dest_joint:b2DistanceJoint;
		public function sling() {
			// 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);
			// the ground
			var final_body:b2Body;
			var the_body:b2BodyDef;
			var the_box:b2PolygonDef;
			the_body = new b2BodyDef();
			the_body.position.Set(8.5, 13);
			the_box = new b2PolygonDef();
			the_box.SetAsBox(8.5, 0.5);
			the_box.friction=0.3;
			the_box.density=0;
			final_body=m_world.CreateBody(the_body);
			final_body.CreateShape(the_box);
			final_body.SetMassFromShapes();
			// some boxes
			for (var i:int=0; i<7; i++) {
				the_body = new b2BodyDef();
				the_body.position.Set(12, 12-i);
				the_box = new b2PolygonDef();
				the_box.SetAsBox(0.5,0.5);
				the_box.friction=0.3;
				the_box.density=0.5;
				final_body=m_world.CreateBody(the_body);
				final_body.CreateShape(the_box);
				final_body.SetMassFromShapes();
			}
			// pivot for revolute joint
			the_pivot.radius=0.2;
			the_pivot.density=0;
			bd=new b2BodyDef  ;
			bd.position.Set(3,6.5);
			var rev_joint:b2Body=m_world.CreateBody(bd);
			rev_joint.CreateShape(the_pivot);
			rev_joint.SetMassFromShapes();
			// box for the revolute joint
			the_box.SetAsBox(2,0.1);
			the_box.density=0.01;
			the_box.friction=1;
			the_box.restitution=0.1;
			bd=new b2BodyDef  ;
			bd.position.Set(3,6.5);
			var rev_box:b2Body=m_world.CreateBody(bd);
			rev_box.CreateShape(the_box);
			rev_box.SetMassFromShapes();
			// revolute joint
			the_rev_joint.Initialize(rev_joint,rev_box,new b2Vec2(3,6.5));
			the_rev_joint.enableMotor=true;
			the_rev_joint.motorSpeed=10;
			the_rev_joint.maxMotorTorque=1000;
			var joint_added:b2RevoluteJoint=m_world.CreateJoint(the_rev_joint) as b2RevoluteJoint;
			// bullet
			the_box.SetAsBox(0.2,0.2);
			the_box.density=1.0;
			the_box.friction=0.4;
			the_box.restitution=0.1;
			bd = new b2BodyDef();
			bd.position.Set(2, 5);
			var bullet:b2Body=m_world.CreateBody(bd);
			bullet.CreateShape(the_box);
			bullet.SetMassFromShapes();
			// distance joint
			the_dist_joint.Initialize(bullet, rev_box, new b2Vec2(2,5),new b2Vec2(1,6.5));
			the_dist_joint.collideConnected=true;
			dest_joint=m_world.CreateJoint(the_dist_joint) as b2DistanceJoint;
			// 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 {
			m_world.DestroyJoint(dest_joint);
			dest_joint=null;
			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;
	}
}

Download the source code.

How would you turn it into a game?

Rate this post: 1 Star2 Stars3 Stars4 Stars5 Stars (6 votes, average: 3.67 out of 5)
Loading ... Loading ...
If you found this post useful, please consider a small donation.
» 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.

15 Responses

  1. Prankard says:

    Might be an interesting concept for a game you have there :)

  2. Amazing job Emanuele!

    More one nice example of Box2D!

  3. Gonzalo says:

    There is a bug with dragging. Try dragging the ball and then lines get weird.

  4. The function destroyMouse seens bugged :S

    i use like this:
    public function destroyMouse(evt:MouseEvent):void
    {
    if (mouseJoint)
    {
    mundo.DestroyJoint(mouseJoint);
    mouseJoint=null;
    }
    }

  5. Shival says:

    Great and really interesting.

  6. Something is wrong there… =X

  7. Gawd says:

    You should have had it rotating the other direction. Would be easier to use.

  8. @Gawd

    Yeah, i try to change this is this code, but i encouter this problem:

    How change de rotation? Simple change the value to negative right?
    the_rev_joint.motorSpeed=-10;
    the_rev_joint.maxMotorTorque=-1000;

    NO! This not work :(
    hahah

  9. robert says:

    hey i found a glitch
    once the bullet is released you can pick it up
    not a glitch
    but if you click about 1in up from the edge of the catapult it creats a piont and then the bullet goes crazy

  10. VideoGuy says:

    I just tried this tutorial within the web page, and I got an ActionScript error alert.

    TypeError: Error #1009: Cannot access a property or method of a null object reference.
    at Box2D.Dynamics::b2World/DestroyJoint()
    at sling/destroyMouse()

    I don’t know that much about Box2D, or if it’s even important, but I thought you might want to know. It occurs when I click on the bullet, drag it, and then release it.

  11. Joshua Barnett says:

    Bruno Mikoski leave the torque alone its only the speed that needs to be changed to a negative.

    Also the stack falls over on its own if you leave it alone any ideas how to fix this problem. I’ve tried adjusting the friction and density with no lucky anyone?

  12. supermaggel says:

    the sling initially works, but then it all gets buggy as hell :)

  13. [...] same script we saw at Box2D joints: Distance Joint with some modifications and the concept saw at Creating a sling with Box2D using joints when we must remove the [...]

  14. Dream@Night says:

    yeah !there is a bug !But ,I think you have solved it ! haha
    for other vistors ,I’ll add some codes to solve it !

    public function destroyMouse(evt:MouseEvent):void {
    if (dest_joint) {
    m_world.DestroyJoint(dest_joint);
    }
    dest_joint=null;
    if (mouseJoint) {
    m_world.DestroyJoint(mouseJoint);
    mouseJoint=null;
    }

Leave a Reply