Reputation: 383
I have 4 SpriteNodes on screen that I would like not to bounce off each other but rather flow through each other, while maintaining collision with certain SpriteNodes and the frame of the screen. I have already declared categories for all of them:
let BCategory : UInt32 = 0x1 << 0
let B2Category : UInt32 = 0x1 << 1
let B3Category : UInt32 = 0x1 << 2
let B4Category : UInt32 = 0x1 << 3
let BotCategory : UInt32 = 0x1 << 4
let PadCategory : UInt32 = 0x1 << 5
let WallCategory : UInt32 = 0x1 << 6
And added Bitmasks as well:
b.physicsBody!.categoryBitMask = BCategory
b2.physicsBody!.categoryBitMask = B2Category
b3.physicsBody!.categoryBitMask = B3Category
b4.physicsBody!.categoryBitMask = B4Category
p.physicsBody!.categoryBitMask = PadCategory
wall.categoryBitMask = WallCategory
bot.physicsBody?.categoryBitMask = BotCategory
b.physicsBody?.contactTestBitMask = BotCategory | PadCategory
b2.physicsBody?.contactTestBitMask = BotCategory | PadCategory
b3.physicsBody?.contactTestBitMask = BotCategory | PadCategory
b4.physicsBody?.contactTestBitMask = BotCategory | PadCategory
As well as checked for collisions between the SpriteNodes I would like to collide via:
func didBeginContact(contact: SKPhysicsContact) {
Is it possible to have all of the b's (b, b2, b3, b4) collide with p, wall, and bot but not amongst themselves? Any help is very much appreciated!
EDIT: The issue I'm having is that the SpriteNodes represented by the b's (b, b2, b3, b4) are bouncing off of each other. I would like each of the b's to only bounce off the SpriteNodes contained in BotCategory and PadCategory, and slide past/through the other b's.
Upvotes: 3
Views: 1040
Reputation: 8134
You've gotten mixed up between collisions and contacts. A collision is when 2 physics bodies hit and bounce off each other. Collisions are handled completely by the game engine. You just have to set the necessary collisionBitMask
A contact is when the sprite-kit game engine tells you code that 2 physics bodies have made contact. You can then make one explode, update a score etc. 2 bodies can collide without you being notified of a contact, or they can make contact without a collision. You have to set the contactTestBitMask, set your program as the physicsWorld.contactDelegate
and implement either or both of the didBeginContact
/didEndContact
functions.
Whether or not 2 bodies collide is controlled by the collisionBitMask
. By default, this is set to UInt32.Max
i.e. everything collides with everything. Given 2 bodies, A and B, it's possible for body A to collide with body B i.e. to bounce off it, but for body B NOT to collide with body A i.e to be unaffected by the collision.
Whether or not your code is notified about 2 bodies making contact is controlled by the contactTestBitMask
. This is set to 0 by default i.e. no contacts are registered. Given 2 bodies A and B, you only have to set the contactTestBit mask for body A to the category for bodyB for all contacts between the 2 to be registered.
I find this function useful to check what collision and contacts you have in your scene:
func checkPhysics() {
// Create an array of all the nodes with physicsBodies
var physicsNodes = [SKNode]()
//Get all physics bodies
enumerateChildNodesWithName("//.") { node, _ in
if let _ = node.physicsBody {
physicsNodes.append(node)
} else {
print("\(node.name) does not have a physics body so cannot collide or be involved in contacts.")
}
}
//For each node, check it's category against every other node's collion and contctTest bit mask
for node in physicsNodes {
let category = node.physicsBody!.categoryBitMask
// Identify the node by its category if the name is blank
let name = node.name != nil ? node.name : "Category \(category)"
if category == UInt32.max {print("Category for \(name) does not appear to be set correctly as \(category)")}
let collisionMask = node.physicsBody!.collisionBitMask
let contactMask = node.physicsBody!.contactTestBitMask
// If all bits of the collisonmask set, just say it collides with everything.
if collisionMask == UInt32.max {
print("\(name) collides with everything")
}
for otherNode in physicsNodes {
if (node != otherNode) && (node.physicsBody?.dynamic == true) {
let otherCategory = otherNode.physicsBody!.categoryBitMask
// Identify the node by its category if the name is blank
let otherName = otherNode.name != nil ? otherNode.name : "Category \(otherCategory)"
// If the collisonmask and category match, they will collide
if ((collisionMask & otherCategory) != 0) && (collisionMask != UInt32.max) {
print("\(name) collides with \(otherName)")
}
// If the contactMAsk and category match, they will contact
if (contactMask & otherCategory) != 0 {print("\(name) notifies when contacting \(otherName)")}
}
}
}
Just call it after setting up the physics with checkPhysics()
and it will list which bodies collide and for which contact you will be notified.
Upvotes: 5
Reputation: 6393
You need to specify the collisionBitMask
on the physicsBodies as well as the category/contact-masks. This is by default turned ON for all bits. So something like this:
b.physicsBody?.collisionBitMask = BotCategory | PadCategory
Upvotes: 4