0

我一直在尝试使用 Ray Wenderlich 教程在 cocos2d 中进行碰撞检测,但是每当我尝试破坏 b2Bodyinline b2Body* b2Fixture::GetBody() { return m_body; }时,只要对象发生碰撞,我就会得到。我看过类似的问题,但似乎没有一个对我有用。这是我的勾选方法;问题从“std::vector”开始,运行正常之前的代码,只是检测到两个物体之间的碰撞并破坏两个 b2Bodies 每次都会给我一个错误:`

(void)tick:(ccTime) dt {
    _world->Step(dt, 10, 10);
    ...some code that works fine...then here when trying to delete the bodies:
    std::set<b2Body *>toDestroy;
std::set<MyContact>::iterator pos;
for(pos = _contactListener->_contacts.begin();
    pos != _contactListener->_contacts.end(); ++pos) {
    MyContact contact = *pos;
    bodyA = contact.fixtureA->GetBody();
    bodyB = contact.fixtureB->GetBody();
    if (bodyA->GetUserData() != NULL && bodyB->GetUserData() != NULL) {
        spriteA = (__bridge CCSprite *) bodyA->GetUserData();
        spriteB = (__bridge CCSprite *) bodyB->GetUserData();
            if (((spriteA.tag == 411 || spriteA.tag == 412) && spriteB.tag == 8))
            {
                //Remove CCSprites
                [self removeBall];
                for(CCSprite *tile4 in row4){
                    [self removeTiles];
                    [row4 removeObject:tile4];
                    [childrenToDestroy addObject:tile4];
                }

                //Remove b2bodies by adding them to array
                toDestroy.insert(bodyA);
                toDestroy.insert(bodyB);
            }
    }
}
std::set<b2Body *>::iterator pos2;
for(pos2 = toDestroy.begin(); pos2 != toDestroy.end(); ++pos2) {
    b2Body *body = *pos2;
    if (body->GetUserData() != NULL)
    {
        body->SetActive(false);
        _world->DestroyBody(body);
    }
}

这部分代码看起来是正确的,但随后我在样板文件“ stl_function.h”中收到一个错误,提示“二进制表达式的操作数无效('const MyContact' 和 'const MyContact') ”并且它说它在我的联系人监听器中找到文件:

#import "MyContactListener.h"

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

MyContactListener::~MyContactListener() {
}

void MyContactListener::BeginContact(b2Contact* contact) {
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
_contacts.insert(myContact);  <------------//Says "7.In instantiation of member function 'std::set<MyContact, std::less<MyContact>, std::allocator<MyContact> >::insert' requested here"
}

void MyContactListener::EndContact(b2Contact* contact) {
MyContact myContact = { contact->GetFixtureA(), contact->GetFixtureB() };
std::set<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) {
}
4

2 回答 2

0

为了使用 std::set,您的元素将通过键(如地图)存储。所以你需要定义 < 操作符。 寻找更多信息。

就像是:

struct Data
{
   int x;
   int y;

   bool operator<(const Data& rhs) const
   {
      return x < rhs.x;
   }

};

void InsertData(const Data& data)
{
   std::set<Data> dataSet;

   dataSet.insert(data);
}

我发现接触侦听器在碰撞解决过程中对同一个物体进行了多次“点击”。这导致了几个问题,因为实体多次收到有关碰撞的通知,它们被多次破坏,睡眠丢失等。

我编写了一个联系人监听器(如下),它会自动检查重复项并排除它们。这按预期工作:

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

在这个代码库中,有一个“MessageManager”接收在物理之后被调用的消息,并将处理碰撞消息,将它们传递给实体。如果您愿意,可以将 NotifyCollisions 代码修改为您的销毁。

这个有帮助吗?

于 2013-11-12T12:27:29.453 回答
0

仅在两个步骤之间移除实体。在时间步期间调用碰撞回调,因此您应该记住以某种方式删除物体(例如,添加到全局数组),然后在下一步销毁它们。那里有更多细节。

于 2013-07-03T10:46:42.727 回答