Search code examples
iossprite-kitcollision-detectiongame-physicsskphysicsbody

SK Game - didBeginContact/didEndContact isn't getting called


I'm making a drag and drop game, and attempting to use physicsBodies to detect contacts between 1 static object and the object being dragged by the user.

I've searched on here for hours, and watched tutorials online, but all I keep seeing is contact detection working with dynamic nodes (such as projectiles). I don't need collisions because nothing happens to any of the nodes when they intersect, I just need contact detection to implement game logic.

I originally had a working solution using CGRectContainsPoint and CGRectContainsRect, but it's super buggy and after doing some research I realized that it's not the correct way to implement contact/collisions in SK.

I've got my bitMask setup like so:

//contact bit masks
typedef NS_OPTIONS(uint32_t, ContactCategory) {
    ContactCategoryTile     = 1 << 0,   //0000
    ContactCategoryKey      = 1 << 1,   //0010
    ContactCategoryRotor    = 1 << 2,   //0100
};

My selected node setup like so:

#import "TileNode.h"
#import "Utilities.h"

@interface TileNode ()

@end

@implementation TileNode

+(instancetype)tileNodeAtPosition:(CGPoint)position
                tileComboScore:(NSInteger)comboScore
                tileArray:(NSArray*)array
                randomNumber:(int)randomNumber
                initialCombo:(NSInteger)initCombo
{
    //custom node properties
    TileNode *tileNode = [array objectAtIndex:randomNumber];
    tileNode.position = position;
    tileNode.size = CGSizeMake(23, 63);

    //using label property from .h file and parenting to generated tileNode
    tileNode.comboLabel = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
    tileNode.comboLabel.fontColor = [UIColor whiteColor];
    tileNode.comboLabel.text = [NSString stringWithFormat: @"%d",initCombo];
    tileNode.comboLabel.fontSize = 12;
    tileNode.comboLabel.position = CGPointMake(13, 45);

    [tileNode setupPhysicsBody];
    [tileNode addChild:tileNode.comboLabel];

    return tileNode;
}

-(void)setupPhysicsBody
{
    self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.frame.size];
    NSLog(@"tileframe %@", NSStringFromCGRect(self.frame));
    self.physicsBody.dynamic = NO;
    self.physicsBody.categoryBitMask = ContactCategoryTile;
    self.physicsBody.contactTestBitMask = ContactCategoryTile | ContactCategoryRotor | ContactCategoryKey;
    self.physicsBody.collisionBitMask = 0;
}

My destination node type setup up like so:

#import "KeyNode.h"
#import "Utilities.h"

@implementation KeyNode

+(instancetype)keyNodeAtPosition:(CGPoint)position
{
    //custom class properties for generic yellow nodes in UI
    KeyNode *keyTile = [KeyNode spriteNodeWithImageNamed:@"key"];
    keyTile.position = position;
    keyTile.size = CGSizeMake(25, 65);
    keyTile.anchorPoint = CGPointMake(0.5, 0.5);
    keyTile.name = @"keyNode";

    [keyTile setupPhysicsBody];

    return keyTile;
}

-(void)setupPhysicsBody
{
    self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.frame.size];
    NSLog(@"keyframe %@", NSStringFromCGRect(self.frame));
    self.physicsBody.dynamic = NO;
    self.physicsBody.categoryBitMask = ContactCategoryKey;
    self.physicsBody.contactTestBitMask = ContactCategoryTile;
    self.physicsBody.collisionBitMask = 0;
}

And my contact detection delegate method like so:

-(void)didEndContact:(SKPhysicsContact *)contact
{
    NSLog(@"Working!");
    //Condition for tile and key contact
    if (contact.bodyA.categoryBitMask == ContactCategoryTile  && contact.bodyB.categoryBitMask == ContactCategoryKey)
    {
        NSLog(@"Tile contact with key");
    }
    //condition for tile and tile contact
    else if (contact.bodyA.categoryBitMask == ContactCategoryTile && contact.bodyB.categoryBitMask == ContactCategoryTile)
    {
        NSLog(@"Tile contact with tile");
    }
    //condition for tile and rotor contact
    else if(contact.bodyA.categoryBitMask == ContactCategoryTile && contact.bodyB.categoryBitMask == ContactCategoryRotor)
    {
        NSLog(@"Tile contact with rotor");
    }
}

And both nodes are being instantiated in initWithSize like so:

CGPoint position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 180);
TileNode *tileNode1 = [TileNode tileNodeAtPosition:position tileComboScore:self.comboScore tileArray:tileImagesArray randomNumber:randomTileGenerator initialCombo:self.initialCombo];
[self addChild:tileNode1];

KeyNode *keyNode1 = [KeyNode keyNodeAtPosition:CGPointMake(CGRectGetMidX(self.frame) - 100, CGRectGetMidY(self.frame) - 15)];
[self addChild:keyNode1];

Any help would be greatly appreciated.


Solution

  • I found the answer in a thread from last year that worked. You can work around wanting static bodies to have collisions.

    If you set the gravity to be non-existent and make your static nodes dynamic it works:

    self.physicsWorld.gravity = CGVectorMake(0, 0);
    self.physicsBody.dynamic = YES;