Lirf
Lirf

Reputation: 121

Swift SpriteKit Contact check inside the PhysicsBody

I am working on PhysicsBody and get some troubles. First I don't really now if this is with PhysicsBody possible or only with pixel check.

The problem is: Contact check works pretty well but if a node is inside a PhysicsBody it won't be able to see if it collides. in the Pictures it is pretty well explained.

Picture 1: This works

Picture 2: This won't

Some ideas how it works? Maybe PhysicsBody(Green Line) fill with the SKNode?

Here some Code: (Some explain: if Human moves inside Object and Touched is false nothing happened and it is okay but if Human is moved inside Object and Touched will be True nothing happened too and this is my problem.)

    enum myContacts: UInt32 {
    case None   = 0
    case All    = 0xFFFFFFFF
    case Object  = 0b001
    case Human = 0b010
}

class whatever...{
    let Object = SKSpriteNode(imageNamed: "xyz")
    Object.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))

    Object.physicsBody = SKPhysicsBody(circleOfRadius: Object.size.width/2)
    Object.physicsBody?.dynamic = true
    Object.physicsBody?.categoryBitMask = myContacts. Object.rawValue
    Object.physicsBody?.contactTestBitMask = myContacts.Human.rawValue
    Object.physicsBody?.collisionBitMask = 0
    Object.physicsBody?.usesPreciseCollisionDetection = true
    addChild(Object)

    let Human = SKSpriteNode(imageNamed: "zyx")
    Human.position = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame))

    Human.physicsBody = SKPhysicsBody(circleOfRadius: Human.size.width/2)
    Human.physicsBody?.dynamic = true
    Human.physicsBody?.categoryBitMask = myContacts. Human.rawValue
    Human.physicsBody?.contactTestBitMask = myContacts.Object.rawValue
    Human.physicsBody?.collisionBitMask = 0
    Human.physicsBody?.usesPreciseCollisionDetection = true
    addChild(Human)
}

func didBeginContact(contact: SKPhysicsContact) {
    if touched {
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
        switch contactMask {
        case myContacts.Object.rawValue | myContacts.Human.rawValue:
            print("Human touched")
        default:
            break
        }
    }
}

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    touched = true
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    touched = false
}

Upvotes: 1

Views: 824

Answers (1)

Whirlwind
Whirlwind

Reputation: 13675

Not sure if I completely understand what you are asking, but if you just want to detect a contact when node is spawned inside the space "taken" by another node, this code will work:

#import "GameScene.h"

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

@interface GameScene()<SKPhysicsContactDelegate>

@property (nonatomic, strong) SKSpriteNode *player;

@property (nonatomic, strong) SKSpriteNode *obstacle;

@end

@implementation GameScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */

    self.physicsWorld.contactDelegate = self;

    [self initializeNodes];


}


-(void)initializeNodes{


    self.player =  [SKSpriteNode spriteNodeWithColor:[SKColor greenColor] size:CGSizeMake(50,50)];

    self.player.name = @"player";

    self.player.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

    self.player.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.player.size];
    self.player.physicsBody.collisionBitMask = 0;
    self.player.physicsBody.categoryBitMask = playerCategory;
    self.player.physicsBody.affectedByGravity = NO;
    self.player.physicsBody.contactTestBitMask = obstacleCategory;

    self.player.zPosition = 10;

    [self addChild:self.player];


    self.obstacle =  [SKSpriteNode spriteNodeWithColor:[SKColor yellowColor] size:CGSizeMake(100,100)];

    self.obstacle.name = @"obstacle";

    self.obstacle.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));

    self.obstacle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:self.obstacle.size];
    self.obstacle.physicsBody.collisionBitMask = 0;
    self.obstacle.physicsBody.categoryBitMask = obstacleCategory;
    self.obstacle.physicsBody.affectedByGravity = NO;
    self.obstacle.physicsBody.contactTestBitMask = playerCategory;

    self.obstacle.zPosition = 8;

    [self addChild:self.obstacle];

}





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


-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
}

@end

Here, everything is pretty much straight forward:

  • I make two nodes and assign physics bodies to them
  • I place those two nodes at the same position
  • As a result, a contact is detected

If you copy & paste this code and run it, what you are going to see in the console is the message which says : "Contact detected".

I guess that is the same situation from the second picture (where you are saying that contact is not detected).

Also, if you continue to move the player (while a player is inside of an obstacle's bounds), the further contacts will not be detected. Player have to leave the bounds of an obstacle first. But still, you can check the return value of allContactBodies method which returns an array of SKPhysicsBody objects that current body (player's physics body) is in contact with.

Upvotes: 1

Related Questions