Cocos2d删除b2Bodies

时间:2013-07-03 05:18:08

标签: cocos2d-iphone box2d collision-detection contact

我一直在尝试使用Ray Wenderlich教程在cocos2d中进行碰撞检测,但每当我试图销毁b2Body时,只要对象发生碰撞,我就会得到inline b2Body* b2Fixture::GetBody() { return m_body; }。我看过类似的问题,但似乎没有一个对我有用。这是我的tick方法;问题始于" 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);
    }
}

这部分代码看起来正确,但后来我在样板文件中得到错误&#34; stl_function.h&#34;说&#34;二进制表达式的操作数无效(&#39; const MyContact&#39;和&#39; const MyContact&#39;)&#34;它说它在我的联系人监听文件中找到了:

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

2 个答案:

答案 0 :(得分:0)

仅在两个步骤之间移除实体。在时间步长期间调用碰撞回调,因此您应该记住要移除的某些实体(例如,添加到全局数组),然后在下一步销毁它们。更多细节there

答案 1 :(得分:0)

为了使用std :: set,您的元素将由键(如地图)存储。所以你需要定义&lt;运营商。 Look for more information.

类似的东西:

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代码修改为您的销毁。

这有用吗?