RevoluteJoint Box2d的问题

时间:2011-04-03 14:26:32

标签: cocos2d-iphone physics box2d

我有旋转关节的问题。当我用litlle box和revoluteJoint做一条线时,我注意到了我的第一个盒子的奇怪行为。它与其他盒子分开。

你可以在这里看到:

Youtube

你可以编译它,你会看到我在说什么......

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

有什么想法吗?提前致谢

1 个答案:

答案 0 :(得分:1)

您的情况下的问题是您的第一个盒子围绕锚点旋转360度。这可能发生在第一个和最后一个框。我认为您需要限制连接的360度旋转。你已经确定了你的盒子可以达到的最大角度。您可以通过在关节中使用马达来实现。以下是Box2D手册中的一些代码,用于为关节创建电机,

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;

我希望它有所帮助。