3
votes

I am detecting contacts from a ball and two edges of the screen (left and right one) For that purpose I created: – SKSpriteNode *ball – SKNode *leftEdge – SKNode *rightEdge

Here I am setting up the bit masks

static const uint32_t kCCBallCategory       = 0x1 << 0;
static const uint32_t kCCEdgeCategory       = 0x1 << 1;

Here I am adding the edges

leftEdge.physicsBody = [SKPhysicsBody bodyWithEdgeFromPoint:CGPointZero toPoint:CGPointMake(0.0, self.size.height)];
leftEdge.position = CGPointZero;
leftEdge.physicsBody.categoryBitMask = kCCEdgeCategory;
[self addChild:leftEdge];

Right edge is added exactly the same, except it has different name and position is set to

rightEdge.position = CGPointMake(self.size.width, 0.0);

Here I am configuring and adding the ball

ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:6.0];
ball.physicsBody.categoryBitMask = kCCBallCategory;
ball.physicsBody.collisionBitMask = kCCEdgeCategory;
ball.physicsBody.contactTestBitMask = kCCEdgeCategory;
[_mainLayer addChild:ball];

Later in didBeginContact I am checking if first body is the ball and the second body is the edge and adding some explosion to it

SKPhysicsBody *firstBody;
SKPhysicsBody *secondBody;
if (firstBody.categoryBitMask == kCCBallCategory && secondBody.categoryBitMask == kCCEdgeCategory) {
        // Collision between ball and the edge
        [self addExplosion:contact.contactPoint withName:@"BallEdgeBounce"];
    }

And the strange thing is – when the ball hits the left edge - code works fine and explosion effect added to the scene. But the right edge wont do the same. It came by surprise for me, because collisions works just fine. So why does the right edge behave like that? How do I fix this?

You could look at the project on the github, settings is done in GameScene.m file https://github.com/Fenkins/Space-Cannon

3

3 Answers

2
votes

I've looked into your Git project and this is happening because you have wrongly set category for rightEdge ( to be more precise, you haven't set it at all). You should do something like this:

SKNode *rightEdge = [[SKNode alloc]init];
rightEdge.physicsBody = [SKPhysicsBody bodyWithEdgeFromPoint:CGPointZero toPoint:CGPointMake(0.0, self.size.height)];
rightEdge.position = CGPointMake(self.size.width, 0.0);
// leftEdge.physicsBody.categoryBitMask = kCCEdgeCategory;//Error when copy/pasting ;-)
rightEdge.physicsBody.categoryBitMask = kCCEdgeCategory;
[self addChild:rightEdge];
0
votes

You might have missed a simple practice carried out in the didBeginContact: method, of assigning the first and second bodies based on their categoryBitMask values.

-(void)didBeginContact:(SKPhysicsContact *)contact {
    SKPhysicsBody *firstBody;
    SKPhysicsBody *secondBody;

    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    } else {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }
    ...
}

This needs to be done because there is no guarantee which body will be the first or the second.

0
votes

This is a different direction than where you seem to be going with your app, but it works.

SKSpriteNode *edgeLeft = [SKSpriteNode spriteNodeWithColor:[SKColor clearColor] size:CGSizeMake(1, self.frame.size.height)]; edgeLeft.physicsBody.collisionBitMask = kCCEdgeCategory; edgeLeft.position = CGPointMake(3, self.frame.size.height / 2); [self addChild:edgeLeft];

Then do the same for the top edge.

Hope this helped.