Sprite Kit Node not detecting collision and not bouncing

3.1k views Asked by At

Following RayWenderlich tutorial i'm having some problem to be able to create a block that makes the bullet bounce in it. But the most disgunting thing is not to be able to detect the collision between the bullet and the brick. Now the bullet pass the brick like it doesn't exist.

Here is the definition of bullet and brick: Bullet:

    bullet = [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:kBulletSize];
    bullet.name = kShipFiredBulletName;
    bullet.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bullet.frame.size];
    bullet.physicsBody.dynamic = YES;
    bullet.physicsBody.restitution = 1.0;
    bullet.physicsBody.affectedByGravity = NO;
    bullet.physicsBody.categoryBitMask = kShipFiredBulletCategory;
    bullet.physicsBody.contactTestBitMask = kInvaderCategory;
    bullet.physicsBody.collisionBitMask = 0x0;

Brick:

SKNode* rebote;

rebote = [SKSpriteNode spriteNodeWithColor:[SKColor orangeColor] size:kBouncetSize];
rebote.position = CGPointMake(550, 500);
rebote.name = @"kBounceBlock";
rebote.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rebote.frame.size];
rebote.physicsBody.restitution = 1.0;
rebote.physicsBody.friction = 0.0;
rebote.physicsBody.dynamic = NO;
rebote.physicsBody.affectedByGravity = YES;
rebote.physicsBody.categoryBitMask = kShipFiredBulletCategory;
rebote.physicsBody.contactTestBitMask = kInvaderCategory;
rebote.physicsBody.collisionBitMask = 0x0;

[self addChild:rebote];

And here the collision detection method :

-(void)handleContact:(SKPhysicsContact*)contact
{
    // Ensure you haven't already handled this contact and removed its nodes
    if (!contact.bodyA.node.parent || !contact.bodyB.node.parent)
        return;

    NSArray* nodeNames = @[contact.bodyA.node.name, contact.bodyB.node.name];
    if ([nodeNames containsObject:kShipName] && [nodeNames containsObject:kInvaderFiredBulletName])
    {
        // Invader bullet hit a ship
        [self runAction:[SKAction playSoundFileNamed:@"ShipHit.wav" waitForCompletion:NO]];
        //1
        [self adjustShipHealthBy:-0.334f];

        if (self.shipHealth <= 0.0f)
        {
            //2
            [contact.bodyA.node removeFromParent];
            [contact.bodyB.node removeFromParent];
        }
        else
        {
            //3
            SKNode* ship = [self childNodeWithName:kShipName];
            ship.alpha = self.shipHealth;

            if (contact.bodyA.node == ship)
                [contact.bodyB.node removeFromParent];
            else
                [contact.bodyA.node removeFromParent];
        }
    }
    else if ([nodeNames containsObject:kInvaderName] && [nodeNames containsObject:kShipFiredBulletName])
    {
         NSLog(@"Contacto entre bala e Invader.");

        // Ship bullet hit an invader
        [self runAction:[SKAction playSoundFileNamed:@"InvaderHit.wav" waitForCompletion:NO]];
        [contact.bodyA.node removeFromParent];
        [contact.bodyB.node removeFromParent];
        //4
        [self adjustScoreBy:100];
    }

    if ([nodeNames containsObject:@"kBounceBlock"])
        NSLog(@"Contacto entre el cuerpo naranja !!");
}

Whaat i'm doing wrong ? I defined the restitution property in bullet and in the brick too. The brick is not dynamic and both are in the same 'collisionBitMask'.

I'm pretty lost. Thanks in advance

2

There are 2 answers

3
Andrey Gordeev On BEST ANSWER

Set up proper contactTestBitMask and collisionBitMask for Brick and Bullet.

For some reasons you have collisionBitMask set to 0x0, which means that node will not collide with any object at all.

Also, you have specified a wrong categoryBitMask for Brick (the same as for Bullet). You should create a separate category for it:

bullet.physicsBody.categoryBitMask = kShipFiredBulletCategory;
bullet.physicsBody.contactTestBitMask = kBrickCategory;
bullet.physicsBody.collisionBitMask = kBrickCategory;


rebote.physicsBody.categoryBitMask = kBrickCategory;
rebote.physicsBody.contactTestBitMask = kShipFiredBulletCategory;
rebote.physicsBody.collisionBitMask = kShipFiredBulletCategory;
0
jemmons On

The categoryBitMask is where you assign the category (or categories) a node "belongs" to. The contactTestBitMask is where you let a node know which other nodes it should fire a -handleContact: for when it collides with them.

You're giving both the nodes above a contactTestBitMask of kInvaderCategory. That means if either of these nodes collides with a node that has a categoryBitMask of kInvaderCategory, their -handleContact: method will be called. But none of your nodes have a categoryBitMask of kInvaderCategory, so that will never happen.

If you were, for example, to give your rebote node a contactTestBitMask of kShipFiredBulletCategory, then it would call -handleContact: whenever the bullet node collided with it because the bullet node has a categoryBitMask of kShipFiredBulletCategory.