-1

我有两个精灵:一个是角色精灵,另一个是障碍精灵。障碍精灵是另一个名为 bgSprite 的精灵的子精灵,它不断移动。我如何检测它们之间的碰撞。我正在使用 CGRECTINTESECTRECT,但它看起来并不现实。我听说过box2d,但我还没有使用它。这是一些代码:

[[CCSpriteFrameCache sharedSpriteFrameCache]     
addSpriteFramesWithFile:@"BoyRunAnimation.plist"];

CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode     
batchNodeWithFile:@"BoyRunAnimation.png"];
[self addChild:spriteSheet];        

self._character = [CCSprite spriteWithSpriteFrameName:@"Boy_Run_0003.png"];
self._character.position = ccp(80, 150);
[spriteSheet addChild:self._character];
[self boyRunningAnimation]; 

//障碍

for (int i=0; i<5; i++)
{
int xPos=500+500*i;
if (xPos<2*_roadImage1.contentSize.width)
{
    CCSprite *obstacle=[CCSprite node];
    obstacle.textureRect=CGRectMake(0, 0, 50, _roadImage1.contentSize.height);
    obstacle.color=ccc3(255, 255,255);

    if (xPos <= _roadImage1.contentSize.width)
    {
        obstacle.position=ccp(xPos, _roadImage1.contentSize.height/2);

        [_roadImage1 addChild:obstacle z:0 tag:1];
    }
    else
    {
        obstacle.position=ccp(xPos-_roadImage1.contentSize.width, 60);

        [_roadImage2 addChild:obstacle z:0 tag:2];
    }
    [obstacleArray addObject:obstacle];
 }    
 }

在更新方法中:

  CCRect obstacleBox = [obstacle boundingBox];
  CCPoint obstaclePosition = obstacleBox.origin;
  obstaclePosition = [[obstacle parent] convertToWorldSpace:obstaclePosition];
  obstaclePosition = [[self._character parent] convertToNodeSpace:obstaclePosition];
  obstacleBox.origin = obstaclePosition;
  if (CGRectIntersectsRect(self._character.boundingBox, obstacleBox))
  {
    isTouchActive=NO;
    NSLog(@"collision");
   }

请帮我。

4

2 回答 2

1

如果您使用的是 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 并且用户标签指向根类(称为实体)。它会累积一个冲突列表并检查每个新事件是否引用了已经看到的一对,从而过滤掉重复项。在世界更新 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());
       */
   }
};

这个有帮助吗?

于 2013-11-10T11:35:19.373 回答
0

在 COCOS2D-X

首先,你已经为你的精灵制作了身体。并根据精灵移动身体。

您必须使用 b2contactlistener 扩展您的课程。它几乎没有您必须在代码中实现的方法。您可以阅读这篇文章,了解使用 Cocos2D-X 进行碰撞检测的 clerarity Box2D | Cocos2d-x

于 2013-11-13T06:24:29.557 回答