没有物理的碰撞(Cocos2D + Box2D iOS)

时间:2013-08-11 22:24:40

标签: ios cocos2d-iphone listener box2d contact

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

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

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

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

谢谢!

编辑:

Si,我终于让它与sprite.tag一起工作,但我不能破坏身体和纹理。有时使用[textureB removeFromParentAndCleanup:YES];时,我会EXC_BAD_ACCESS。 正如我所理解的那样,因为我实际上在使用它,所以我不能破坏它。

但是在我的Hero课程中尝试使用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。

Hero userData

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);

2 个答案:

答案 0 :(得分: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;
       }
   }

如果要将物理主体用于硬币,则需要为yourObject状态创建typedef,并在联系人侦听器void ContactListener::EndContact(b2Contact* contact)方法中更改yourObject currentState。 currentState是yourObject的属性。 在void ContactListener::EndContact(b2Contact* contact)

中执行类似的操作
yourObject.currentState = isCollideOnCoin;

然后在您的更新中添加以下行:

if (yourObject.currentState == isCollideOnCoin)
{
 // collision detected;
}

答案 1 :(得分: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
     }
 }