GRAVITY SPHERE

15
Oct
2012

This demo here shows a Gravity Sphere. Yep, I gave it this weird name ;). Anyways what happens here is that when any body comes within a certain range of the sphere (circle), it gets attracted towards it.

What I have done:

1) Create a body with two fixtures and one of the fixtures with higher radius is made a sensor. This will be the perimeter which when breached will pull the particular body towards the sphere. Also the world gravity is set to ZERO.

		var world = new b2World(new b2Vec2(0,0), true);
        
		var bodyDef = new b2BodyDef;
		bodyDef.type = b2Body.b2_staticBody;
        bodyDef.position.Set(10,7);
		bodyDef.userData = 'CIRCLE';
        
		//CREATING A CIRCLE WITH MULTIPLE(2) FIXTURES -- ONE OF THEM WILL BE A SENSOR
        
        //CIRCLE -- MAIN BODY FIXTURE
		var fixDef = new b2FixtureDef;		
		fixDef.density = 10.0;
		fixDef.friction = 0.5;
		fixDef.restitution = .5;
		fixDef.shape = new b2CircleShape(2);
		
		//CIRCLE -- SENSOR FIXTURE
		var fixDef2 = new b2FixtureDef;
		fixDef2.shape = new b2CircleShape(6);
		fixDef2.shape.SetLocalPosition(new b2Vec2(0 ,0));
		fixDef2.density = 0;
		fixDef2.isSensor = true; // SENSOR SET TO TRUE -- Fixture "fixDef2" is a SENSOR
		  
        var wheel = world.CreateBody(bodyDef);
		wheel.CreateFixture(fixDef);
		wheel.CreateFixture(fixDef2);

2) Now we need to detect when the body breaches the perimeter. We can use contact listeners provided by Box2dWeb. After we detect which body enters the perimeter, we will store it in an array. We will remove the body from the array when it leaves the perimeter. Here is the code snippet for it.
var pull = []; //ARRAY Storing the BODY
var listener = new Box2D.Dynamics.b2ContactListener;
listener.BeginContact = function(contact) {
	fxA=contact.GetFixtureA(); // 1st COLLISION FIXTURE
	fxB=contact.GetFixtureB(); // 2nd COLLISION FIXTURE
	sA=fxA.IsSensor(); // Will store whether 1st fixture is a sensor or not (true or false)
	sB=fxB.IsSensor(); // Will store whether 2nd fixture is a sensor or not (true or false)
	if((sA && !sB) || (sB && !sA))	{ // Will go on further iff Fixture A or B not both are sensors.
		if(sA)	{
			var bodyB = fxB.GetBody();
			pull.push(bodyB);
		}
		else	{
			var bodyA = fxA.GetBody();
			pull.push(bodyA);
		}
	}
}

listener.EndContact = function(contact) {
	fxA=contact.GetFixtureA(); // 1st COLLISION FIXTURE
	fxB=contact.GetFixtureB(); // 2nd COLLISION FIXTURE
	sA=fxA.IsSensor(); // Will store whether 1st fixture is a sensor or not (true or false)
	sB=fxB.IsSensor(); // Will store whether 2nd fixture is a sensor or not (true or false)
	if((sA && !sB) || (sB && !sA))	{ // Will go on further iff Fixture A or B NOT both are sensors.
		if(sA)	{
			var bodyB = fxB.GetBody();
			var index = pull.indexOf(bodyB); // Stores the index of the body to be REMOVED
			pull.splice(index,1); // REMOVES the body at that index
		}
		else	{
			var bodyA = fxA.GetBody();
			var index = pull.indexOf(bodyA); // Stores the index of the body to be REMOVED
			pull.splice(index,1); // REMOVES the body at that index
		}
	}
}

Also don't forget to add this line in the update().
world.SetContactListener(listener);

3) Now in update() add the following code.
			for(i=0; i < pull.length; i++)	{
				var c1 = pull[i].GetWorldCenter();
				var c2 = wheel.GetWorldCenter();
				var vec = new b2Vec2();
				vec.x = c2.x - c1.x;
				vec.y = c2.y - c1.y;
				var mag = Math.sqrt(((vec.x*vec.x)+(vec.y*vec.y)));
				vec.x = vec.x / mag;
				vec.y = vec.y / mag;
				var force = new b2Vec2();
				force.x = 200 * vec.x;
				force.y = 200 * vec.y;
				pull[i].ApplyForce(force, pull[i].GetWorldCenter());
				pull[i].SetAngularDamping(3);
			}

We know that any Vector is product of Magnitude and Direction (direction is a unit vector meaning it has a magnitude of ONE). Here Vector vec defines the direction vector. Since we divide by mag (magnitude of direction vector) it makes it a unit vector and multiplying it by 200 makes the magnitude of force equal to 200 * (Sqaure root of) 2.

You must have noticed the last line which sets an Angular Damping of 3. If there was no Angular Damping set on the body it will rotate too much on collision with the sphere.

4) That's it!!!

Here is a demo of GRAVITY SPHERE in Box2dweb.



By administrator at 12:14:21 AM 10 Comment(s)

Comments

I think it would be great if these demos worked with touch input! The exploding bodies demo is great fun and works on my mobile devices, but unfortunately it's impossible to drag things using a mousejoint. Also, are you ever going to start using emscripten-compiled box2d? I'm really curious about performance comparisons between emscripten box2d and box2dweb.
By unphased on 15 Oct, 2012 at 10:15:16 AM
Even I want to code these demos so that they work on devices with touch input but the problem is I don't have a touch device to check whether a demo works or not!
By administrator on 15 Oct, 2012 at 11:22:59 PM
And as for emscripten....at this moment I really don't know. It's syntax is a bit different and I have never worked with that version.
By administrator on 15 Oct, 2012 at 11:25:12 PM
For emscripten, the syntax can get quite hairy as you have to worry about JS to C++ bindings. I think without a good ecosystem and support it's probably not worth the trouble for the few small new features. And who knows box2dweb might even get updated also. As for touch devices I would be glad to collaborate with you somehow. How might I provide you with "pull requests"? I'll at least post here when I come up with mouse joints bound to touch. In fact multitouch allows for the possibility of multiple mousejoints simultaneously, and box2d even seems to allow for it as well. Imagine all the manipulative power we'll have with multitouch mousejoints.
By unphased on 18 Oct, 2012 at 05:38:17 AM
jQuery mobile has events for touch devices, which you should be able to translate the xy coords on the event callback to a mousejoint
By evertith on 18 Oct, 2012 at 07:05:03 AM
Indeed, implementing touch-powered mousejoints should be very straightforward. It's pretty surprising actually, considering how simple it should be that I have still not seen any demo that implements this.
By unphased on 18 Oct, 2012 at 07:16:09 AM
@unphased: I would love to. Please post it here or mail me when you come up with something. Meanwhile I'll also start working on some examples and will mail you them.
By administrator on 18 Oct, 2012 at 09:17:25 PM
That sounds great! It might be a week or two before i get to a working state of combining a JS box2d lib to multitouch but I fully intend to do this. Looking forward to seeing what you'll cook up next as a demo.
By unphased on 19 Oct, 2012 at 03:54:57 AM
Hey coding owl, have you seen this? It's an optimized version of box2dweb: https://github.com/illandril/box2dweb-closure I put a copy of the demo here: http://www.iforce2d.net/illandril-box2dweb-closure
By iforce2d on 26 Oct, 2012 at 10:11:09 PM
I went through it's Github page. Looks promising. But what are it's other advantages other than loading fast?
By administrator on 27 Oct, 2012 at 12:37:42 PM

Add a Comment

Please enter the email address.Invalid format. (Won't be Displayed)
Notify me of followup comments
Enter the displayed Code: captcha