David
David

Reputation: 169

Problem with RevoluteJoint Box2d

i have a problem with revolutejoint. When i make a line with litlle boxes and revoluteJoint i noticed a strange behavior of my first box. it separates from rest of the boxes.

You can see it here:

Youtube

You can compile it, and you'll see what im talking about…

HelloWorldScene.h

// When you import this file, you import all the cocos2d classes
#import "cocos2d.h"
#import "Box2D.h"
#import "GLES-Render.h"

// HelloWorld Layer
@interface HelloWorld : CCLayer
{
    b2World* world;
    GLESDebugDraw *m_debugDraw;
}

// returns a Scene that contains the HelloWorld as the only child
+(id) scene;
-(void) Test;

@end

HelloWorldScene.mm

// Import the interfaces
#import "HelloWorldScene.h"

//Pixel to metres ratio. Box2D uses metres as the unit for measurement.
//This ratio defines how many pixels correspond to 1 Box2D "metre"
//Box2D is optimized for objects of 1x1 metre therefore it makes sense
//to define the ratio so that your most common object type is 1x1 metre.
#define PTM_RATIO 32

// enums that will be used as tags
enum {
    kTagTileMap = 1,
    kTagBatchNode = 1,
    kTagAnimation1 = 1,
};

// HelloWorld implementation
@implementation HelloWorld

+(id) scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // 'layer' is an autorelease object.
    HelloWorld *layer = [HelloWorld node];

    // add layer as a child to scene
    [scene addChild: layer];

    // return the scene
    return scene;
}   

// initialize your instance here
-(id) init
{
    if( (self=[super init])) {

        // enable touches
        self.isTouchEnabled = YES;

        // enable accelerometer
        self.isAccelerometerEnabled = YES;

        CGSize screenSize = [CCDirector sharedDirector].winSize;
        CCLOG(@"Screen width %0.2f screen height %0.2f",screenSize.width,screenSize.height);

        // Define the gravity vector.
        b2Vec2 gravity;
        gravity.Set(0.0f, -10.0f);

        // Do we want to let bodies sleep?
        // This will speed up the physics simulation
        bool doSleep = true;

        // Construct a world object, which will hold and simulate the rigid bodies.
        world = new b2World(gravity, doSleep);

        world->SetContinuousPhysics(true);

        // Debug Draw functions
        m_debugDraw = new GLESDebugDraw( PTM_RATIO );
        world->SetDebugDraw(m_debugDraw);

        uint32 flags = 0;
        flags += b2DebugDraw::e_shapeBit;
        flags += b2DebugDraw::e_jointBit;
//      flags += b2DebugDraw::e_aabbBit;
//      flags += b2DebugDraw::e_pairBit;
//      flags += b2DebugDraw::e_centerOfMassBit;
        m_debugDraw->SetFlags(flags);       

        // Define the ground body.
        b2BodyDef groundBodyDef;
        groundBodyDef.position.Set(0, 0); // bottom-left corner

        // Call the body factory which allocates memory for the ground body
        // from a pool and creates the ground box shape (also from a pool).
        // The body is also added to the world.
        b2Body* groundBody = world->CreateBody(&groundBodyDef);

        // Define the ground box shape.
        b2PolygonShape groundBox;       

        // bottom
        groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(screenSize.width/PTM_RATIO,0));
        groundBody->CreateFixture(&groundBox,0);

        // top
        groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO));
        groundBody->CreateFixture(&groundBox,0);

        // left
        groundBox.SetAsEdge(b2Vec2(0,screenSize.height/PTM_RATIO), b2Vec2(0,0));
        groundBody->CreateFixture(&groundBox,0);

        // right
        groundBox.SetAsEdge(b2Vec2(screenSize.width/PTM_RATIO,screenSize.height/PTM_RATIO), b2Vec2(screenSize.width/PTM_RATIO,0));
        groundBody->CreateFixture(&groundBox,0);

        //Set up sprite

        [self Test];

        [self schedule: @selector(tick:)];
    }
    return self;
}   

- (void) Test {

    // Circle
    b2Body *circle1;
    b2BodyDef bd1;
    bd1.position.Set(45.0f/PTM_RATIO, 180.0f/PTM_RATIO);
    bd1.type = b2_kinematicBody;
    bd1.fixedRotation = false;
    bd1.allowSleep = false;
    circle1 = world->CreateBody(&bd1);

    b2CircleShape shapecircle1;
    shapecircle1.m_radius = 0.5f;

    b2FixtureDef fdcircle1;
    fdcircle1.shape = &shapecircle1;
    fdcircle1.density = 2.0f;
    fdcircle1.friction = 2.0f;

    circle1->CreateFixture(&fdcircle1);

    // Boxes

    b2PolygonShape shape;
    shape.SetAsBox(6.0f/PTM_RATIO, 0.125f);

    b2FixtureDef fd;
    fd.shape = &shape;
    fd.density = 20.0f;
    fd.friction = 0.2f;

    b2RevoluteJointDef jd;
    jd.collideConnected = false;

    const float32 y = 9.0f;
    b2BodyDef bd;
    bd.type = b2_dynamicBody;
    bd.position.Set(15.0f/PTM_RATIO, y);
    b2Body* prevBody = world->CreateBody(&bd);
    prevBody->CreateFixture(&fd);
    b2Vec2 anchor(float32(0), y);

    for (int32 i = 1; i < 8; ++i)
    {
        b2BodyDef bd;
        bd.type = b2_dynamicBody;
        bd.position.Set((15.0f + (i*10))/PTM_RATIO, y);
        b2Body* body = world->CreateBody(&bd);
        body->CreateFixture(&fd);
        b2Vec2 anchor(float32(i*10)/PTM_RATIO, y);

        jd.Initialize(prevBody, body, anchor);
        world->CreateJoint(&jd);

        prevBody = body;
    }
}

-(void) draw
{
    // Default GL states: GL_TEXTURE_2D, GL_VERTEX_ARRAY, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
    // Needed states:  GL_VERTEX_ARRAY,
    // Unneeded states: GL_TEXTURE_2D, GL_COLOR_ARRAY, GL_TEXTURE_COORD_ARRAY
    glDisable(GL_TEXTURE_2D);
    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    world->DrawDebugData();

    // restore default GL states
    glEnable(GL_TEXTURE_2D);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

}   

-(void) tick: (ccTime) dt
{
    //It is recommended that a fixed time step is used with Box2D for stability
    //of the simulation, however, we are using a variable time step here.
    //You need to make an informed choice, the following URL is useful
    //http://gafferongames.com/game-physics/fix-your-timestep/

    int32 velocityIterations = 8;
    int32 positionIterations = 1;

    // Instruct the world to perform a single step of simulation. It is
    // generally best to keep the time step and iterations fixed.
    world->Step(dt, velocityIterations, positionIterations);

    //Iterate over the bodies in the physics world
    for (b2Body* b = world->GetBodyList(); b; b = b->GetNext())
    {
        if (b->GetUserData() != NULL) {
            //Synchronize the AtlasSprites position and rotation with the corresponding body
            CCSprite *myActor = (CCSprite*)b->GetUserData();
            myActor.position = CGPointMake( b->GetPosition().x * PTM_RATIO, b->GetPosition().y * PTM_RATIO);
            myActor.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
        }
    }
}

// on "dealloc" you need to release all your retained objects
- (void) dealloc
{
    // in case you have something to dealloc, do it in this method
    delete world;
    world = NULL;

    delete m_debugDraw;

    // don't forget to call "super dealloc"
    [super dealloc];
}
@end

Any idea? Thanks in advance

Upvotes: 1

Views: 775

Answers (1)

Tayyab
Tayyab

Reputation: 10631

The problem in your case is that your first box makes a 360 degree rotation around the anchor. This can happen to first and last box. I think you need to restrict the 360 degree rotation for your join. You have do define that maximum angle that your box can achieve. You can do it by using motors in your joints. Following is some code from Box2D manual to create motors for your joints,

b2RevoluteJointDef jointDef;
jointDef.Initialize(body1, body2, myBody1->GetWorldCenter());
jointDef.lowerAngle = -0.5f * b2_pi; // -90 degrees
jointDef.upperAngle = 0.25f * b2_pi; // 45 degrees
jointDef.enableLimit = true;
jointDef.maxMotorTorque = 10.0f;
jointDef.motorSpeed = 0.0f;
jointDef.enableMotor = true;

I hope it helps.

Upvotes: 1

Related Questions