2012-01-23 9 views
5

ho qualche semplice configurazione corpi box2d con un listener contatto in questo modo:Rileva collisione iniziale di due corpi box2d senza collisioni continua

#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) { 

} 

E ho bisogno di riprodurre un suono quando due corpi si sono scontrati. Tuttavia, questa implementazione rileva continue collisioni in modo che il suono venga riprodotto quando i corpi si toccano. La mia conoscenza di box2d e C++ è già molto limitata, c'è un modo semplice per rilevare una nuova collisione senza rilevare collisioni continue?

+0

Ti suggerisco di passare attraverso [tutorial] (http://www.raywenderlich.com/606/how-to-use-box2d-for-just-collision-detection-with-cocos2d-iphone) in modo che tu sarebbe in grado di rilevare una singola collisione – Marine

+0

"Quando due corpi sono entrati in collisione" = BeginContact. Questa non è una cosa continua, è per questo che si chiama 'Begin' :) – iforce2d

risposta

-1

Prima impostare un timer come questo ..

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

e in questo metodo

- (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

Hai l'idea di base a destra, ma ha bisogno di una certa raffinatezza.

nella chiamata BeginContact (...), si ha:

PLAYSOUND(COLLISION); 

Invece di giocare il suono qui, che cosa si dovrebbe fare è enqueue qualche altro sistema per riprodurre l'audio per questa particolare coppia. Imposta il tag userdata dei tuoi corpi sul puntatore alla classe (o qualche altro ID per tenere traccia delle entità). In questo modo:

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()); 
     */ 
    } 
}; 

L'ultima parte di questo è quello NON giocare di nuovo il suono per un breve periodo di tempo, anche se si verifica una collisione. È possibile farlo creando un cronometro o il conto alla rovescia da un tempo fisso nei cicli di aggiornamento dell'entità.

Era utile?

Problemi correlati