views:

218

answers:

1

I am trying to create a dynamic body that orbits around a static body in Box2D. I have a zero-gravity world, and a DistanceJoint that connects the two bodies. I have removed all friction and damping from the bodies and the joint, and am applying an initial linear velocity to the dynamic body. The result is that the body starts orbiting, but its velocity diminishes over time - which I do not expect in a zero gravity environment without friction.

Am I doing something wrong? Should the linear velocity be recreated at each step, or can I delegate this work to Box2D?

Here is the relevant code:

// positions of both bodies

Vector2 planetPosition = new Vector2(x1 / Physics.RATIO, y1 / Physics.RATIO);
Vector2 satellitePosition = new Vector2(x2 / Physics.RATIO, y2 / Physics.RATIO);


// creating static body

BodyDef planetBodyDef = new BodyDef();
planetBodyDef.type = BodyType.StaticBody;
planetBodyDef.position.set(planetPosition);
planetBodyDef.angularDamping = 0;
planetBodyDef.linearDamping = 0;

planetBody = _world.createBody(planetBodyDef);

CircleShape planetShapeDef = new CircleShape();
planetShapeDef.setRadius(40);

FixtureDef planetFixtureDef = new FixtureDef();
planetFixtureDef.shape = planetShapeDef;
planetFixtureDef.density = 0.7f;
planetFixtureDef.friction = 0;

planetBody.createFixture(planetFixtureDef);

// creating dynamic body

BodyDef satelliteBodyDef = new BodyDef();
satelliteBodyDef.type = BodyType.DynamicBody;
satelliteBodyDef.position.set(satellitePosition);
satelliteBodyDef.linearDamping = 0;
satelliteBodyDef.angularDamping = 0;

satelliteBody = _world.createBody(satelliteBodyDef);

CircleShape satelliteShapeDef = new CircleShape();
satelliteShapeDef.setRadius(10);

FixtureDef satelliteFixtureDef = new FixtureDef();
satelliteFixtureDef.shape = satelliteShapeDef;
satelliteFixtureDef.density = 0.7f;
satelliteFixtureDef.friction = 0;

satelliteBody.createFixture(satelliteFixtureDef);

// create DistanceJoint between bodies

DistanceJointDef jointDef = new DistanceJointDef();        
jointDef.initialize(satelliteBody, planetBody, satellitePosition, planetPosition);
jointDef.collideConnected = false;
jointDef.dampingRatio = 0;

_world.createJoint(jointDef);

// set initial velocity

satelliteBody.setLinearVelocity(new Vector2(0, 30.0f)); // orthogonal to the joint
+2  A: 

Physically, you are correct. Conservation of energy should ensure that the speed of the body remains constant.

However, Box2D cannot perfectly represent physics. There will be a small error in every frame, and these errors add up. I don't know how Box2D handles joints, but if it projects the object's position onto a circle, this would cause the distance travelled during a frame to be slightly smaller than it would have been without the joint.

Bottom line: it's not reasonable to expect the speed to remain exactly the same as what you started with, and you will need to compensate. Depending on your needs, you can either set the velocity manually each frame, or maybe use a revolute joint, anchored on the planet, with a motor.

Thomas
thank you for the explanation! it really makes sense, when one thinks about it in terms of computer science, with all the rounding errors... I guess I was simply expecting pure physics :)
Alexander Gyoshev