# 论述如何基于Box2D模拟星球重力效果

private var world:b2World=new b2World(new b2Vec2(0,0),true);

abspace from emanueleferonato.com

package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.*;
public class Main extends Sprite {
private var world:b2World=new b2World(new b2Vec2(0,0),true);
private var worldScale:Number=30;
private var planetVector:Vector.<b2Body>=new Vector.<b2Body>();
private var debrisVector:Vector.<b2Body>=new Vector.<b2Body>();
private var orbitCanvas:Sprite=new Sprite();
public function Main() {
orbitCanvas.graphics.lineStyle(1,0xff0000);
debugDraw();
}
private function createDebris(e:MouseEvent):void {
}
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.restitution=0;
fixtureDef.density=1;
var circleShape:b2CircleShape=new b2CircleShape(r/worldScale);
fixtureDef.shape=circleShape;
var bodyDef:b2BodyDef=new b2BodyDef();
bodyDef.userData=new Sprite();
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var thePlanet:b2Body=world.CreateBody(bodyDef);
planetVector.push(thePlanet);
thePlanet.CreateFixture(fixtureDef);
orbitCanvas.graphics.drawCircle(pX,pY,r*3);
}
var polygonShape:b2PolygonShape = new b2PolygonShape();
polygonShape.SetAsBox(w/worldScale/2,h/worldScale/2);
var fixtureDef:b2FixtureDef = new b2FixtureDef();
fixtureDef.density=1;
fixtureDef.friction=1;
fixtureDef.restitution=0;
fixtureDef.shape=polygonShape;
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.type=b2Body.b2_dynamicBody;
bodyDef.position.Set(pX/worldScale,pY/worldScale);
var box:b2Body=world.CreateBody(bodyDef);
debrisVector.push(box);
box.CreateFixture(fixtureDef);
}
private function debugDraw():void {
var debugDraw:b2DebugDraw = new b2DebugDraw();
var debugSprite:Sprite = new Sprite();
debugDraw.SetSprite(debugSprite);
debugDraw.SetDrawScale(worldScale);
debugDraw.SetFlags(b2DebugDraw.e_shapeBit|b2DebugDraw.e_jointBit);
debugDraw.SetFillAlpha(0.5);
world.SetDebugDraw(debugDraw);
}
private function update(e:Event):void {
world.Step(1/30, 10, 10);
world.ClearForces();
for (var i:int=0; i<debrisVector.length; i++) {
var debrisPosition:b2Vec2=debrisVector[i].GetWorldCenter();
for (var j:int=0; j<planetVector.length; j++) {
var planetShape:b2CircleShape=planetVector[j].GetFixtureList().GetShape() as b2CircleShape;
var planetPosition:b2Vec2=planetVector[j].GetWorldCenter();
var planetDistance:b2Vec2=new b2Vec2(0,0);
planetDistance.Subtract(planetPosition);
var finalDistance:Number=planetDistance.Length();
planetDistance.NegativeSelf();
var vecSum:Number=Math.abs(planetDistance.x)+Math.abs(planetDistance.y);
debrisVector[i].ApplyForce(planetDistance,debrisVector[i].GetWorldCenter());
}
}
}
world.DrawDebugData();
}
}
}

for (var i:int=0; i<debrisVector.length; i++) {

var debrisPosition:b2Vec2=debrisVector[i].GetWorldCenter();

for (var j:int=0; j<planetVector.length; j++) {

var planetShape:b2CircleShape=planetVector[j].GetFixtureList().GetShape() as b2CircleShape;

……设定它的半径。所以在这种情况下，半径越大，重力吸引力就越强烈。

var planetPosition:b2Vec2=planetVector[j].GetWorldCenter();

var planetDistance:b2Vec2=new b2Vec2(0,0);

planetDistance.Subtract(planetPosition);

……扣除星球坐标轴。

var finalDistance:Number=planetDistance.Length();

planetDistance.NegativeSelf();

var vecSum:Number=Math.abs(planetDistance.x)+Math.abs(planetDistance.y);

debrisVector[i].ApplyForce(planetDistance,debrisVector[i].GetWorldCenter());

debris from emanueleferonato.com

Simulate radial gravity (also known as “planet gravity”) with Box2D as seen on Angry Birds Space

by Emanuele Feronato

With the launch of Angry Birds Space I am sure you are wondering how to simulate planet gravity with Box2D.

And guess what… the basics are very easy.

First, in space there’s no gravity, so you will create a b2World world without gravity this way:

Then, it’s just a matter of applying Forces according to bodies and planets position.

Look at this script:

The whole code just create static bodies (planets) and let you place dynamic bodies (debris) with the click of the mouse.

The only interesting part of the script is the for loop in the update function, which I’ll explain line by line:

Loop which scans for all debris previously stored in debrisVector Vector declared at line 14 and updated at line 54

Gets debris position

Loop which scans for all planets previously stored in planetVector Vector declared at line 13 and updated at line 38

I need to know the mass of the planet because the bigger the mass, the more intense the gravity attraction. Unfortunately Box2D static bodies do not have mass, so I need to get the circle shape of the planet…

… and get its radius. So in this case the bigger the radius, the more intense the gravity attraction

Gets planet position

Creates a new b2Vec2 variable which will store the distance between the planet and the debris

… subtracts planet coordinates

Calculates the distance between the planet and the debris

Checks if the debris should be affected by planet gravity (in this case, the debris must be within a radius of three times the planet radius)

Inverts planet distance, so that the force will move the debris in the direction of the planet origin

Gets the sum of distance vector components. I will need this to make gravity attraction weaker when the debris is far from the planet, and stronger when the debris is getting close to the planet

This is the final formula to make the gravity weaker as we move far from the planet

And finally the force can be applied to debris

This is the result:（Source：emanueleferonato