Тёмная тема
Здравствуйте. Я новичок в 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"]; }
Проблема в том, что столкновения не всегда срабатывают, например если сблизить оба объекта почти впритык, потом отодвинуть и снова придвинуть, то коллизия уже не сработает. С первого раза работает хорошо.
используй события контакт листера
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); // } // //}
Та я их и использую, делал поп примеру из http://www.raywenderlich.com/606/box2d-tutorial-for-ios-how-to-us… ocos2d-iphone
С отключенным world->SetAllowSleeping(false); все ок.
Тема в архиве.