Войти
Box2DФорумОбщее

Столкновения не всегда срабатывают

#0
13:26, 23 авг. 2013

Здравствуйте. Я новичок в box2d, поэтому прошу помощи. Создаю тело так:

- (void)addBoxBodyForSprite:(CCSprite *)sprite {
    b2BodyDef spriteBodyDef;
    spriteBodyDef.type = b2_dynamicBody;
    spriteBodyDef.position.Set(sprite.position.x/PTM_RATIO,
                               sprite.position.y/PTM_RATIO);
    spriteBodyDef.userData = sprite;
    body = world->CreateBody(&spriteBodyDef);
    
    b2PolygonShape spriteShape;
    
    int num = 7;
    b2Vec2 verts[] = {b2Vec2(-11.8f / PTM_RATIO, -24.5f / PTM_RATIO),
        b2Vec2(11.7f / PTM_RATIO, -24.0f / PTM_RATIO),
        b2Vec2(29.2f / PTM_RATIO, -14.0f / PTM_RATIO),
        b2Vec2(28.7f / PTM_RATIO, -0.7f / PTM_RATIO),
        b2Vec2(8.0f / PTM_RATIO, 18.2f / PTM_RATIO),
        b2Vec2(-29.0f / PTM_RATIO, 18.7f / PTM_RATIO),
        b2Vec2(-26.3f / PTM_RATIO, -12.2f / PTM_RATIO)};
    spriteShape.Set(verts, num);

    
    b2FixtureDef spriteShapeDef;
    spriteShapeDef.shape = &spriteShape;
    spriteShapeDef.density = 10.0;
    spriteShapeDef.isSensor = true;
    body->SetGravityScale(0);
    
    body->CreateFixture(&spriteShapeDef);
}

Проверка на столкновения:

 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 (spriteA.tag == 1 && spriteB.tag == 2) {
                toDestroy.push_back(bodyA);
            } else if (spriteA.tag == 2 && spriteB.tag == 1) {
                toDestroy.push_back(bodyB);
            }
        }
    }
    
    std::vector<b2Body *>::iterator pos2;
    for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
        body = *pos2;
        if (body->GetUserData() != NULL) {
            CCSprite *sprite = (CCSprite *) body->GetUserData();
            [self removeChild:sprite cleanup:YES];
        }
        world->DestroyBody(body);
    }
    
    if (toDestroy.size() > 0) {
        NSLog(@"contakt");
        //[[SimpleAudioEngine sharedEngine] playEffect:@"hahaha.caf"];
    }

Проблема в том, что столкновения не всегда срабатывают, например если сблизить оба объекта почти впритык, потом отодвинуть и снова придвинуть, то коллизия уже не сработает. С первого раза работает хорошо.


#1
14:58, 23 авг. 2013

используй события контакт листера

class PhysicContactListener : public b2ContactListener 
{
public:
       PhysicContactListener();
  ~PhysicContactListener();  
public:
      // вызывается перед контактом, можно отменить контакт и он не произойдет
      void PreSolve(b2Contact* contact, const b2Manifold* oldManifold);
      
      // вызывается когда два тела начинают пересекаться
      void BeginContact(b2Contact* contact);

      // вызывается всегда пока тела находятся в контакте
      void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse);

      // вызывается когда два тела перестают пересекаться
      void EndContact(b2Contact* contact);
};

PhysicContactListener::PhysicContactListener(): b2ContactListener() {}
PhysicContactListener::~PhysicContactListener() {}

// Всегда первым объектом в контакте является объект созданный раньше

void PhysicContactListener::BeginContact(b2Contact* contact) {
    
    id bo1 = (__bridge id)contact->GetFixtureA()->GetBody()->GetUserData();
    id bo2 = (__bridge id)contact->GetFixtureB()->GetBody()->GetUserData();
    //DDLogCDebug(@"%@/%@", [bo1 class], [bo2  class]);
    if ([bo1 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo1 beginContact:contact with:bo2];
    }
    if ([bo2 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo2 beginContact:contact with:bo1];
    }    
}
void PhysicContactListener::EndContact(b2Contact* contact) {
    id bo1 = (__bridge id)contact->GetFixtureA()->GetBody()->GetUserData();
    id bo2 = (__bridge id)contact->GetFixtureB()->GetBody()->GetUserData();    
    if ([bo1 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo1 endContact:contact with:bo2];
    }
    if ([bo2 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo2 endContact:contact with:bo1];
    }
}
void PhysicContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) {
    id bo1 = (__bridge id)contact->GetFixtureA()->GetBody()->GetUserData();
    id bo2 = (__bridge id)contact->GetFixtureB()->GetBody()->GetUserData();
    if ([bo1 isNotEmpty] && [bo1 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo1 preSolve:contact oldManifold:(b2Manifold*)oldManifold with:bo2];
    }
    if ( [bo2 isNotEmpty] && [bo2 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
        [bo2 preSolve:contact oldManifold:(b2Manifold*)oldManifold with:bo1];
    }
}

void PhysicContactListener::PostSolve(b2Contact* c, const b2ContactImpulse* impulse) {

//    b2Log("contact ##############################################\n" );
//    b2Log("contact A=%d B=%d\n",c->GetChildIndexA(),c->GetChildIndexB() );
//    c->GetFixtureA()->Dump(0);
//    c->GetFixtureB()->Dump(0);
//    id bo1 = (__bridge id)contact->GetFixtureA()->GetBody()->GetUserData();
//    id bo2 = (__bridge id)contact->GetFixtureB()->GetBody()->GetUserData();
//    if ([bo1 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
//        [bo1 postSolve:contact :(b2ContactImpulse*)impulse with:bo2];
//    }else if ([bo2 conformsToProtocol:@protocol(ObjectContactSolveProtocol)]) {
//        [bo2 postSolve:contact :(b2ContactImpulse*)impulse with:bo1];
//    }   
}

// отключаем контакт
//void PreSolve(b2Contact* contact, const b2Manifold* oldManifold)
//{
//    b2WorldManifold worldManifold;
//    contact->GetWorldManifold(&worldManifold);
//    if (worldManifold.normal.y < -0.5f)
//    {
//        contact->SetEnabled(false);
//    }
//    
//}

#2
21:01, 23 авг. 2013

Та я их и использую, делал поп примеру из http://www.raywenderlich.com/606/box2d-tutorial-for-ios-how-to-us… ocos2d-iphone

#3
21:53, 23 авг. 2013

С отключенным world->SetAllowSleeping(false); все ок.

Box2DФорумОбщее

Тема в архиве.