c++cocos2d-xcocos2d-x-3.x

How to check for specific collisions in cocos2d-x v3.1? C++


I'm attempting to check for specific collisions between sprites with Physics bodies. The problem is that I don't know how to assign either a tag to each node physics body or set the collision bitmask properly for each sprite. I am successfully checking for collisions but it's only a true or false for all objects.

I'm following a guide in the cocos2d-x documentation that I've linked below. In it, it explains how to set masking bits and masking categories.

Collision filtering allows you to prevent collision between shapes. Cocos2d-x >supports collision filtering using category and groups bitmasks.

Cocos2d-x supports 32 collision categories. For each shape you can specify which category it belongs to. You also specify what other categories this shape can collide with. This is done with masking bits

The problem is that when I set:

sprite1->getPhysicsBody()->setCategoryBitmask(0x02); // 0010 sprite1->getPhysicsBody()->setCollisionBitmask(0x01); // 0001

There isn't collision detection for those sprites. But when I set:

invaderPhysicsBody->setContactTestBitmask(true);

There is a collision detection.

Does anybody know how to successfully set the collision bitmask or category bitmask?

Objects with possible collisions:

  1. Vector of sprites for invaders.
  2. Vector of player missiles
  3. Vector of invader missiles
  4. Sprite for player
  5. Four sprites for shields

This is my onContactBegin function that will remove the Node once they collide. This is where I need to test which objects collided.

bool Gameplay::onContactBegin(PhysicsContact &contact) {
    std::cout << "onContactBegin -------> " << std::endl;
    player_score += 10;

    auto nodeA = contact.getShapeA()->getBody()->getNode();
    auto nodeB = contact.getShapeB()->getBody()->getNode();

    std::cout << contact.getShapeA()->getTag() << std::endl;

    if ((contact.getShapeA()->getCategoryBitmask() & contact.getShapeB()->getCollisionBitmask()) == 0
        || (contact.getShapeB()->getCategoryBitmask() & contact.getShapeA()->getCollisionBitmask()) == 0)
    {
        std::cout << "Overlap!" << std::endl;
    }
    nodeA->removeFromParent();
    nodeB->removeFromParent();

    return true;
}

Here is my collision listener:

 // Enable collision listener.
    auto contactListener = EventListenerPhysicsContact::create();
    contactListener->onContactBegin = CC_CALLBACK_1(Gameplay::onContactBegin, this);
    this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);

This is how I currently create and set the Physics bodies for my sprites:

int spacing = 0;
    // Four Player Shields
    for (int i = 0; i < 4; i++) {


        auto shield = Sprite::create("player_shield.png");

        auto shield_x = shield->getContentSize();
        auto shield_y = shield->getContentSize();
        auto shieldPhysicsBody = PhysicsBody::createBox(Size(shield_x.width,shield_y.height), PHYSICSBODY_MATERIAL_DEFAULT);

        shieldPhysicsBody->setContactTestBitmask(true);
        shieldPhysicsBody->setDynamic(true);
        shieldPhysicsBody->setTag(0);

        shield->setPosition(Vec2(200 + spacing, 150));

        shield->addComponent(shieldPhysicsBody);
        this->addChild(shield);
        spacing += 200;
    }

Here is the guide I've been following.


Solution

  • There is a big mistake in your code. setContactTestBitmask accept a int rather than bool. When you call shieldPhysicsBody->setContactTestBitmask(true), it's actually shieldPhysicsBody->setContactTestBitmask(0x0000001). And 0x000001 & 0x000010 = 0, so no contact event will be raised. The & result of spriteA's categoryBitmask and spriteB's ContactTestBitmask determines whether a contact event will be raised. BTW, generally speaking, you don't need check contaction manually, ie:

    if ((contact.getShapeA()->getCategoryBitmask() & contact.getShapeB()->getCollisionBitmask()) == 0
        || (contact.getShapeB()->getCategoryBitmask() & contact.getShapeA()->getCollisionBitmask()) == 0)
    {
        std::cout << "Overlap!" << std::endl;
    }