RSS

Tag Archives: open gl

Rope made from Box2D bodies

Here is a video of how a rope looks like made from box2d bodies. Earlier i has given a tutorial of how to make a rope using Verlets. This one, on the contrary, has bodies attached to it. Verlets can be used where only a visual simulation is required and the rope is not to interact with other bodies. That ways you can save up on performance. This will however take up more resources.

This slideshow requires JavaScript.

Some word on how it works

So here is how it goes. The objective of the demonstration was to create a rope out of box2d bodies. The rope would respond to collisions with other bodies and the walls of the world. Alongside, just for demonstration sakes, i also added a mouse joint so that you can drag the rope and see how it works.

Start off by defining some common properties for creating bodies:

//body and fixture defs are common to all chain links
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.position = startPos;
b2FixtureDef fixtureDef;
fixtureDef.density = 0.1;
b2PolygonShape polygonShape;
polygonShape.SetAsBox(linkWidth,linkHeight);
fixtureDef.shape = &polygonShape;

and some others for a revolute joint

//set up the common properties of the joint before entering the loop
b2RevoluteJointDef revoluteJointDef;
revoluteJointDef.localAnchorA.Set( 0, linkHeight);
revoluteJointDef.localAnchorB.Set( 0, -linkHeight);

then we create the links in the chain

//use same definitions to create multiple bodies
for (int i = 0; i < 20; i++) { b2Body* newLink = world->CreateBody( &bodyDef );
newLink->CreateFixture( &fixtureDef );
PhysicsSprite* segmentSprite = [PhysicsSprite spriteWithFile:@"rope_seg_new2.png"];
[self addChild:segmentSprite];
[segmentSprite setPhysicsBody:link];


revoluteJointDef.bodyA = link;
revoluteJointDef.bodyB = newLink;
world->CreateJoint( &revoluteJointDef );


link = newLink;//prepare for next iteration
}

Then to create the circle that is attached to the rope. We do the following:

PhysicsSprite* circleBodySprite = [PhysicsSprite spriteWithFile:@"circle2x_bounce.png"];
[self addChild:circleBodySprite z:1];

//body with circle fixture
b2CircleShape circleShape;
circleShape.m_radius = circleBodySprite.contentSize.width/2 / PTM_RATIO;
fixtureDef.shape = &circleShape;
b2Body* chainBase =world->CreateBody( &bodyDef );
chainBase->CreateFixture( &fixtureDef );
[circleBodySprite setPhysicsBody:chainBase];

Then we define two revolute joints. One for the circle and the other one between the cirlce and the chain.

//a revolute joint to connect the circle to the ground
revoluteJointDef.bodyA = referenceBody;//provided by testbed
revoluteJointDef.bodyB = chainBase;
revoluteJointDef.localAnchorA = startPos;//world coords, because m_groundBody is at (0,0)
revoluteJointDef.localAnchorB.Set(0,0);//center of circle
world->CreateJoint( &revoluteJointDef );

//another revolute joint to connect the chain to the circle
revoluteJointDef.bodyA = link;//the last added link of the chain
revoluteJointDef.bodyB = chainBase;

//the regular position for chain link joints, as above
revoluteJointDef.localAnchorA.Set(0,linkWidth);

//a little in from the edge of the circle
revoluteJointDef.localAnchorB.Set(0,linkWidth);
world->CreateJoint( &revoluteJointDef );

Now that we have our chain ready. We will add mouse joints upon tap. For that i created this function that will fetch the body that was under the tap location:

-(b2Body *) getBodyAtLocation:(b2Vec2) aLocation {
for (b2Body* b = world->GetBodyList(); b; b = b->GetNext()) {
b2Fixture* bodyFixture = b->GetFixtureList();
if (bodyFixture->TestPoint(aLocation)){
return b;
}
}
return NULL;
}

and this is how the mouse joint is installed

if (mouseJoint != NULL) return;


UITouch *myTouch = [touches anyObject];
CGPoint location = [myTouch locationInView:[myTouch view]];
location = [[CCDirector sharedDirector] convertToGL:location];
b2Vec2 locationWorld = [self toMeters:location];
freeBody = [self getBodyAtLocation:locationWorld];

//hit test point in box2d
if (freeBody) {
b2MouseJointDef md;
md.bodyA = referenceBody;
md.bodyB = freeBody;
md.target = locationWorld;
md.collideConnected = true;
md.maxForce = 100.0f;

mouseJoint = (b2MouseJoint *)world->CreateJoint(&md);
freeBody->SetAwake(true);
}

Here is a link to the source code and here is a link to the video of how it works. Here is a link to another source code that doesn’t use mouse joint and rather translates swipe variables (angle and distance) to move the body.

 
30 Comments

Posted by on March 24, 2012 in Box2d, cocos2d, Objective C, Xcode

 

Tags: , , , , , , , , , , , , , , , , , , ,