1

In my project I am trying to detect a collision between two SKSpriteNodes, but it will not work. Here is my code for the physics category :

struct PhysicsCategory {
static let enemy : UInt32 = 0x1 << 1
static let player : UInt32 = 0x1 << 3
static let neutral : UInt32 = 0x1 << 2
 }

For the neutral, enemy and player bodies

  neutral = SKSpriteNode(imageNamed: "Cave-Bottom")
    neutral.size = CGSize(width: self.frame.width, height: self.frame.height / 8)
    neutral.position = CGPoint(x: 0, y: self.frame.height / -2.5)
    neutral.zPosition = 2
    neutral.physicsBody?.categoryBitMask = PhysicsCategory.neutral
    neutral.physicsBody?.collisionBitMask = PhysicsCategory.player
    neutral.physicsBody?.contactTestBitMask = PhysicsCategory.player
    neutral.physicsBody = SKPhysicsBody.init(rectangleOf:              neutral.size)

    enemy = SKSpriteNode(imageNamed: "spike")
    enemy.size = CGSize(width: 40, height: 40)
    enemy.position = CGPoint(x: 0, y: 0)
    enemy.zPosition = 2
    enemy.physicsBody = SKPhysicsBody.init(rectangleOf: enemy.size)
    enemy.physicsBody?.categoryBitMask = PhysicsCatagory.enemy
    enemy.physicsBody?.collisionBitMask = PhysicsCatagory.player
    enemy.physicsBody?.contactTestBitMask = PhysicsCatagory.player

    player = SKSpriteNode(imageNamed: "bob")
    player.size = CGSize(width: 40, height: 40)
    bob.zPosition = 3
    player.physicsBody?.categoryBitMask = PhysicsCatagory.player
    player.physicsBody?.collisionBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
    player.physicsBody?.contactTestBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
    player.physicsBody = SKPhysicsBody.init(rectangleOf: player.size)

And the code for my ContactHasBegan function:

  func didBegin(_ contact: SKPhysicsContact) {

   print("collided!")

    if (contact.bodyA.categoryBitMask == PhysicsCatagory.enemy && contact.bodyB.categoryBitMask == PhysicsCatagory.player) {
        print("player and enemy!")
    }
    if (contact.bodyB.categoryBitMask == PhysicsCatagory.enemy && contact.bodyA.categoryBitMask == PhysicsCatagory.player) {
        print("player and enemy!")
    }
    if (contact.bodyA.categoryBitMask == PhysicsCatagory.neutral && contact.bodyB.categoryBitMask == PhysicsCatagory.player) {
        print("neutral and player!")    
    }
    if contact.bodyB.categoryBitMask == PhysicsCatagory.neutral && contact.bodyA.categoryBitMask == PhysicsCatagory.player{
        print("neutral and player")
    }          }

For some reason it only detects a collision between the player and enemy and prints "Collided!" and none of the if statements in the didBeginContact function test out positive.

Jason
  • 93
  • 9

1 Answers1

4

Because player's physicsBody doesn't have it's category and contactTest bit masks set corrcetly.

You've created the player's physicsBody AFTER you tried to set the player's physicsBody's attributes:

player.physicsBody?.categoryBitMask = PhysicsCatagory.player
player.physicsBody?.collisionBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
player.physicsBody?.contactTestBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
player.physicsBody = SKPhysicsBody.init(rectangleOf: player.size)

In the first 3 lines of code, because player.physicsBody is an optional, the rest of the line is ignored, as there is no physicsBody.

So the physics body is created with all properties set to default i.e. it collides with everything and contacts nothing.

You need to move the line :

player.physicsBody = SKPhysicsBody.init(....

to before the code where you set the physics body's attributes:

player.physicsBody = SKPhysicsBody.init(rectangleOf: player.size)
player.physicsBody?.categoryBitMask = PhysicsCatagory.player
player.physicsBody?.collisionBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
player.physicsBody?.contactTestBitMask = PhysicsCatagory.enemy | PhysicsCatagory.neutral
Steve Ives
  • 7,894
  • 3
  • 24
  • 55
  • 1
    player,physicsBody => player.physicsBody – El Tomato Jun 09 '17 at 05:51
  • 1
    a cool way to avoid this is to do `let pb = SKPhysicsBody()` then just do `player.physicsBody = pb` at the end.. That way you don't have to do optional chaining. – Fluidity Jun 09 '17 at 12:23
  • @Fluidity, this is not only a cool way, this should be the preferred way when assigning any type of variable. You should set the data up then assign, not assign then set the data up. – Knight0fDragon Jun 09 '17 at 16:19