3

我是 Cocos2D 世界的初学者,更是 Box2D 的初学者。我正在使用这两个引擎开发一个 iOS 游戏,我想要的是让一个人(英雄)在滚动地图中捡起硬币。

好吧,问题是“联系侦听器”。我似乎无法理解它的真正作用,以及如何使用它来区分我的硬币和地图周围的其他物体(都是静态物体)。我设置了所有硬币.isSensor = true以禁用碰撞。我正在使用来自raywenderlich.com教程的 MyContactListener。

所以,主要的问题是:如何通过接触监听器知道是什么类型的身体与英雄的身体发生碰撞?

(我在这里阅读了很多教程和问题,我似乎不知道从哪里开始)

谢谢!

编辑:

Si,我终于让它与 sprite.tag 一起工作,但我无法破坏身体和纹理。有时在使用时[textureB removeFromParentAndCleanup:YES];我会得到EXC_BAD_ACCESS. 据我了解,我不能破坏身体,因为我实际上是在使用它。

但是当试图body->SetUserData(self);在我的英雄类中使用时

@interface Hero : CCNode {
CCSprite * texture;
CGPoint position;
b2Body* body;
TypeCase type;
}

我进入EXC_BAD_ACCESS我的更新方法:

for(b2Body *b = world_->GetBodyList(); b; b=b->GetNext()) {
    if (b->GetUserData() != NULL) {
        if ([b->GetUserData() isKindOfClass:[Hero class]])
        {
            Hero* hero = (Hero*)b->GetUserData();
            CCSprite *heroSprite = hero.texture;
            heroSprite.position = ccp(b->GetPosition().x * PTM_RATIO,
                                b->GetPosition().y * PTM_RATIO);
        }
        else if ([b->GetUserData() isKindOfClass:[Tile class]])
        {
            Tile* tile = (Tile*)b->GetUserData();
            CCSprite *tileSprite = tile.texture;
            tileSprite.position = ccp(b->GetPosition().x * PTM_RATIO,
                                b->GetPosition().y * PTM_RATIO);
        }       
    }
}

我在调用 isKindOfClass 时得到 EXC_BAD_ACCESS。

英雄用户数据

b2BodyDef heroBodyDef;
heroBodyDef.fixedRotation = true;
heroBodyDef.type = b2_dynamicBody;
heroBodyDef.position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
body = world_->CreateBody(&heroBodyDef);
body->SetUserData(self);

平铺用户数据

b2BodyDef blockBodyDef;
blockBodyDef.type = b2_staticBody;
blockBodyDef.position.Set(position.x/PTM_RATIO, position.y/PTM_RATIO);
blockBodyDef.userData = self;
b2Body *body = world ->CreateBody(&blockBodyDef);
4

2 回答 2

3

不要对硬币使用物理对象.. 这会影响 fps :) 为硬币创建 CCSprite 并检测与硬币精灵和 body->UserData 的碰撞;在 CCArray 中添加你的硬币并在你的更新方法中写下这样的内容:

CCSprite *sprite = (CCSprite*)yourObject.body->GetUserData();
Coins *coinObject;
CCARRAY_FOREACH(coinsArray, coinObject)
   {
     if (CGRectIntersectsRect([sprite boundingBox], [coinObject boundingBox]))
       {
         // collision detected;
       }
   }

如果你想为你的硬币使用物理体,你需要为你的对象状态创建 typedef,并在你的联系监听void ContactListener::EndContact(b2Contact* contact)器方法中更改你的对象 currentState。currentState 是 yourObject 的属性。做这样的事情void ContactListener::EndContact(b2Contact* contact)

yourObject.currentState = isCollideOnCoin;

然后在你的更新中添加这一行:

if (yourObject.currentState == isCollideOnCoin)
{
 // collision detected;
}
于 2013-08-12T10:44:52.023 回答
2

您可以创建一个自定义类(例如BodyType),它指示身体类型(在您的情况下是玩家/硬币)

然后您可以在您创建的身体上使用用户数据属性:

playerBody->SetUserData(new BodyType(1));
coinBody->SetUserData(new BodyType(2));

在联系侦听器中有一个名为的方法,它有一个名为beginContact的参数。b2Contact*contact

使用此参数获取两个主体:

b2Body* bodyA = contact->GetFixtureA()->GetBody();
b2Body* bodyB = contact->GetFixtureB()->GetBody();

然后你可以通过检查来知道你的玩家是否击中硬币:

if ((bodyA->GetUserData().getType() == 1 && bodyB->GetUserData().getType() == 2) ||
    (bodyA->GetUserData().getType() == 2 && bodyB->GetUserData().getType() == 1)) {
   // Mark collision or save coin body in a member of your contact listener for removing it later
}
  • 当然,请确保用户数据不为空,因为所有主体都将传递给联系人侦听器,并且并非所有人都可能设置了用户数据成员。

编辑

关于 BAD_ACCESS,请执行以下操作:

 if (b->GetUserData() != NULL) {
     id myUserData = (id)b->GetUserData();

     if ([myUserData isKindOfClass:[Hero class]])
     { 
        Hero *hero = (Hero *)myUserData;
        // Do your stuff
     }
 }
于 2013-08-12T13:38:37.693 回答