Обнаружить начальное столкновение двух тел box2d без непрерывного столкновения - PullRequest
5 голосов
/ 24 января 2012

У меня есть несколько простых настроек box2d с прослушивателем контактов, например:

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

}

И мне нужно воспроизвести звук, когда два тела столкнулись. Однако эта реализация обнаруживает непрерывные столкновения, поэтому звук воспроизводится при касании тел. Мои знания о box2d и C ++ уже очень ограничены, есть ли простой способ обнаружить новое столкновение без обнаружения непрерывных столкновений?

Ответы [ 2 ]

0 голосов
/ 30 декабря 2013

У вас правильная основная идея, но она нуждается в некотором уточнении.

В вашем вызове BeginContact (...) у вас есть:

PLAYSOUND(COLLISION);

Вместо воспроизведения звука здесьчто вы должны сделать, это поставить в очередь какую-то другую систему для воспроизведения звука для этой конкретной пары.Установите в теге userdata ваших тел указатель на класс (или какой-либо другой идентификатор для отслеживания сущностей).Примерно так:

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

Последняя часть состоит в том, чтобы НЕ снова воспроизводить звук в течение короткого времени, даже если происходит столкновение.Вы можете сделать это путем создания секундомера или обратного отсчета с фиксированного времени в циклах обновления сущностей.

Было ли это полезно?

0 голосов
/ 10 апреля 2012

Сначала установите таймер как это ..

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

и в этом методе

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