1

I am trying to make a game with a player block and a few obstacle blocks. The player can collide with the obstacle but the obstacles should not collide with each other but instead "pass through" each other. I have the following enumeration for my bit mask:

enum bitMask: UInt32 {
    case player = 1
    case obstacle = 2
    case frame = 4
}

This is how I define my player block:

let player = SKSpriteNode(imageNamed: "yellow-square")
player.physicsBody = SKPhysicsBody(texture: player.texture!, size: player.frame.size)
player.physicsBody!.dynamic = false
player.physicsBody!.categoryBitMask = bitMask.player.rawValue
player.physicsBody!.contactTestBitMask = bitMask.obstacle.rawValue
player.physicsBody!.collisionBitMask = 0
addChild(player)
player.physicsBody!.contactTestBitMask = bitMask.obstacle.rawValue
player.physicsBody!.collisionBitMask = bitMask.frame.rawValue

my obstacle blocks (in a for loop):

let obstacle = SKSpriteNode(imageNamed: "black-square")
obstacle.physicsBody = SKPhysicsBody(texture: obstacle.texture!, size: obstacle.frame.size)
boundaryNode.addChild(obstacle)
obstacle.physicsBody!.applyImpulse(CGVectorMake(-15, -10))
obstacle.physicsBody!.categoryBitMask = bitMask.obstacle.rawValue
obstacle.physicsBody!.contactTestBitMask = bitMask.player.rawValue

and my contact function:

func didBeginContact(contact: SKPhysicsContact) {
    let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
    switch(contactMask) {
        case bitMask.player.rawValue | bitMask.obstacle.rawValue:
            let yourTimeNode = contact.bodyB.node
            yourTimeNode?.physicsBody?.allowsRotation = false

            let firstNode = contact.bodyA.node
            firstNode?.physicsBody?.allowsRotation = false

            print("Collision")
        default:
            return
    }
}

Currently every block collides with each other and I do not know how to turn off collision between obstacles and keep the collision between the obstacle and player block.

spigen
  • 81
  • 1
  • 7
  • Unrelated: For your bitmask I believe you are looking for [OptionSetType](http://stackoverflow.com/questions/24066170/how-to-create-ns-options-style-bitmask-enumerations-in-swift/24066171#24066171) – Joe Feb 03 '16 at 16:17

1 Answers1

2

There is a few things in your code to change. First you should make the bit masks like so

struct BitMask {
     static let player: UInt32 = 0x1 << 0
     static let obstacle: UInt32 = 0x1 << 1
     static let frame: UInt32 = 0x1 << 2
}

this way you only need to increase the last number by 1, which makes your life easier if you start adding a lot more bit masks. Than you call it like so

...categoryBitMask = BitMask.obstacle // no need for rawValue

Than you should change your contact method to look more like this

/// Did Begin Contact
func didBeginContact(contact: SKPhysicsContact) {
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {
        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    if (firstBody.categoryBitMask == BitMask.player) && (secondBody.categoryBitMask == BitMask.obstacle) {
        // do your thing 
    }
}

And finally in your player and obstacle code, firstly in the player code you are repeating 2 values (contactBitMask/categoryBitMask), so delete them. Secondly the reason your obstacle are colliding with each other is because you have not set a collisionBitMask for your obstacles. This makes it default 0xFFFFFFFF which means all bits are set and it will interact with everything. To fix it add this to the obstacle code

 obstacle.physicsBody!.collisionBitMask = BitMask.player

which now makes the obstacles only collide with the player.

crashoverride777
  • 10,581
  • 2
  • 32
  • 56
  • By default, the [collisionBitMask](https://developer.apple.com/library/ios/documentation/SpriteKit/Reference/SKPhysicsBody_Ref/#//apple_ref/occ/instp/SKPhysicsBody/collisionBitMask) has all bits set ( 0xFFFFFFFF ). So, when logical AND operator is performed between obstacle's collision bit mask and other object's category bit mask, the result will be non-zero value. That is why the collisions will occur between obstacles and other bodies even if you don't set collision bit mask on obstacle explicitly. – Whirlwind Feb 03 '16 at 18:23
  • I guess that you understand that 0xFFFFFFFF is not equivalent for zero , but rather equal to 4294967295, which is UInt32.max, so you should slightly change your answer. – Whirlwind Feb 03 '16 at 19:02
  • I know what you mean and realised my answer is technically wrong there. Its not worth really explaining so I just removed the last part and slightly edited the other. Thanks – crashoverride777 Feb 03 '16 at 19:44
  • It happens...But still you have the same error(probably a typo this time). You haven't removed that zero which was the point of my comment. I am talking about this part: " This makes it default to 0 (0xFFFFFFFF)" , it should be : This makes it default to 0xFFFFFFFF (which is 4294967295). – Whirlwind Feb 03 '16 at 19:54
  • sorry I am getting confused with my own bitMasks now haha. I made 2.5 games so I should now lmao. – crashoverride777 Feb 03 '16 at 20:08
  • :) No worries. All other things were correct, and this one is fixed now, so I give you an upvote :) – Whirlwind Feb 03 '16 at 20:30
  • Thank you, I appreciate it. Been a long day haha – crashoverride777 Feb 03 '16 at 21:23
  • Thanks, this works perfectly although I think you meant - obstacle.physicsBody!.collisionBitMask = BitMask.player – spigen Feb 03 '16 at 22:46