2
votes

I'm trying to detect collisions between two sprites but I'm unable to do this with a child sprite.

self.player = [[Player alloc] initWithImageNamed:@"player"];
self.player.position = CGPointMake(150, 75);
[self addChild:self.player];

      _object = [SKSpriteNode spriteNodeWithImageNamed:@"object"];
      _object.position = CGPointMake(-40, 27);
       [self.player addChild:_object];

then I have collision detetion like this

- (void)checkCollisions {
[self.map enumerateChildNodesWithName:@"enemy"
usingBlock:^(SKNode *node, BOOL *stop){SKSpriteNode *enemy = (SKSpriteNode *)node;
if (CGRectIntersectsRect(enemy.frame, _object.frame)) {
[enemy removeFromParent];
}
}]; }

*This does not work!!! but if I use :

CGRectIntersectsRect(enemy.frame, self.player.frame)  

I can detect a collision with the main body. how do I do collision detection for a child of another sprite?

2

2 Answers

2
votes

The child node's position and frame property are relative to it's parent, which you need to account for in your code.

SKNode has two methods that can help you with converting the position of a given SKNode to/from the coordinate spaces of another node:

convertPoint:fromNode:
convertPoint:toNode:

You can use those to convert a SKNode's position property to another coordinate space. What you want to do is convert the _object's position to the coordinate space of the enemy or visa versa and then use a temporary CGRect with that new position for your CGRectIntersectsRect check.

Here's an example :

CGPoint globalPosition = [self.player convertPoint:_object.position toNode:self.player.parent];
CGRect tempRect = CGRectMake(globalPosition.x, globalPosition.y, _object.frame.size.width, _object.frame.size.height);

if (CGRectIntersectsRect(enemy.frame, _object.frame))
{
   // collision occurred
}

This code is assuming that your enemy and your player are in the same coordinate space. (have the same parent)

1
votes

This happens because _object is a child node for self.player, and enemy node is a child node for self.map node. Both nodes should have same parent if you want to compare their frames.

I suggest you to use Sprite Kit's built-in collision handling mechanism:

// Object:
_object = [SKSpriteNode spriteNodeWithImageNamed:@"object"];
_object.position = CGPointMake(-40, 27);
_object.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:_object.frame.size;
_object.physicsBody.categoryBitMask = OBJECT_CATEGORY;
_object.physicsBody.contactTestBitMask = ENEMY_CATEGORY;
_object.physicsBody.collisionBitMask = 0;
[self.player addChild:_object];

// Enemy:
// init enemy: SKSpriteNode *enemy = [SKSpriteNode spriteNodeWithImageNamed:@"enemy"];
enemy.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:enemy.frame.size;
enemy.physicsBody.categoryBitMask = ENEMY_CATEGORY;
enemy.physicsBody.contactTestBitMask = OBJECT_CATEGORY;
enemy.physicsBody.collisionBitMask = 0;
// add enemy to the scene: [self addChild:enemy];

// Define that your SKScene conforms to SKPhysicsContactDelegate protocol:
.....
@interface MyScene : SKScene <SKPhysicsContactDelegate>
....


// SKScene.m:
static uint32_t const OBJECT_CATEGORY = 0x1 << 0;
static uint32_t const ENEMY_CATEGORY = 0x1 << 1;

@implementation MyScene

- (id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        .......
        self.physicsWorld.contactDelegate = self;
        ........
    }
    return self;
}

.......

- (void)didBeginContact:(SKPhysicsContact *)contact{
    SKPhysicsBody *firstBody, *secondBody;
    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    }
    else {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }

    if (((firstBody.categoryBitMask & OBJECT_CATEGORY) != 0) &&
             (secondBody.categoryBitMask & ENEMY_CATEGORY) != 0) {
        NSLog(@"Collision detected!");
    }

@end