开发者

Box2D dynamic body getting stuck (iPhone)

开发者 https://www.devze.com 2023-03-17 01:42 出处:网络
I have a ground object and a spear shaped object(dynamic). When a button is pressed, a linear velocity is applied to the spear. It works fine but sometimes, it gets stuck on the ground. This happens m

I have a ground object and a spear shaped object(dynamic). When a button is pressed, a linear velocity is applied to the spear. It works fine but sometimes, it gets stuck on the ground. This happens most of the time (not always) when the side opposite of spear hide collides straight down with the ground. I am attaching some images so you guys get the picture:

Box2D dynamic body getting stuck (iPhone)

Here my code:

#import "HelloWorldLayer.h"

#define PTM_RATIO 32


@implementation HelloWorldLayer

+(CCScene *) scene{
    CCScene *scene = [CCScene node];

    HelloWorldLayer *layer = [HelloWorldLayer node];
    [scene addChild: layer];

    return scene;
}

-(id) init {

    if( (self=[super init])) {

        isSimulating = NO;

        CGSize winSize = [CCDirector sharedDirector].winSize;

        self.isAccelerometerEnabled = YES;
        self.isTouchEnabled = YES;

        // Create sprite and add it to the layer
        _spear = [CCSprite spriteWithFile:@"image_SPEAR.png"];
        _spear.position = ccp(40, 30);

        [self addChild:_spear];


        label = [CCLabelTTF labelWithString:@"Hello World" fontName:@"Marker Felt" fontSize:20];
        CGSize size = [[CCDirector sharedDirector] winSize];
        label.position =  ccp( size.width /2 , size.height/2 );
        [self addChild: label];

        CCMenuItem *starMenuItem = [CCMenuItemImage 
                                    itemFromNormalImage:@"ball.png" selectedImage:@"ball.png" 
                                    target:self selector:@selector(starButtonTapped:)];
        starMenuItem.position = ccp(60, 250);
        CCMenu *starMenu = [CCMenu menuWithItems:starMenuItem, nil];
        starMenu.position = CGPointZero;
        [self addChild:starMenu];


        // Create a world
        b2Vec2 gravity = b2Vec2(0.0f, -20.0f);
        bool doSleep = true;
        _world = new b2World(gravity, doSleep);

        // Create edges around the entire screen
        b2BodyDef groundBodyDef;
        groundBodyDef.position.Set(0,0);
        b2Body *groundBody = _world->CreateBody(&groundBodyDef);
        b2PolygonShape groundBox;
        b2FixtureDef boxShapeDef;
        boxShapeDef.shape = &groundBox;
        groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(winSize.width/PTM_RATIO, 0));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(0,0), b2Vec2(0, winSize.height/PTM_RATIO));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(0, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, winSize.h开发者_高级运维eight/PTM_RATIO));
        groundBody->CreateFixture(&boxShapeDef);
        groundBox.SetAsEdge(b2Vec2(winSize.width/PTM_RATIO, winSize.height/PTM_RATIO), b2Vec2(winSize.width/PTM_RATIO, 0));
        groundBody->CreateFixture(&boxShapeDef);
        boxShapeDef.friction = 0.3f;


        [self setup];

    }
    return self;
}

- (void)setup {

    NSLog(@"Setting up...");
    //set the sprite's initial position
    _spear.position = ccp(40, 30);
    _spear.rotation = 0.0f;


    //row 1, col 1
    int num = 7;
    b2Vec2 verts[] = {
        b2Vec2(-36.0f / PTM_RATIO, -2.7f / PTM_RATIO),
        b2Vec2(20.1f / PTM_RATIO, -2.1f / PTM_RATIO),
        b2Vec2(24.4f / PTM_RATIO, -4.6f / PTM_RATIO),
        b2Vec2(36.7f / PTM_RATIO, -1.4f / PTM_RATIO),
        b2Vec2(23.9f / PTM_RATIO, 2.7f / PTM_RATIO),
        b2Vec2(20.7f / PTM_RATIO, 0.0f / PTM_RATIO),
        b2Vec2(-36.0f / PTM_RATIO, -0.5f / PTM_RATIO)
    };






    // Create spear body and shape
    b2BodyDef spearBodyDef;
    spearBodyDef.type = b2_dynamicBody;
    spearBodyDef.position.Set(40.0/PTM_RATIO, 30.0/PTM_RATIO);
    //spearBodyDef.angle =  45.0 * (180.0f/b2_pi);
    spearBodyDef.userData = _spear;
    _spearBody = _world->CreateBody(&spearBodyDef);

    b2PolygonShape spearShape;
    spearShape.Set(verts, num);

    b2FixtureDef spearShapeDef;
    spearShapeDef.shape = &spearShape;
    spearShapeDef.density = 0.75f;
    spearShapeDef.friction = 0.2f;
    spearShapeDef.restitution = 0.2f;
    _spearBody->CreateFixture(&spearShapeDef);

}


- (void)starButtonTapped:(id)sender {

    if (isSimulating) {
        NSLog(@"Not simulating now...");

        [self unschedule:@selector(tick:)];
        _world->DestroyBody(_spearBody);
        _spearBody = NULL;
        [self setup];
    } else {
        NSLog(@"Simulating now...");
        [self schedule:@selector(tick:)];

        float angle = _spearBody->GetAngle();

        b2Vec2 force;
        force.Set(cos(angle) * 15.0f , sin(angle) * 15.0f);
        _spearBody->SetLinearVelocity(force);
    }
    isSimulating = !isSimulating;

}

- (void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    if (!isSimulating) {

        UITouch* touch = [touches anyObject];
        CGPoint location = [touch locationInView: [touch view]];
        location = [[CCDirector sharedDirector] convertToGL: location];

        float angleRadians = atanf((float)location.y / (float)location.x);
        float angleDegrees = CC_RADIANS_TO_DEGREES(angleRadians);

        _spear.rotation = -1 * angleDegrees;
        _spearBody->SetTransform(_spearBody->GetPosition(), angleRadians);

        [label setString:[NSString stringWithFormat:@"Angle: %f    X: %f    Y:%f", angleDegrees, location.x, location.y]];
        NSLog(@"%@", @"touched");

    }

}



- (void)tick:(ccTime) dt {
    _world->Step(dt, 10, 10);
    for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) {    
        if (b->GetUserData() != NULL) {
            CCSprite *ballData = (CCSprite *)b->GetUserData();
            ballData.position = ccp(b->GetPosition().x * PTM_RATIO,
                                    b->GetPosition().y * PTM_RATIO);
            ballData.rotation = -1 * CC_RADIANS_TO_DEGREES(b->GetAngle());
        }        
    }
}

- (void) dealloc {
    delete _world;
    _world = NULL;

    [super dealloc];
}
@end

I am guessing it has to do with friction and restitution but I have tried a lot of values and nothing makes this behavior go away. Thanks.

**UPDATE:**I figured out what's causing this. Everytime it gets stuck, it's when the spear goes outside of groundBody. Everytime. But, why would it go outside of groundBody in the first place? Here's an image showing this. At the bottom, the spear is outside of body:

Box2D dynamic body getting stuck (iPhone)


Try turning off sleeping...

bool doSleep = false;
_world = new b2World(gravity, doSleep);

I had a similar problem in one of my box2d based games and this "feature" is what caused it.


note that in the latest version of Cocos2D, you need to use the following to prevent that sticking behaviour:

_world->SetAllowSleeping(false);


Your spear shape is not convex. I highly recommend you use Box2D's debug draw feature to check things every now and then. http://www.iforce2d.net/b2dtut/debug-draw

Here is what the polygon really comes out like - the lines are what you specified, the shaded area is what you got:

Box2D dynamic body getting stuck (iPhone)


Actually box2D has an iterative solver. So the quality of the simulation directly depends on iterations quantity. Try increasing position and/or velocity iterations, when making Step. Also check you are using fixed time step (usually it gives better results). And also you your spear moves rapidly try enabling continuous physics and setting your spear body as bullet (b2BodyDef property).

0

精彩评论

暂无评论...
验证码 换一张
取 消