0
votes

Hello fellow developers,

I am new to Sprite Kit and just started implementing physics into my game. I only have two sprites that need to come into contact. One is the main character, a butterfly "bfly" and the other is an energy ball which gives health to the main character upon contact.

Something strange is occurring in my game however, even though I implemented all of my lines for the physics to work, sometimes, upon certain conditions that I do not understand, the energy ball just goes right through the main character and ignores that a contact and the effects that contact implements should occur. Then I have to actively seek the energy ball so that it happens and try touching it various times to be successful.

I want contact to always occur, no matter if the energy accidentally ran into me, or I actively seek it out. When those two sprites touch each other in any way contact should occur. I tried everything, and finally decided to ask for help.

Here is my delegate:

@interface CloudScene () <SKPhysicsContactDelegate>

Notice that I added these properties in hopes of fixing issue, but issue was there before them:

@property(assign, nonatomic) uint32_t contactTestBitMask;
@property(nonatomic) BOOL usesPreciseCollisionDetection;

static const uint32_t bflyCategory = 0x1 << 0;
static const uint32_t energyCategory = 0x1 << 1;

initWithSize method:

self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;

Physics of both (notice collisions were set to 0 before and issue still existed, I only added them in hopes that the bouncing effect would at least not let ball go right through bfly character but didn't work) :

    _bfly.name = @"bflyNode";
    _bfly.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_bfly.frame.size];
    _bfly.physicsBody.categoryBitMask = bflyCategory;
    _bfly.physicsBody.contactTestBitMask = energyCategory;
    _bfly.physicsBody.collisionBitMask = bflyCategory | energyCategory;
    _bfly.physicsBody.usesPreciseCollisionDetection = YES;
    _bfly.physicsBody.dynamic = YES;
    _bfly.physicsBody.affectedByGravity = NO;
    _bfly.physicsBody.mass = 1;


energyball.name = @"energyballNode";
energyball.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:energyball.frame.size];
energyball.physicsBody.categoryBitMask = energyCategory;
energyball.physicsBody.contactTestBitMask = bflyCategory;
energyball.physicsBody.collisionBitMask = energyCategory | bflyCategory;
energyball.physicsBody.usesPreciseCollisionDetection = YES;
energyball.physicsBody.dynamic = YES;
energyball.physicsBody.affectedByGravity = NO;
energyball.physicsBody.mass = 1;

And finally here is my didBeginContact Method:

-(void)didBeginContact:(SKPhysicsContact *)contact{

SKPhysicsBody *bfly;
SKPhysicsBody *energyball;

if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
    bfly = contact.bodyA;
    energyball = contact.bodyB;
}
else
{
    bfly = contact.bodyB;
    energyball = contact.bodyA;
}

if ((bfly.categoryBitMask & bflyCategory) != 0)
{

    SKNode * energyball = (contact.bodyA.categoryBitMask & bflyCategory) ? contact.bodyB.node : contact.bodyA.node;
    SKAction*energySound = [SKAction playSoundFileNamed:@"Energybell.m4a" waitForCompletion:NO];
    [energyball runAction:energySound];
    energyball.hidden = YES;
    [self addChild:[self FenergyNode:@"energy"]];
    [self adjustScoreBy:2];
    [scoreLabel setText: [NSString stringWithFormat:@"Score: %d", [GameState sharedInstance].score]];
    _bflyHP =MAX(0, _bflyHP+100);
    [energyball runAction:[SKAction removeFromParent]];


}

}

Thanks in advance !

1

1 Answers

0
votes

I think you're shooting yourself in the foot with this line:

SKNode * energyball = (contact.bodyA.categoryBitMask & bflyCategory) ?
                                            contact.bodyB.node : contact.bodyA.node;

If I understand your code correctly, energy balls categoryBitMask is never set to the bflyCategory. Hence you are always selecting bodyA's node. Since A and B can change at any time relying on the energyBall always being bodyA is prone to fail at some point.

Moreover you already selected SKPhysicsBody* energyBall earlier, which you should have used instead. Which should also bring up a compiler warning like "x shadows local variable y" because they use the same identifier (variable name).

Try replacing the line above with this:

SKNode* ball = energyball.node;

And change any uses of SKNode* energyball to ball.