Swift SpriteKit basic Contact / Collision - swift

The problem: When the coin spawns, it's physicsBody appears right underneath the spriteNode. Also, when the player comes in contact with the coin's physicsBody, the player bounces off of the physicsBody and the game ends.
What the output should be: The coin's physisBody should be aligned properly with the coin spriteNode. When the player comes in contact with the coin, the coin should disappear and +1 should be added to the proper label.
The current code:
struct ColliderType {
static let playerCategory: UInt32 = 0x1 << 0
static let boundary: UInt32 = 0x1 << 1
​
​static let coinCategory: UInt32 = 0x1 << 2
​
​static let bodyA: UInt32 = 0x1 << 4
​
​static let bodyB: UInt32 = 0x1 << 8
}
override func didMoveToView(view: SKView) {
var coinInt = 0
​
​
​
​self.physicsWorld.gravity = CGVectorMake(0.0, -7.0)
physicsWorld.contactDelegate = self
player = SKSpriteNode(imageNamed: "player")
player.zPosition = 1
player.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width / 5.12)
player.physicsBody?.dynamic = true
player.physicsBody?.allowsRotation = false
self.addChild(player)
generateCoins()
​
​
coin = SKSpriteNode( imageNamed: "coin")
coin.physicsBody? = SKPhysicsBody(circleOfRadius: coin.size.height / 10)
coin.physicsBody?.dynamic = false
coin.physicsBody?.allowsRotation = false
coin.zPosition = 1
​self.addChild(coin)
​
player.physicsBody?.categoryBitMask = ColliderType.playerCategory
​player.physicsBody?.contactTestBitMask = ColliderType.boundary
player.physicsBody?.collisionBitMask = ColliderType.coinCategory | ColliderType.boundary
coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
coin.physicsBody?.collisionBitMask = ColliderType.playerCategory
func didPlayerCollideWithCoin(player: SKSpriteNode, coin: SKSpriteNode) {
self.coin.removeFromParent()
self.coin += 1
coinLabel.text = "\(coinInt)"
}
​
​
​
​func generateCoins() {
if(self.actionForKey("spawning") != nil){return}
let coinTimer = SKAction.waitForDuration(7, withRange: 2)
let spawnCoin = SKAction.runBlock {
self.coin = SKSpriteNode( imageNamed: "coin")
self.coin.physicsBody = SKPhysicsBody(circleOfRadius: self.coin.size.height / 10)
self.coin.name = "coin"
self.coin.physicsBody?.dynamic = false
self.coin.physicsBody?.allowsRotation = false
var coinPosition = Array<CGPoint>()
coinPosition.append((CGPoint(x:340, y:103)))
coinPosition.append((CGPoint(x:340, y:148)))
coinPosition.append((CGPoint(x:340, y:218)))
coinPosition.append((CGPoint(x: 340, y:343)))
let spawnLocation = coinPosition[Int(arc4random_uniform(UInt32(coinPosition.count)))]
let action = SKAction.repeatActionForever(SKAction.moveToX(+self.xScale, duration: 4.4))
self.coin.runAction(action)
self.coin.position = spawnLocation
self.addChild(self.coin)
print(spawnLocation)
}
let sequence = SKAction.sequence([coinTimer, spawnCoin])
self.runAction(SKAction.repeatActionForever(sequence), withKey: "spawning")
}
​​
func didBeginContact(contact:SKPhysicsContact) {
let bodyA: SKPhysicsBody = contact.bodyA
let bodyB: SKPhysicsBody = contact.bodyB
if ((bodyA.categoryBitMask == ColliderType.playerCategory) && (bodyB.categoryBitMask == ColliderType.coinCategory)){
didPlayerCollideWithCoin(bodyA.node as! SKSpriteNode, coin: bodyB.node as! SKSpriteNode)
}
}

I would recommend that you read these documentation first!
contactTestBitMask - A mask that defines which categories of bodies cause intersection notifications with a current physics body.
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 nonzero 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.
collisionBitmask - A mask that defines which categories of physics bodies can collide with this physics body.
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 nonzero
value, 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.
Remove this code to solve the colliding issue
coin.physicsBody?.collisionBitMask = ColliderType.playerCategory
Try to see if this solves your SpriteNode alignment issue
var coinTexture = SKTexture(imageNamed: "coin")
coin = SKSpriteNode(texture:coinTexture)

Also, I would recommend changing how you're defining your Category Bitmasks. Since you're already doing bit shifting with <<, you don't need to shift by powers of two. That's what the bit shifting does for you. Try changing your code to this:
static let playerCategory: UInt32 = 0x1 << 0
static let boundary: UInt32 = 0x1 << 1 ​
​static let coinCategory: UInt32 = 0x1 << 2 ​
​static let bodyA: UInt32 = 0x1 << 3 ​
​static let bodyB: UInt32 = 0x1 << 4
This won't help with your problem, but this is good to know.

I actually found a workaround that works much better for my game, where I sublcass SKNode to represent objects like missiles that have different damage, terrain cells, etc. I set the collision bit masks to all my objects to be the same (i.e., they all need to interact with each other. Then to loop through all collisions with player and also get a pointer to the proper object that it's colliding with, I do the following
for (int i=0; i<[self.physicsBody.allContactedBodies count]; i++) {
SKPhysicsBody* contactedBody = self.physicsBody.allContactedBodies[i];
if (contactedBody != NULL && [contactedBody.node isKindOfClass:[TerrainCell class]]) {
NSLog(#"BUMPED INTO TERRAIN");
TerrainCell* collisionObject = (TerrainCell*)contactedBody.node;
// do more stuff specific to TerrainCell
}
}

Related

Change texture of individual nodes in didBeginContact

I've created a simple game where I have a match hover over candles (the odd description lends itself to my question) and the player scores a point when the match comes in contact with the wick. However, if it comes into contact with the anything else (like the 'wax' part of the candle), the game is over. The player controls the match by tapping on the screen.
My candle, being the wick and the coloured part, is created as follows (I have removed irrelevant parts, like the series of random textures):
func makeCandles() {
//Node properties and randomisation
let candle = SKNode()
let randomCandle = Int(arc4random_uniform(UInt32(candleTexture.count)))
let randomTexture = candleTexture[randomCandle] as SKTexture
let random = arc4random_uniform(17)
candle.position = CGPoint(x: self.frame.size.width, y: CGFloat(random * 12) - 120)
//Candle
let chosenCandle = SKSpriteNode(texture: randomTexture)
chosenCandle.position = CGPoint(x: 0, y: self.frame.size.height / 2)
chosenCandle.physicsBody = SKPhysicsBody(rectangleOfSize: chosenCandle.size)
chosenCandle.physicsBody?.dynamic = false
chosenCandle.physicsBody?.categoryBitMask = self.candleCategory
chosenCandle.physicsBody?.contactTestBitMask = self.matchCategory
chosenCandle.physicsBody?.collisionBitMask = 0
chosenCandle.physicsBody?.restitution = 0
candle.addChild(chosenCandle)
//Wick
let wickArea = SKSpriteNode(texture: wickTexture)
wickArea.name = "wickNode"
wickArea.position = CGPoint(x: 0, y: self.frame.size.height / 1.3)
wickArea.physicsBody = SKPhysicsBody(rectangleOfSize: CGSize(width: wickArea.size.width / 4, height: wickArea.size.height))
wickArea.physicsBody?.dynamic = false
wickArea.physicsBody?.categoryBitMask = self.wickCategory
wickArea.physicsBody?.contactTestBitMask = self.matchCategory
wickArea.physicsBody?.collisionBitMask = 0
wickArea.zPosition = 11
wickArea.physicsBody?.restitution = 0
candle.addChild(wickArea)
//Add the node and zPosition
self.partsMoving.addChild(candle)
chosenCandle.zPosition = 12
}
The candles are then created in a runBlock:
let createCandles = SKAction.runBlock({() in self.makeCandles()})
let briefPause = SKAction.waitForDuration(averageDelay, withRange: randomDelay)
let createAndPause = SKAction.sequence([createCandles, briefPause])
let createAndPauseForever = SKAction.repeatActionForever(createAndPause)
self.runAction(createAndPauseForever)
This is my function that changes the texture which is called in didBeginContact:
func updateFlame() {
if let newNode: SKNode = self.childNodeWithName("//wickNode") {
let updateTexture = SKAction.setTexture(flameTexture, resize: true)
newNode.runAction(updateTexture)
}
}
This is my didBeginContact function:
func didBeginContact(contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == wickCategory || contact.bodyB.categoryBitMask == wickCategory {
score += 1
scoreLabel.text = "\(score)"
updateFlame()
} else {
runGameOverScene()
}
My problem is that it only changes the first node to a flame, and doesn't change any others. Even if it is the second or third wick on which contact is detected, only the first created wick is changed (the first one that comes across the screen). I know that contact is being detected on each node and that that works fine, because the score updates every time the match comes into contact with a wick.
What am I doing wrong that is stopping the texture of each node that individually comes into contact with the match from changing? Everything else is working just fine, but this part has had me beat for a week and everything I've tried doesn't work. This is the closest I've gotten.
After much trial and error, I have finally figured out how to make each node change texture when contact occurs! This is my code for that part:
func didBeginContact(contact: SKPhysicsContact) {
let collision : UInt32 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask)
if collision == (matchCategory | candleCategory | cakeCategory) {
runGameOverScene()
}
if (contact.bodyA.categoryBitMask == wickCategory) {
let newWick = contact.bodyA.node
let updateTexture = SKAction.setTexture(flameTexture, resize: true)
newWick!.runAction(updateTexture)
} else if (contact.bodyB.categoryBitMask == wickCategory) {
let newWick = contact.bodyB.node
let updateTexture = SKAction.setTexture(flameTexture, resize: true)
newWick!.runAction(updateTexture)
}
}
I followed the logic of this question (even though I wanted to set the texture, not remove it) and it worked perfectly: removeFromParent() Doesn't Work in SpriteKit.

Detecting when two of the same colors collide

I have a square consisting of four different colors in the middle of my scene. At the same time, I have smaller squares of the same color randomly generated from each sides of the scene with the intention of colliding with the square in the middle. (Blue to blue, yellow to yellow, etc).
My goal is to have it set up so that when a blue square collides with a blue square or any of the like, it will .removeFromParent(). How should I go about doing this? Will post code if necessary.
Edit:
enum BodyType: UInt32 {
case blueSquare = 1
case redSquare = 2
case yellowSquare = 4
case greenSquare = 8
}
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
didBeginContact() {
switch(contactMask) {
case BodyType.redSquare.rawValue | BodyType.redSquare.rawValue:
let scoreLabel = childNodeWithName("scores") as! Points
scoreLabel.increment()
let firstNode = contact.bodyB.node
firstNode?.removeFromParent()
default:
return
}
}
First thing you should do is set up the contactTestBitMasks & categoryBitMasks on all of your SKSpriteNodes, like this -
struct PhysicsCatagory {
static let FirstPerson : UInt32 = 0x1 << 1
static let SecondPerson : UInt32 = 0x1 << 2
}
override func didMoveToView(view: SKView) {
...
firstPerson.SKPhysicsBody?.catagoryBitMask = PhysicsCatagory.FirstPerson
firstPerson.SKPhysicsBody?.contactTestBitMask = PhysicsCatagory.SecondPerson
...
secondPerson.SKPhysicsBody?.catagoryBitMask = PhysicsCatagory.SecondPerson
secondPerson.SKPhysicsBody?.contactTestBitMask = PhysicsCatagory.FirstPerson
...
}
This is just setting up the catagoryBitMask and the contactTestBitMask. The categoryBitMask will be equal to the object you are currently editing, whereas, the contactTestBitMask will be equal to the object you want the object to collide with.
Also, before we move on, we want to add the Contact Delegate to our scene.
class GameScene: SKScene, SKPhysicsContactDelegate{...
And then add the delegate to our scene -
override func didMoveToView(view: SKView) {
...
self.physicsWorld.contactDelegate = self
...
Next, you add the didBeginContact
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA.node as! SKSpriteNode!
let secondBody = contact.bodyB.node as! SKSpriteNode!
}
Lastly inside of that, test...
func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA.node as! SKSpriteNode!
let secondBody = contact.bodyB.node as! SKSpriteNode!
if firstBody.color == secondBody.color{
firstBody.removeFromParent()
secondBody.removeFromParent()
}
}
Hope that helps! :D
Once you detect a collision, compare the colors of the colliding squares and if equal, call .removeFromParent(). If you post code I could try to give the specific methods that would help.
If you want to get fancy you could create a subclass for your squares with a colorTag property (1 = blue, 2 = yellow ect.) and then compare the tags of the colliding squares. Although I doubt the cost of comparing the colors is much.

Why is there multiple collision calls Sprite Kit Swift

I am building an iOS swift game with collision. The hero is being bombarded by small stars coming from the right side of the screen. Every time a star hits the hero, the score is iterated and the star is removed. But, more than one point is added to the score.
Node Set-up:
var star = SKSpriteNode(imageNamed: "star")
star.size = CGSizeMake(30, 30)
star.zPosition = 10
var starPhysicsRect = CGRectMake(star.position.x - star.frame.size.width / 2, star.position.y - star.frame.size.width / 2, star.frame.size.width, star.frame.size.height)
star.physicsBody = SKPhysicsBody(edgeLoopFromRect: starPhysicsRect)
star.physicsBody?.restitution = 0
star.name = "star"
star.physicsBody?.mass = 0
return star
didBeginContact Function:
func didBeginContact(contact: SKPhysicsContact) {
//collision variables
var firstBodyNode = contact.bodyA.node as! SKSpriteNode
var secondBodyNode = contact.bodyB.node as! SKSpriteNode
var firstNodeName = firstBodyNode.name
var secondNodeName = secondBodyNode.name
//other variables
var scoreLabel: SKLabelNode = constantsInstance.scoreLabel(position: CGPointMake(self.frame.size.width * 0.86, self.frame.size.height * 0.928))
//check if hero hit star
if firstNodeName == "hero" && secondNodeName == "star" {
println("star hit")
secondBodyNode.removeFromParent()
//iterate score
childNodeWithName("scoreLabel")?.removeFromParent()
scoreLabel.text = "\(counterForScore)"
counterForScore++
self.addChild(scoreLabel)
}
}
I get "star hit" printed to the console several times as well. Why would the didBeginContact function be called more than once if I remove the star on the first call of the function?
I have run simulations on a smaller scale and found that the star goes fairly deep into the hero (because of the SKAction), if there is no remove command. Could it be that the didBeginContact function is called many times while the star is going into the hero and before it is removed?
All help is greatly appreciated.
You can check if parent of the SKSpriteNode is nil before continuing.
func didBeginContact(contact: SKPhysicsContact) {
var firstBodyNode : SKSpriteNode!
var secondBodyNode : SKSpriteNode!
// Assuming that the contact test bit mask of star is greater than hero. If it's not you should reverse the condition.
if contact.bodyA.contactTestBitMask < contact.bodyB.contactTestBitMask {
firstBodyNode = contact.bodyA.node as! SKSpriteNode
secondBodyNode = contact.bodyB.node as! SKSpriteNode
} else {
firstBodyNode = contact.bodyB.node as! SKSpriteNode
secondBodyNode = contact.bodyA.node as! SKSpriteNode
}
var firstNodeName = firstBodyNode.name
var secondNodeName = secondBodyNode.name
if firstNodeName == "hero" && secondNodeName == "star" {
if secondBodyNode.parent != nil {
// Your code.
}
}
}
Could it possibly be due to the physicsBody:
var star = SKSpriteNode(imageNamed: "star")
star.size = CGSizeMake(30, 30)
star.zPosition = 10
var starPhysicsRect = CGRectMake(star.position.x - star.frame.size.width / 2, star.position.y - star.frame.size.width / 2, star.frame.size.width, star.frame.size.height)
star.physicsBody = SKPhysicsBody(edgeLoopFromRect: starPhysicsRect)
Have a look at the logic creating the starPhysicsRect:
(star.position.x - star.frame.size.width / 2, star.position.y - star.frame.size.width / 2, star.frame.size.width, star.frame.size.height)
From what I can see this translates to the following values:
(-15, -15, 30, 30) those negative position-coordinates seem odd. Are you sure you don't just want: SKPhysicsBody(rectangleOfSize: star.size) ?

Swift: Contact detection between 2 nodes?

Alright, so I've been following various other SO links and trying to figure this out- I need to have contact detection between 2 nodes. Not collision detection, which I learned results in the nodes bouncing each other around. I don't want them to knock each other around, I just want to know when they touch.
Right now I have physics bodies for the 2 nodes, savior and chicken1 as well as the ground (ground) upon which savior sits. These are all set up here:
savior.physicsBody?.dynamic = true
savior.physicsBody?.allowsRotation = false
savior.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(savior.size.width, savior.size.height))
chicken1.physicsBody?.dynamic = true
chicken1.physicsBody?.allowsRotation = false
chicken1.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(chicken1.size.width, chicken1.size.height))
ground.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(self.frame.size.width, groundTexture.size().height*2))
ground.physicsBody?.dynamic = false
I need to set up contact detection between savior and chicken1. There seem to be various ways to do this, but this is what I put together:
//Contact detection
self.physicsWorld.contactDelegate = self
savior.physicsBody?.categoryBitMask = saviorCategory
savior.physicsBody?.contactTestBitMask = animalCategory
savior.physicsBody?.collisionBitMask = 0
chicken1.physicsBody?.categoryBitMask = animalCategory
chicken1.physicsBody?.contactTestBitMask = saviorCategory
chicken1.physicsBody?.collisionBitMask = 0
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 == 0 && secondBody.categoryBitMask == 1 {
println("they made contact")
}
}
This code results in savior falling right through ground and going right through chicken1, with no contact detection because even when savior and chicken1 touch, nothing happens.
I need savior and ground to continue to collide, but I don't want savior and chicken1 to collide, just touch.
The program needs to execute something when they touch.
It's a mess but how can I fix this?
EDIT:
Here is what I have, animalCategory has been changed to chickenCategory for clarity and no contact is detected. Also savior still falls through ground.
self.physicsWorld.contactDelegate = self
var screenTouches = Bool()
let saviorCategory: UInt32 = 0x1 << 0
let chickenCategory: UInt32 = 0x1 << 1
savior.physicsBody?.categoryBitMask = saviorCategory
savior.physicsBody?.contactTestBitMask = chickenCategory
savior.physicsBody?.collisionBitMask = chickenCategory
chicken1.physicsBody?.categoryBitMask = chickenCategory
chicken1.physicsBody?.contactTestBitMask = saviorCategory
chicken1.physicsBody?.collisionBitMask = saviorCategory
func didBeginContact(contact: SKPhysicsContact) {
var firstBody : SKPhysicsBody
var secondBody : SKPhysicsBody
if contact.bodyA.categoryBitMask == chickenCategory && contact.bodyB.categoryBitMask == saviorCategory {
println("contact made")
savior.hidden = true
}
else if contact.bodyA.categoryBitMask == saviorCategory && contact.bodyB.categoryBitMask == chickenCategory {
println("contact made")
savior.hidden = true
}
}
Ok so it seems like all you want is for just detection that they touched, but you don't want them to push each other. I would in the didBeginContact where ever you put your collision detection between them , make their physicsbody = nil, so that when they collide it knows that they collide and when you put this it makes them go through each other. And if you want to put code to do something else just put that code before you make the physicsbody nil. Also if you want to put back their physicsbody, just put it back.
For anyone who is still stuck on this, if you want to detect that two sprites are touching each other without them actually having a physical effect on each other (i.e. causing movement), then the key is to set the collisionBitMask property of the physicsBody to 0:
node.physicsBody!.collisionBitMask = 0
This means that you will receive events in didBeginContact but the interacting objects will not cause an actual physical effect on each other.
This is how to do it:
Set up your category bit masks:
let saviorCategory: UInt32 = 0x1 << 0
let chickenCategory: UInt32 = 0x1 << 1
let groundCategory: UInt32 = 0x1 << 2
Set up the physics bodies:
func didMove(to: View) {
savior.physicsBody?.categoryBitMask = saviorCategory
savior.physicsBody?.contactTestBitMask = chickenCategory
savior.physicsBody?.collisionBitMask = groundCategory
chicken1.physicsBody?.categoryBitMask = animalCategory
chicken1.physicsBody?.contactTestBitMask = saviorCategory
chicken1.physicsBody?.collisionBitMask = groundCategory
ground.physicsBody?.categoryBitMask = groundCategory
ground.physicsBody?.contactTestBitMask = 0 // No contact detection for ground
ground.physicsBody?.collisionBitMask = UInt32.Max // Everything collides with the ground
physicsWorld.contactDelegate = self
// Rest of didMoveToView
}
Note: It isn't actually necessary to define chicken as contacting saviour and saviour as contacting chicken; you only need to define that one contacts the other, but it can make the code more readable to say that each contacts the other.
Implement didBegin:
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case chickenCategory | saviourCategory:
print("Collision between chicken and saviour")
let saviour = contact.bodyA.categoryBitMask == saviourCategory ? contact.bodyA.node! : contact.bodyB.node!
saviour.hidden = true
default :
//Some other contact has occurred
print("Some other contact")
}
}
Don't forget to set your class as an SKPhysicsContactDelegate
Check out the examples here:
Attack button in SpriteKit

Swift SpriteKit Physics Collision Issue

I am making a simple physics based game. Everything is working normally with exception to collision detection. It feels like the didBeginContact method is being ignored.
I have tried several ways of configuring the "PhysicsCategory" struct (even using enum) and several formations of the bodyA/bodyB contact statements.
I am all out of ideas. I can get the 2 objects to collide but they just bounce off each other. There are no errors and nothing logged to the console. I hope that I have made a trivial mistake that I am overlooking.
Below is all the pertinent code. In case it matters... setupPhysics() is being called in didMoveToView
PhysicsCategory Struct
struct PhysicsCategory {
static let None: UInt32 = 0
static let Fish: UInt32 = 0b1
static let Bird: UInt32 = 0b10
static let BottomEdge: UInt32 = 0b100}
Physics Setup Method
//MARK: - Physics Methods
func setupPhysics() {
/* Physics World */
physicsWorld.gravity = CGVectorMake(0, -9.8)
physicsWorld.contactDelegate = self
physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
/* Bottom Collision Rect */
let bEdge = CGRect(x: CGPointZero.x, y: CGPointZero.y, width: size.width, height: size.height * 0.005)
let bottomEdge = SKShapeNode(rect: bEdge)
bottomEdge.physicsBody = SKPhysicsBody(edgeLoopFromRect: bEdge)
bottomEdge.physicsBody!.categoryBitMask = PhysicsCategory.BottomEdge
bottomEdge.physicsBody!.collisionBitMask = PhysicsCategory.Fish
bottomEdge.physicsBody!.dynamic = false
gameLayer.addChild(bottomEdge)
/* Fish */
fish.physicsBody = SKPhysicsBody(circleOfRadius: blowfish.size.height / 2.1)
fish.physicsBody!.allowsRotation = false
fish.physicsBody!.categoryBitMask = PhysicsCategory.Fish
fish.physicsBody!.collisionBitMask = PhysicsCategory.Bird | PhysicsCategory.BottomEdge
/* Left Random Bird */
randomLeftBird.physicsBody = SKPhysicsBody(rectangleOfSize: randomLeftBird.size)
randomLeftBird.physicsBody!.affectedByGravity = false
randomLeftBird.physicsBody!.allowsRotation = false
randomLeftBird.physicsBody!.categoryBitMask = PhysicsCategory.Bird
randomLeftBird.physicsBody!.collisionBitMask = PhysicsCategory.Fish
/* Random Right Bird */
randomRightBird.physicsBody = SKPhysicsBody(rectangleOfSize: randomRightBird.size)
randomRightBird.physicsBody!.affectedByGravity = false
randomRightBird.physicsBody!.allowsRotation = false
randomRightBird.physicsBody!.categoryBitMask = PhysicsCategory.Bird
randomRightBird.physicsBody!.collisionBitMask = PhysicsCategory.Fish
}
didBeginContact Setup
func didBeginContact(contact: SKPhysicsContact!) {
let collision: UInt32 = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if collision == PhysicsCategory.Fish | PhysicsCategory.Bird {
println("COLLISON WITH BIRD!")
updateLives()
} else if collision == PhysicsCategory.Fish | PhysicsCategory.BottomEdge {
println("EPIC FAIL!")
}
}
I don't see any use of contactTestBitMask in your code. That one controls whether you get contact delegate messages — collisionBitMask just controls whether they collide (bounce off).
These are separate so that you can get contact delegate messages even for categories that don't bounce off each other, but it means you also can have collisions that don't send messages. (That can be a good thing if you don't want game logic for every kind of collision.) Any that you do want contact messages for you need to explicitly request.