1
votes

I have a web and some insects i am throwing web and having collision detection with insects and destroying them. i have used bod2d for collision detection.

World Method

-(void)createWorld
{

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

 // 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(b_gravity);
    world->SetAllowSleeping(doSleep);

    world->SetContinuousPhysics(true);

}

Create Web

-(void) createWeb
{
    freeBodySprite = [CCSprite spriteWithFile:@"web1.png"];
        [self addChild:freeBodySprite z:2 tag:TAG_WEB];

    CGPoint startPos = CGPointMake(100, 320/1.25);

    bodyDef.type = b2_staticBody;
    bodyDef.position = [self toMeters:startPos];
    bodyDef.userData = freeBodySprite;

    float radiusInMeters = ((freeBodySprite.contentSize.width * freeBodySprite.scale/PTM_RATIO) * 1.0f);
    shape.m_radius = radiusInMeters;

    fixtureDef.shape = &shape;
    fixtureDef.density = 0.01f;
    fixtureDef.friction = 0.1f;
    fixtureDef.restitution = 0.1f;

    circularObstacleBody = world->CreateBody(&bodyDef);
    stoneFixture = circularObstacleBody->CreateFixture(&fixtureDef);
        freeBody = circularObstacleBody;
}

I have created my insect animation with spritesheet and then created b2body for that Sprite

-(b2Body *) createMovingBoxObstacle
{


    //set this to avoid updating this object in the tick schedule
        _ants.userData = (void *)YES;

    b2BodyDef bodyDef_Ant;
    bodyDef_Ant.type = b2_dynamicBody;
    CGPoint startPos = ccp(520,winSize.height/7.6);
    bodyDef_Ant.position = [self toMeters:startPos];
    bodyDef_Ant.userData = _ants;

    b2PolygonShape dynamicBox;
    float tileWidth = ((_ants.contentSize.width * _ants.scale/PTM_RATIO) * 0.5f);
    float tileHeight = ((_ants.contentSize.height * _ants.scale/PTM_RATIO) * 0.5f);
    dynamicBox.SetAsBox(tileWidth, tileHeight);

    b2FixtureDef fixtureDef_Ant;
    fixtureDef_Ant.shape = &dynamicBox;
    fixtureDef_Ant.friction = 0.7;
    fixtureDef_Ant.density = 0.1f;
    fixtureDef_Ant.restitution = 0.7;


    staticBody = world->CreateBody(&bodyDef_Ant);
    staticBody->CreateFixture(&fixtureDef_Ant);

       VAMovingObstacle* moveableObject = [[VAMovingObstacle alloc] init];
       moveableObject.startPoint = ccp(520,winSize.height/7.6);
       moveableObject.endPoint = ccp(-50,winSize.height/7.6);
       moveableObject.transitionTime = 20.0;
       moveableObject.breakTime = 1.0;

    moveableObject.obstacleSprite = _ants;
    moveableObject.physicalBody = staticBody;
    [moveableObject startMovement];

    if (!movingObstacles) {
        movingObstacles = [[NSMutableArray alloc] init];
    }
    [movingObstacles addObject:moveableObject];
    [moveableObject release];
    return staticBody;
}

VAMovingObstacle is a class which helps sprite along with b2body to move from left to right (runaction)

Here is my contact listner EndContact method

void ContactListener::EndContact(b2Contact* contact)
{
    b2Body* bodyA = contact->GetFixtureA()->GetBody();
    b2Body* bodyB = contact->GetFixtureB()->GetBody();

    if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
        CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
        CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();


        if (spriteA.tag == TAG_WEB && spriteB.tag >= TAG_ANT) {

        }

        else if (spriteA.tag >= TAG_ANT && spriteB.tag == TAG_WEB) {

            [spriteA removeFromParentAndCleanup:YES];
            [[HelloWorldLayer sharedLevel] WebCollisionWithInsect:bodyA];
        }
    }
}

when ever collision happens EndContact method calls WebCollisionWithInsect:bodyA

-(void) WebCollisionWithInsect:(b2Body*) bodyT{
            world->DestroyBody(bodyT);
}

On world->DestroyBody(bodyT) line it give an error

Assertion failed: (IsLocked() == false), function DestroyBody, file /Users/libs/Box2D/Dynamics/b2World.cpp, line 134.

Any Idea what i am doing wrong. ?

Edited I have added this line in EndContact

destroyCollisionDetectionBody = objBody;
didInsectCollideWithWeb = YES;

Keeping reference of body i want to destroy. Now i can destroy my body inside tick method on if check Added these lines in tick method

if(didInsectCollideWithWeb)
    {
        [self unschedule:@selector(tick:)];
        [freeBodySprite removeFromParentAndCleanup:YES]; // this is my web
        world->DestroyBody(destroyCollisionDetectionBody);
        world->DestroyBody(freeBody);
        [self createWeb];
        [self schedule:@selector(tick:)];
        didInsectCollideWithWeb = NO;

    }

But now problem is that when i am destroying my web i.e freebody. i cant recreate it. as i was doing it before by calling [self createWeb];

1

1 Answers

1
votes

You are trying to destroy a box2d object while its being used in the simulation phase (as EndContact is called during that phase). The simulation phase is the one executed when you call the world's step method.

So what you should do is keep a reference to the body object you want to remove and after the box2d simulation phase (after the step method returns) execute the WebCollisionWithInsect with the desired body