pretty_girl
pretty_girl

Reputation: 5

How to test if 2 SKSpriteNodes collide

Hi I am a newbie in IOS Dev. I would like to text if my hull node and my fallingObject node collide. Once it collided, I want to remove that fallingObject node.

In my code I created a basket in my Scene. then on a Random point on the screen it creates a fallingObject node.

My goal is once the fallingObject collides (or catched) by the hull (imaginary box inside the basket node). the fallingObject would disappear or removed from the Scene.

Please see my code below:

static const uint32_t boxCategory  = 0x1 << 0;
static const uint32_t fallingObjectCategory = 0x1 << 1;

#import "MyScene.h"

    - (SKSpriteNode *)newBasket
        {
            SKSpriteNode *basketImage = [[SKSpriteNode alloc] initWithImageNamed:@"basket-01.png"];
            basketImage.size = CGSizeMake(150,120);

            SKSpriteNode *hull = [[SKSpriteNode alloc] initWithColor:[SKColor grayColor] size:CGSizeMake(64,32)];
            [basketImage addChild:hull];

            hull.alpha = 0.0;
            hull.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:hull.size];
            hull.physicsBody.dynamic = NO;


            hull.physicsBody.categoryBitMask = boxCategory;
            hull.physicsBody.contactTestBitMask = fallingObjectCategory;
            hull.physicsBody.collisionBitMask = boxCategory | fallingObjectCategory;

            _basket = basketImage;
            _box =hull;

            return basketImage;
        }

        - (void)addFallingObject
        {

            SKSpriteNode *fallingObject = [[SKSpriteNode alloc] initWithImageNamed:[self getRandomFallingObject]];

            //Configure the Size
            switch (randomNumber) {
                case 0:
                    fallingObject.size = CGSizeMake(70,45);
                    break;
                case 1:
                    fallingObject.size = CGSizeMake(30,45);
                    break;
                case 2:
                    fallingObject.size = CGSizeMake(40,90);
                    break;
                default:
                    fallingObject.size = CGSizeMake(50,50);
                    break;
            }


            fallingObject.position = CGPointMake(skRand(0, self.size.width), self.size.height-50);
            fallingObject.name = @"fallingObject";
            fallingObject.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:fallingObject.size];
            self.physicsWorld.speed = 0.30;

           fallingObject.physicsBody.categoryBitMask = fallingObjectCategory;
           fallingObject.physicsBody.contactTestBitMask = boxCategory;
           fallingObject.physicsBody.collisionBitMask = fallingObjectCategory | boxCategory;

            [self addChild:fallingObject];

        }

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

    SKPhysicsBody *boxBody;
    SKPhysicsBody *fallingObjectBody;

    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
    {
        boxBody = contact.bodyA;
        fallingObjectBody = contact.bodyB;
    }
    else
    {
        boxBody = contact.bodyB;
        fallingObjectBody = contact.bodyA;
    }

    if ((boxBody.categoryBitMask & boxCategory) !=0 && (fallingObjectBody.categoryBitMask & fallingObjectCategory) !=0)
    {
        //do whatever you want like remove a node
    }

}

thank you for all your help. :D

Upvotes: 0

Views: 626

Answers (1)

Douglas
Douglas

Reputation: 2524

I have a sprite kit game with two things that collide. One is the player and one is the charge. I set up a category for both like this before all my code. This is before all my imports and stuff.

static const uint32_t playerCategory  = 0x1 << 4;
static const uint32_t chargeCategory = 0x1 << 5;

Then when I make each node I use the following.

self.player.physicsBody.categoryBitMask = playerCategory;
self.player.physicsBody.contactTestBitMask = chargeCategory;
self.player.physicsBody.collisionBitMask = chargeCategory | selfCategory;

and for the charge.

_chargedBall.physicsBody.categoryBitMask = chargeCategory; 
_chargedBall.physicsBody.contactTestBitMask = playerCategory;
_chargedBall.physicsBody.collisionBitMask = playerCategory | selfCategory | chargeCategory;

This tells the player it can collide with a charge and something I called self, but that is not necessary right now.

Then in didBeginContact I use.

SKPhysicsBody *playerBody, *chargeBody;

if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
{
    playerBody = contact.bodyA;
    chargeBody = contact.bodyB;
}
else
{
    playerBody = contact.bodyB;
    chargeBody = contact.bodyA;
}

if ((playerBody.categoryBitMask & playerCategory) !=0 && (chargeBody.categoryBitMask & chargeCategory) !=0)
{  
  //do whatever you want like remove a node
}

EDIT #1

I actually make my objects in initWithSize.

-(id)initWithSize:(CGSize)size {
if (self = [super initWithSize:size])
{   // a bunch of code

    self.player = [[Player alloc] initWithImageNamed:@"character"];
    self.player.name = @"MyPlayer";
    self.player.position = CGPointMake(self.frame.size.width / 2.0f, 120);
    self.player.zPosition = 15;
    self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.player.frame.size];
    self.player.physicsBody.dynamic = YES;
    self.player.physicsBody.affectedByGravity = NO;
    self.player.physicsBody.mass = 0.25;
    self.player.physicsBody.allowsRotation = NO;
    self.player.physicsBody.friction = 0.5;
    self.player.physicsBody.restitution = 0.3;
    self.player.physicsBody.categoryBitMask = playerCategory;
    self.player.physicsBody.contactTestBitMask = chargeCategory;
    self.player.physicsBody.collisionBitMask = chargeCategory | selfCategory;
    [self.map addChild:self.player];

 }

Then I make the other obj in a method.

- (void)spawnChargesWithNumber:(int)number
{   // some code
 _chargedBall.position = (CGPointMake(_randomX, random));
_chargedBall.name = [NSString stringWithFormat:@"chargeNumber%i", number];
_chargedBall.zPosition = 15;
_chargedBall.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:13.0f];
_chargedBall.physicsBody.dynamic = YES;
_chargedBall.physicsBody.affectedByGravity = NO;
_chargedBall.physicsBody.mass = 0.1;
_chargedBall.velocity = CGPointMake(0.0, 0.0); //changed actualVelocityX to 0
_chargedBall.physicsBody.categoryBitMask = chargeCategory;
_chargedBall.physicsBody.contactTestBitMask = playerCategory;
_chargedBall.physicsBody.collisionBitMask = playerCategory | selfCategory | chargeCategory;
[self.map addChild:_chargedBall];

}

EDIT #2 This might clear some things up. It is from the Apple Docs.

***categoryBitMask

A mask that defines which categories this physics body belongs to.

@property(assign, nonatomic) uint32_t categoryBitMask Discussion Every physics body in a scene can be assigned to up to 32 different categories, each corresponding to a bit in the bit mask. You define the mask values used in your game. In conjunction with the collisionBitMask and contactTestBitMask properties, you define which physics bodies interact with each other and when your game is notified of these interactions.

The default value is 0xFFFFFFFF (all bits set).

Availability Available in iOS 7.0 and later. See Also @property collisionBitMask @property contactTestBitMask Declared In SKPhysicsBody.h

***collisionBitMask

A mask that defines which categories of physics bodies can collide with this physics body.

@property(assign, nonatomic) uint32_t collisionBitMask Discussion When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a non-zero value, then this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.

The default value is 0xFFFFFFFF (all bits set).

Availability Available in iOS 7.0 and later. See Also @property categoryBitMask Declared In SKPhysicsBody.h

***contactTestBitMask

A mask that defines which categories of bodies cause intersection notifications with this physics body.

@property(assign, nonatomic) uint32_t contactTestBitMask Discussion When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a non-zero value, an SKPhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.

The default value is 0x00000000 (all bits cleared).

Availability Available in iOS 7.0 and later. See Also @property categoryBitMask Declared In SKPhysicsBody.h

Upvotes: 1

Related Questions