Mar 292012
 

Rigid Body and Soft Body Physics

This is the first of a 4 part series which will show you how to simulate a simple soft body physics object in Box2d. We will be attempting to draw a fully texture mapped, squishy object. In part 1, I will be constructing the physics object.

Box2d is a rigid body physics engine. This means that the physics bodies are non-deformable. But imagine a scenario where you do want a deformable physics body. A good example is a water balloon. The water balloon should be squishy and should deform when it hits the ground. A soft body physics engine can handle something like this. Unfortunately, Box2d is not a soft body physics engine. But there is a way to simulate this in Box2d using distance joints.

Distance Joint

A distance joint keeps the distance between two points a constant. The key feature of distance joint that will help us achieve the soft body physics simulation is that a distance joint can be made soft to simulate a springy connection. We will be creating a wheel like structure in Box2d and then connecting all of the bodies with a springy distance joint in order to simulate the squishiness.

You can read more about distance joints here.

Wheel Construction

The shape to the left is what we will be constructing in Box2d. The greater the number of circles in the outer ring, the better the circle will look. In a later part of the tutorial, I will go through constructing a polygon in OpenGL to map to this Box2d wheel construction.

The wheel is constructed of circles surrounding an inner circle. All of the circles are connected to each other by distance joints. The distance joints are configured to be springy. You may find it helpful to read through this post, which explains drawing a circle in Cocos2d using OpenGL. The math part will be relevant to our discussion here.

Let’s Start

Create a Box2d Cocos2d project. You will want to turn on the b2DebugDraw::e_jointBit so that you can see the joints in the debug drawing. I will not go through how to set up the physics world here. You can find articles on this site that can explain it to you if you do not know how to do this. Also, sample source code will be posted so you can refer to that as well. In HelloWorldLayer.mm, you will see the code below. MyNode is the our custom node which will hold our squishy physics object. We add this to the layer and move it to the center of the screen.

// MyNode is the squishy physics
MyNode *node = [MyNode node];
node.position = ccp(240, 160);
[node createPhysicsObject:world];
[self addChild:node];

Here is the source code for MyNode. We create the outer circles and lay them out in a circle pattern around the center circle. Then we connect them all together with distance joints. The code is well commented so you should be able to figure out what’s going on from reading it.

#import "CCNode.h"
#import "Box2D.h"

typedef struct {
    GLfloat x;
    GLfloat y;
} Vertex2D;

static inline Vertex2D Vertex2DMake(GLfloat inX, GLfloat inY) {
    Vertex2D ret;
    ret.x = inX;
    ret.y = inY;
    return ret;
}

@interface MyNode : CCNode {
}

- (void) createPhysicsObject:(b2World*)world;
@end
#import "cocos2d.h"
#import "MyNode.h"

#define PTM_RATIO 32.f

@implementation MyNode

- (id) init {
    self = [super init];   

    return self;
}

// The number of outer circles (more, the smoother the circle)
#define NUM_SEGMENTS 12

- (void) createPhysicsObject:(b2World *)world {
    // Center is the position of circle that is in the center
    b2Vec2 center = b2Vec2(240/PTM_RATIO, 260/PTM_RATIO);
    
    b2CircleShape circleShape;
    circleShape.m_radius = 0.25f;
    
    b2FixtureDef fixtureDef;
    fixtureDef.shape = &circleShape;
    fixtureDef.density = 0.1;
    fixtureDef.restitution = 0.05;
    fixtureDef.friction = 1.0;
    
    // The greater the number, the more springy
    float springiness = 4.0;
    
    // Delta angle to step by
    float deltaAngle = (2.f * M_PI) / NUM_SEGMENTS;
    
    // Radius of the wheel
    float radius = 50;

    // Need to store the bodies so that we can refer back
    // to it when we connect the joints
    NSMutableArray *bodies = [NSMutableArray array];
    
    // For each segment...
    for (int i = 0; i < NUM_SEGMENTS; i++) {
        // Current angle
        float theta = deltaAngle*i;
        
        // Calcualte the x and y based on theta 
        float x = radius*cosf(theta);
        float y = radius*sinf(theta);
        
        // Remember to divide by PTM_RATIO to convert to Box2d coordinates
        b2Vec2 circlePosition = b2Vec2(x/PTM_RATIO, y/PTM_RATIO);
        
        b2BodyDef bodyDef;
        bodyDef.type = b2_dynamicBody;
        // Position should be relative to the center
        bodyDef.position = (center + circlePosition);
        
        // Create the body and fixture
        b2Body *body;
        body = world->CreateBody(&bodyDef);
        body->CreateFixture(&fixtureDef);
        
        // Add the body to the array to connect joints to it
        // later. b2Body is a C++ object, so must wrap it
        // in NSValue when inserting into it NSMutableArray
        [bodies addObject:[NSValue valueWithPointer:body]];
    }
    
    // Circle at the center (inner circle)
    b2BodyDef innerCircleBodyDef;
    innerCircleBodyDef.type = b2_dynamicBody;    
    // Position is at the center
    innerCircleBodyDef.position = center;    
    b2Body *innerCircleBody = world->CreateBody(&innerCircleBodyDef);
    innerCircleBody->CreateFixture(&fixtureDef);
    
    // Connect the joints    
    b2DistanceJointDef jointDef;
    for (int i = 0; i < NUM_SEGMENTS; i++) {
        // The neighbor.
        int neighborIndex = (i + 1) % NUM_SEGMENTS;
        
        // Get the current body and the neighbor
        b2Body *currentBody = (b2Body*)[[bodies objectAtIndex:i] pointerValue];
        b2Body *neighborBody = (b2Body*)[[bodies objectAtIndex:neighborIndex] pointerValue];

        // Connect the outer circles to each other
        jointDef.Initialize(currentBody, neighborBody,
                            currentBody->GetWorldCenter(), 
                            neighborBody->GetWorldCenter() );
        jointDef.collideConnected = true;
        jointDef.frequencyHz = springiness;
        jointDef.dampingRatio = 0.5f;
        
        world->CreateJoint(&jointDef);
        
        // Connect the center circle with other circles        
        jointDef.Initialize(currentBody, innerCircleBody, currentBody->GetWorldCenter(), center);
        jointDef.collideConnected = true;
        jointDef.frequencyHz = springiness;
        jointDef.dampingRatio = 0.5;
        
        world->CreateJoint(&jointDef);
    }

}

@end

Video and Code

You can download the sample source for this article here.

Soft Body Physics with Box2d and Cocos2d Part 2/4
Soft Body Physics with Box2d and Cocos2d Part 3/4
Soft Body Physics with Box2d and Cocos2d Part 4/4

 Posted by at 9:07 pm

  6 Responses to “Soft Body Physics With Box2d (and Cocos2d) Part 1/4”

  1. [...] 1. Quick Tip: Mixing OpenGL and Cocos2d (Triangle Fan) 2. Soft Body Physics with Box2d and Cocos2d Part 1/4 [...]

  2. [...] Quick Tip: Mixing OpenGL and Cocos2d (Triangle Fan) 2. Soft Body Physics with Box2d and Cocos2d Part 1/4 3. Soft Body Physics with Box2d and Cocos2d Part [...]

  3. [...] Quick Tip: Mixing OpenGL and Cocos2d (Triangle Fan) 2. Soft Body Physics with Box2d and Cocos2d Part 1/4 3. Soft Body Physics with Box2d and Cocos2d Part 2/4 4. Soft Body Physics with Box2d and Cocos2d [...]

  4. Hi there, just wanted to mention, I liked this post. It was inspiring. Keep on posting!

  5. First of all thank you for writing this blog.
    I have implemented the same thing. But I am facing one problem, that is ball gets destroyed from its sides. Quuick link for this:http://stackoverflow.com/questions/17627615/how-to-prevent-softbody-ball-from-destruction-in-box2d
    Check out the screenshots. How can i prevent ball from destroying.?

  6. I blog likewise and I am crafting a thing related to this particular blog, “Soft Body Physics Using Box2d and Cocos2d |
    Uchidacoonga”. Do you really care in cases where I reallyutilize some of your concepts?
    Thanks for your effort ,Paulina

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>