vink007 vink007 - 3 months ago 11
Objective-C Question

Detecting collision between objects in array in sprite kit

i'm trying to make a game where obstacles fall from the top of the screen and the player has to try to avoid them, but the didBeginContact method is not getting called and its driving me crazy. here are the parts of my code relevant to the node collisions...

//myScene.h
@interface MyScene : SKScene <SKPhysicsContactDelegate>

//myScene.m
@implementation MyScene

static const uint32_t playerCategory = 0x1 << 0;
static const uint32_t obstacleCategory = 0x1 << 1;

-(id)initWithSize:(CGSize)size
{
if (self = [super initWithSize:size])
{
//setup scene
self.backgroundColor = [SKColor whiteColor];
self.physicsWorld.gravity = CGVectorMake(0, 0);
self.physicsWorld.contactDelegate = self;
obstacles = [NSMutableArray array];

//add player node
player = [SKNode node];
SKSpriteNode *spritePlayer = [SKSpriteNode spriteNodeWithImageNamed:@"black.png"];
spritePlayer.size = CGSizeMake(50, 50);
spritePlayer.position = CGPointMake(self.frame.size.width/2, 100);
player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size];
player.physicsBody.dynamic = NO;
player.physicsBody.mass = 0.02;
[player addChild:spritePlayer];

player.physicsBody.categoryBitMask = playerCategory;
player.physicsBody.contactTestBitMask = obstacleCategory;
player.physicsBody.collisionBitMask = 0;
player.physicsBody.usesPreciseCollisionDetection = YES;

[self addChild:player];
[self spawnNewObstacles];

}
return self;
}

- (void)spawnNewObstacles
{
//spawn obstacles
obstacle = [SKSpriteNode spriteNodeWithImageNamed:@"black.png"];

obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle.frame.size];
obstacle.physicsBody.dynamic = YES;

obstacle.physicsBody.categoryBitMask = obstacleCategory;
obstacle.physicsBody.contactTestBitMask = playerCategory;
obstacle.physicsBody.collisionBitMask = 0;
obstacle.physicsBody.usesPreciseCollisionDetection = YES;
}

-(void)didBeginContact:(SKPhysicsContact *)contact
{
NSLog(@"didBeginContact Called!");

}


the didBeginContact method is not getting called and i can't find what wrong with my code
all help is appreciated...

Answer

sknode size isn't set correctly because there is no image reference, and if you log its size if should be inf, and when I tested your code I returned an exception.

to fix this error change the following line

player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:player.frame.size]; change that to 

to the following and it should work

player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:spritePlayer.size];

as I said below just ditch the player sknode, it is simply redundant unless there is a strong reason to use it. ///////previous answer

I couldn't help but to notice that you didn't add the obstacle node to any parent node, namely the scene, like what you did with the player node using this line

[self addChild:player];

you need to do the same thing with the obstacle node

[self addChild:obstacle];

, I am surprised that you didn't mention not seeing those nodes on the screen, unless you added them in a different section of your code that you did not include, then at this point I suggest you log the positions of both nodes to give an idea of how things are located on the screen.

as for the array you won't need it all you have to do is give a name for every obstacle node like @"obstacle", then you can use the following method to access all the nodes that has that name

obstacle.name = @"obstacle";

/////later when you want to check for node removal

[self enumerateChildNodesWithName:@"obstacle" usingBlock:^(SKNode *node, BOOL *stop) {
    SKSpriteNode *child = (SKSpriteNode*)node;
    if (child.position.y <0){ //or any arbitrary condition
         [child removeFromParent];
    }
}];

Lastly, I can't see the point from using the player as a sknode and then adding an skspritenode to it, unless I am missing something !!! :) . You can simply ditch the player sknode all together and simply use the spritePlayer node instead. Hope this helps.