2012-01-23 14 views
5

mam trochę ciał prostych box2d konfigurację z detektorem kontaktowym tak:Detect początkowego zderzenia dwóch ciał box2d bez ciągłej kolizji

#import "MyContactListener.h" 

MyContactListener::MyContactListener() : _contacts() { 
} 

MyContactListener::~MyContactListener() { 
} 

void MyContactListener::BeginContact(b2Contact* contact) { 
// We need to copy out the data because the b2Contact passed in 
// is reused. 
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; 
_contacts.push_back(myContact); 


b2Body *A = contact->GetFixtureA()->GetBody(); 
b2Body *B = contact->GetFixtureA()->GetBody(); 

NSLog(@"Collision detected!"); 
PLAYSOUND(COLLISION); 

} 

void MyContactListener::EndContact(b2Contact* contact) { 
    MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() }; 
    std::vector<MyContact>::iterator pos; 
    pos = std::find(_contacts.begin(), _contacts.end(), myContact); 
    if (pos != _contacts.end()) { 
     _contacts.erase(pos); 
     } 
} 

void MyContactListener::PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { 

} 

void MyContactListener::PostSolve(b2Contact* contact, const b2ContactImpulse* impulse) { 

} 

I muszę odtworzyć dźwięk, gdy dwa ciała zderzyły. Jednak ta implementacja wykrywa ciągłe kolizje, więc dźwięk jest odtwarzany, gdy ciała się dotykają. Moja znajomość box2d i C++ jest już bardzo ograniczona, czy istnieje prosty sposób na wykrycie nowej kolizji bez wykrycia ciągłych kolizji?

+0

Proponuję, aby przejść [tutorial] (http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone), aby będzie w stanie wykryć pojedynczą kolizję – Marine

+0

"Gdy zderzą się dwa ciała" = Rozpocznij kontakt. To nie jest ciągła rzecz, dlatego nazywa się "Begin" :) – iforce2d

Odpowiedz

-1

Najpierw ustawić timer tak ..

[self schedule:@selector(check collision:)]; 

iw ten sposób

- (void)tick:(ccTime) dt 
    { 

     for(b2Body *b = _world->GetBodyList(); b; b=b->GetNext()) 
      { 
      //--------------My contact Listener Start------------------------- 


       std::vector<MyContact>::iterator pos; 

       for(pos = _contactListener->_contacts.begin(); pos != _contactListener->_contacts.end(); ++pos) 
        { 
         MyContact contact = *pos; 

      // Here get your sprite and make their fixture and check... 

         if ((contact.fixtureA == tempballFixture && contact.fixtureB == _mainballFixture) || 
          (contact.fixtureA == _mainballFixture && contact.fixtureB == tempballFixture)) 
         { 
          if(mainDelegate.music_playing == TRUE) 
          { 
          [[SimpleAudioEngine sharedEngine] playEffect:@"Rock impact.mp3"]; 
          } 
          //-------------collision count for update score value-------- 
        } 
      } 
0

masz prawo podstawowe pojęcia, ale to wymaga pewnego dopracowania.

W swojej BeginContact (...) połączenia, trzeba:

PLAYSOUND(COLLISION); 

Zamiast grać dźwięk tu, co należy zrobić, to enqueue jakiś inny system do odtwarzania dźwięku dla danej pary. Ustaw znacznik userdata swoich ciał na wskaźnik do klasy (lub inny identyfikator do śledzenia obiektów). Tak:

class EntityContactListener : public ContactListener 
{ 
private: 
    GameWorld* _gameWorld; 
    EntityContactListener() {} 

    typedef struct 
    { 
     Entity* entA; 
     Entity* entB; 
    } CONTACT_PAIR_T; 

    vector<CONTACT_PAIR_T> _contactPairs; 

public: 
    virtual ~EntityContactListener() {} 

    EntityContactListener(GameWorld* gameWorld) : 
     _gameWorld(gameWorld) 
    { 
     _contactPairs.reserve(128); 
    } 

    void NotifyCollisions() 
    { 
     Message* msg; 
     MessageManager& mm = GameManager::Instance().GetMessageMgr(); 

     for(uint32 idx = 0; idx < _contactPairs.size(); idx++) 
     { 
     Entity* entA = _contactPairs[idx].entA; 
     Entity* entB = _contactPairs[idx].entB; 

     //DebugLogCPP("Contact Notification %s<->%s",entA->ToString().c_str(),entB->ToString().c_str()); 

     msg = mm.CreateMessage(); 
     msg->Init(entA->GetID(), entB->GetID(), Message::MESSAGE_COLLISION); 
     mm.EnqueueMessge(msg, 0); 

     msg = mm.CreateMessage(); 
     msg->Init(entB->GetID(), entA->GetID(), Message::MESSAGE_COLLISION); 
     mm.EnqueueMessge(msg, 0);   
     } 
     _contactPairs.clear(); 
    } 

    void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) 
    { 

    } 

    // BEWARE: You may get multiple calls for the same event. 
    void BeginContact(b2Contact* contact) 
    { 
     Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData(); 
     Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData(); 
     //DebugLogCPP("Begin Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str()); 
     if(entA->GetGroupID() == entB->GetGroupID()) 
     { // Can't collide if they are in the same group. 
     return; 
     } 

     assert(entA != NULL); 
     assert(entB != NULL); 

     for(uint32 idx = 0; idx < _contactPairs.size(); idx++) 
     { 
     if(_contactPairs[idx].entA == entA && _contactPairs[idx].entB == entB) 
      return; 
     // Not sure if this is needed... 
     if(_contactPairs[idx].entA == entB && _contactPairs[idx].entA == entB) 
      return; 
     } 
     CONTACT_PAIR_T pair; 
     pair.entA = entA; 
     pair.entB = entB; 
     _contactPairs.push_back(pair); 
    } 

    // BEWARE: You may get multiple calls for the same event. 
    void EndContact(b2Contact* contact) 
    { 
     /* 
     Entity* entA = (Entity*)contact->GetFixtureA()->GetBody()->GetUserData(); 
     Entity* entB = (Entity*)contact->GetFixtureB()->GetBody()->GetUserData(); 
     DebugLogCPP("End Contact %s->%s",entA->ToString().c_str(),entB->ToString().c_str()); 
     */ 
    } 
}; 

Ostatnia część tego celu jest NIE grać ponownie dźwięk przez krótki czas nawet jeśli wystąpi kolizja. Możesz to zrobić, tworząc stoper lub odliczając od ustalonego czasu w cyklach aktualizacji jednostki.

Czy było to pomocne?