RevoluteJoint Box2d 的问题

发布于 2024-10-30 04:53:32 字数 7464 浏览 2 评论 0原文

我的旋转关节有问题。当我用小盒子和 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

有什么想法吗?提前致谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

请恋爱 2024-11-06 04:53:32

您的情况的问题是您的第一个框围绕锚点进行 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;

希望对您有所帮助。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文