在没有连续碰撞的情况下检测两个box2d物体的初始碰撞

时间:2012-01-23 20:26:49

标签: cocos2d-iphone box2d physics

我有一些简单的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 :(得分:0)

你有正确的基本想法,但需要进行一些改进。

在您的BeginContact(...)调用中,您有:

PLAYSOUND(COLLISION);

不是在这里播放声音,而是应该做的是将其他系统排入队列以播放此特定对的声音。将您的实体的userdata标记设置为指向该类的指针(或一些其他ID以跟踪实体)。像这样:

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

最后一部分是 NOT 即使发生碰撞也会在短时间内再次播放声音。您可以通过创建秒表或从实体更新周期的固定时间倒计时来完成此操作。

这有用吗?

答案 1 :(得分:-1)

首先设置这样的计时器..

   [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--------
                  }
          }