Box2D Forums

It is currently Mon May 20, 2013 5:47 am

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Wed Jul 18, 2012 4:31 pm 
Offline

Joined: Fri Mar 09, 2012 1:43 pm
Posts: 69
I have 2 bodies colliding. One is created like so in its own class:

Code:
b2BodyDef bodyDefShip;
        bodyDefShip.type = b2_dynamicBody;
        bodyDefShip.userData = self;
        bodyDefShip.position.Set(location.x/PTM_RATIO, location.y/PTM_RATIO);
        shipBody = world->CreateBody(&bodyDefShip);
       
        b2PolygonShape shapeShip;
        shapeShip.SetAsBox(self.contentSize.width/2/PTM_RATIO, self.contentSize.height/2/PTM_RATIO);
       
        b2FixtureDef fixtureDefShip;
        fixtureDefShip.shape = &shapeShip;
        fixtureDefShip.density = 0.0;
        fixtureDefShip.friction = 0.0;
        fixtureDefShip.restitution = 0.0;
       
        shipBody->CreateFixture(&fixtureDefShip);
         
        //for collision detection
        fixtureDefShip.filter.categoryBits = 0x1; //(default is 0x1 so this body belongs to a different category)
        fixtureDefShip.filter.maskBits = 0xFFFF; //(0xFFFF means it collides with all categories)


the second one is created in the action layer, in an addTarget method:

Code:
target = [WeakAndFastShipTarget target];
        //////////////////////////////////BOX2d/////////////////////////////////////////
       
         b2BodyDef bodyDef;
         bodyDef.type = b2_dynamicBody;
         bodyDef.userData = target;
         bodyDef.position.Set(winSize.width/PTM_RATIO, winSize.height/2/PTM_RATIO);
         cometBody = world->CreateBody(&bodyDef);
         
         b2PolygonShape shape;
         shape.SetAsBox(target.contentSize.width/2/PTM_RATIO, target.contentSize.height/2/PTM_RATIO);
         
         b2FixtureDef fixtureDef;
         fixtureDef.shape = &shape;
         fixtureDef.density = 0.0;
         fixtureDef.friction = 0.0;
         fixtureDef.restitution = 0.0;
         
         cometBody->CreateFixture(&fixtureDef);
         
        //for collision detection
        fixtureDef.filter.categoryBits = 0x4; //(default is 0x1 so this body belongs to a different category)
        fixtureDef.filter.maskBits = 0xFFFF; //(0xFFFF means it collides with all categories)


Then I override the beginContact method in my action layer at the end:

Code:
- (void)beginContact:(b2Contact *)contact {
   
    b2Fixture *fixtureA = contact->GetFixtureA();
    b2Fixture *fixtureB = contact->GetFixtureB();
    b2Body *bodyA = fixtureA->GetBody();
    b2Body *bodyB = fixtureB->GetBody();
    GameObject *spriteA = (GameObject *) bodyA->GetUserData();
    GameObject *spriteB = (GameObject *) bodyB->GetUserData();
   
    if (!spriteA.visible || !spriteB.visible) return;
   
    b2WorldManifold manifold;
    contact->GetWorldManifold(&manifold);
    b2Vec2 b2ContactPoint = manifold.points[0];
    CGPoint contactPoint = ccp(b2ContactPoint.x * PTM_RATIO, b2ContactPoint.y * PTM_RATIO);
   
    CGSize winSize = [CCDirector sharedDirector].winSize;
    //////////////////////////////////////////////////////////////////////////SHIP COLLIDES WITH ENEMYSHIP OR ENEMY
    if ((fixtureA->GetFilterData().categoryBits & kCategoryShip && fixtureB->GetFilterData().categoryBits & kCategoryEnemy) ||
        (fixtureB->GetFilterData().categoryBits & kCategoryShip && fixtureA->GetFilterData().categoryBits & kCategoryEnemy)) {
        NSLog(@"Collision happened");
        // Determine enemy ship
        GameObject *enemyShip = (GameObject*) spriteA;
        if (fixtureB->GetFilterData().categoryBits & kCategoryEnemy) {
            enemyShip = spriteB;
        }
        [[SimpleAudioEngine sharedEngine] playEffect:@"explode.caf" pitch:1.0f pan:0.0f gain:0.25f];
                   
        //TAKE A HIT
        [_player takeHit];
    }


and above the action layer I define the categories like so:

Code:
#define kCategoryShip 0x1
#define kCategoryShipLaser 0x2
#define kCategoryEnemy 0x4


As you can see I have an NSLog inside the beginContact if test. If the collision occurs, which it does, the NSLog should appear in the console but it doesn't. I am not clear as to why the bodies aren't colliding.


Top
 Profile  
 
PostPosted: Wed Jul 18, 2012 9:55 pm 
Offline

Joined: Sun Oct 25, 2009 3:28 am
Posts: 242
The filter data stuff in the initialization needs to be before CreateFixture. Box2D does a deep copy of the definition, so changing the definition after CreateFixture does not affect the recently made fixture.


Top
 Profile  
 
PostPosted: Thu Jul 19, 2012 9:19 am 
Offline

Joined: Fri Mar 09, 2012 1:43 pm
Posts: 69
I started a new project and figured it out.

1) I first carried out jayther's suggestion which totally makes sense..DUH

2) My main problem was that I was adding the main ship to the batchNode but the target to self, the layer.

The odd thing is that even with the erroneous code where the ship is in the batch node and the target is on the layer itself, this code is called in the update method works just fine:

Code:
std::vector<b2Body *>toDestroy;
    std::vector<MyContact>::iterator pos;
    for(pos = _contactListener->_contacts.begin();
        pos != _contactListener->_contacts.end(); ++pos) {
        MyContact contact = *pos;
       
        b2Body *bodyA = contact.fixtureA->GetBody();
        b2Body *bodyB = contact.fixtureB->GetBody();
       
        if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
           
            CCSprite *spriteA = (CCSprite *) bodyA->GetUserData();
            CCSprite *spriteB = (CCSprite *) bodyB->GetUserData();
           
            // If either is Comet && SHIP
            if (([spriteA isKindOfClass:[WeakAndFastShipTarget class]] && [spriteB isKindOfClass:[HopperShip class]]) ||
                ([spriteA isKindOfClass:[HopperShip class]] && [spriteB isKindOfClass:[WeakAndFastShipTarget class]]) ) {
                NSLog(@"COMET HIT SHIP");
                //Call takehit on ship && shake screen && ignore collision force between objects
                //[_player takeHit];
                //if (std::find(toDestroy.begin(), toDestroy.end(), bodyB) == toDestroy.end()) {
                //    toDestroy.push_back(bodyB);
                //}
            }
            // Laser && Comet - this is handled elsewhere
            else if ([spriteA isKindOfClass:[WeakAndFastShipTarget class]] && [spriteA isKindOfClass:[HopperShip class]]) {
                NSLog(@"LASER HIT COMET");
               
                //if (std::find(toDestroy.begin(), toDestroy.end(), bodyA) == toDestroy.end()) {
                //    toDestroy.push_back(bodyB);
                //}
            }     
        }       
    }
    // Clean up array of bodies to destroy?
    std::vector<b2Body *>::iterator pos2;
    for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
        b2Body *body = *pos2;     
        if (body->GetUserData() != NULL) {
            NSLog(@"DESTROY VECTOR");
            CCSprite *sprite = (CCSprite *) body->GetUserData();
            [sceneSpriteBatchNode removeChild:sprite cleanup:YES];
        }
        world->DestroyBody(body);
       
    }
   
    if (toDestroy.size() > 0) {
        NSLog(@"MINECART HIT");
        PLAYSOUNDEFFECT(MINECART_HIT);
    }


but then again that code is based off of a class called ContactListener;

whereas the beginContact and endContact methods I am using now work off of the SimpleContactListener Class.

Maybe there is something in there that differs.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: Google [Bot] and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group