关节体中的碰撞检测

时间:2013-11-07 05:16:26

标签: box2d cocos2d-x

我创造了火车。它是组合(关节)矩形,轴,轮。我想检测与其他身体(星星或水果)的碰撞矩形。

任何想法或建议都应该对我有所帮助。

2 个答案:

答案 0 :(得分:0)

我最近给出了另一个问题的答案。我假设您使用box2d作为列车部件。

如果您使用的是box2d,则在处理世界更新时,会在Box2d引擎中处理碰撞检测。这可以检测身体上的固定装置之间的碰撞,而不是身体本身。因此,如果你的身体是由一组固定装置组成的,你可以检测到身体的一小部分(而不仅仅是边界矩形)。

简单的答案是从b2ContactListener派生一个类并告诉b2World你想要使用它。手册中的示例如下所示:

class MyContactListener : public b2ContactListener 
{
public:
void BeginContact(b2Contact* contact) { /* handle begin event */ }
void EndContact(b2Contact* contact) { /* handle end event */ }
void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { /* handle pre-solve event */ }
void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)
{ /* handle post-solve event */ } 
};

您在派生类的实例上使用b2World :: SetContactListener(...)注册它。

但是,它并不那么简单。我的经验是,对于单个“碰撞”,您可以在世界更新期间多次调用您的班级。因此,如果碰撞在碰撞检测阶段破坏了一个物体,那么在同一检测周期内发生其他事件时,您可能会遇到问题(死点?)。

以下是更完整的解决方案。在这里,世界上的每个“东西”都有一个b2Body,用户标签指向根类(称为Entity)。它累积了一个冲突列表并检查每个新事件是否引用了已经看到的一对,过滤掉了重复项。在更新世界更新后,会调用NotifyCollisions向发生冲突的实体发送消息,并且需要对其进行一些操作。

这是更大代码库的一部分;如果您需要澄清,请随时提出任何问题,因为代码不在此处。

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

这有用吗?

答案 1 :(得分:0)

您可以为该矩形体和您的其他身体(星形或水果)设置userdata。 您还必须扩展b2contactlistner(cocos2d-x)。哪个方法很少

void BeginContact(b2Contact* contact) { /* handle begin event */ } void EndContact(b2Contact* contact) { /* handle end event */ } void PreSolve(b2Contact* contact, const b2Manifold* oldManifold) { /* handle pre-solve event */ } void PostSolve(b2Contact* contact, const b2ContactImpulse* impulse)

其中一种方法是获取body userdata并检查你的列车身体userdat是否与其他bodydat碰撞。

例如

void HelloWorld::BeginContact(b2Contact* contact)
{
    b2Body * bodyA = contact->GetFixtureA()->GetBody();
    b2Body * bodyB = contact->GetFixtureB()->GetBody();
//  CCSprite sp1 = (CCSprite*)bodyA->GetUserData();
//  CCSprite sp2 = (CCSprite*)bodyB->GetUserData();
//  b2Body *b1 = (new Layerhero())->b1;
    CCLog("In the begincontact");

    if((bodyA == hero && bodyB == hero2))
{
    CCLog("In the begincontact1");
    boo = true;
}
else if ((bodyA == hero && bodyB == hero3))
{
    CCLog("In the begincontact2");
    boo = true;
}

}