All collisions working except for one. What do I do? - swift

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).
With that being said, 3 out of four of my collisions are working just fine. Red hits red fine, blue hits blue fine and yellow hits yellow fine but my green square just doesn't want to do what it should. This is how I have my collisions set up:
struct PhysicsCatagory {
static let FirstPerson : UInt32 = 0x1 << 1
static let SecondPerson : UInt32 = 0x1 << 2
static let ThirdPerson : UInt32 = 0x1 << 4
static let FourthPerson : UInt32 = 0x1 << 8
}
smallBlue.physicsBody?.categoryBitMask = PhysicsCatagory.FirstPerson
smallBlue.physicsBody?.contactTestBitMask = PhysicsCatagory.SecondPerson
smallRed.physicsBody?.categoryBitMask = PhysicsCatagory.ThirdPerson
smallRed.physicsBody?.contactTestBitMask = PhysicsCatagory.FourthPerson
smallRed.physicsBody?.collisionBitMask = 0
smallGreen.physicsBody?.categoryBitMask = PhysicsCatagory.ThirdPerson
smallGreen.physicsBody?.contactTestBitMask = PhysicsCatagory.FourthPerson
smallGreen.physicsBody?.collisionBitMask = 0
bigRed.physicsBody?.contactTestBitMask = PhysicsCatagory.FourthPerson
bigRed.physicsBody?.categoryBitMask = PhysicsCatagory.ThirdPerson
bigRed.physicsBody?.collisionBitMask = 0
bigGreen.physicsBody?.categoryBitMask = PhysicsCatagory.ThirdPerson
bigGreen.physicsBody?.contactTestBitMask = PhysicsCatagory.FourthPerson
bigGreen.physicsBody?.collisionBitMask = 0
bigBlue.physicsBody?.categoryBitMask = PhysicsCatagory.FirstPerson
bigBlue.physicsBody?.contactTestBitMask = PhysicsCatagory.SecondPerson
bigBlue.physicsBody?.collisionBitMask = 0
bigYellow.physicsBody?.categoryBitMask = PhysicsCatagory.FirstPerson
bigYellow.physicsBody?.collisionBitMask = 0
bigYellow.physicsBody?.contactTestBitMask = PhysicsCatagory.SecondPerson
func didBeginContact() {
let firstBody = contact.bodyA.node as! SKSpriteNode // registering as big blue square
let secondBody = contact.bodyB.node as! SKSpriteNode // register ing as little blue square
if firstBody.color == secondBody.color { //if the colors collide, remove small one from the scene
//firstBody.removeFromParent()
label.text = "\(numPoints)" // points label increment
numPoints++ //points label increment
secondBody.removeFromParent()
}
if firstBody.color != secondBody.color { // if colors don't match, call gameOver scene
//gameOver()
}
let thirdBody = contact.bodyA.node as! SKSpriteNode
let fourthBody = contact.bodyB.node as! SKSpriteNode
if thirdBody.color == fourthBody.color {
label.text = "\(numPoints)"
numPoints++
fourthBody.removeFromParent()
}
if thirdBody.color != fourthBody.color {
//gameOver()
}
let fifthBody = contact.bodyA.node as! SKSpriteNode
let sixthBody = contact.bodyB.node as! SKSpriteNode
if fifthBody.color == sixthBody.color {
label.text = "\(numPoints)"
numPoints++
secondBody.removeFromParent()
}
let seventhBody = contact.bodyA.node as! SKSpriteNode
let eighthBody = contact.bodyB.node as! SKSpriteNode
if seventhBody.color == eighthBody.color {
label.text = "\(numPoints)"
numPoints++
eighthBody.removeFromParent()
print("green removed")
}
}
Is there something I'm missing? Will post more code if necessary.
Here is an english representation of what I am looking for
if small red equals big red then gain a point, update the label, and remove small red
if small blue equals big blue then gain a point, update the labelm and remove small blue
if small yellow equals big yellow then gain a point, update points label and remove little yellow.
if small green equals big green, gain point and update label and remove little yellow from scene
if little blue does not equal big blue, call game over scene
if little yellow does not equal big yellow, call game over scene
if little red does not equal big red, call game over scene
if little green does not equal big green, call game over scene

How the contact bodies work, is didBeginContact will be called everytime 2 nodes collide, that is, in 1 update cycle, if red hits blue, and red hits green, 2 calls to didBeginContact will take place. This means that your creation of thirdBody and so fourth have no meaning, because it ends up being the same as firstBody every time. This means that we can delete all that code entirely, and have it like this:
func didBeginContact() {
let firstBody = contact.bodyA.node as! SKSpriteNode // registering as big blue square
let secondBody = contact.bodyB.node as! SKSpriteNode // register ing as little blue square
if firstBody.color == secondBody.color { //if the colors collide, remove small one from the scene
label.text = "\(numPoints)" // points label increment
numPoints++ //points label increment
secondBody.removeFromParent()
}
if firstBody.color != secondBody.color { // if colors don't match, call gameOver scene
//gameOver()
}
}
What this code says is I do not care what the 2 objects are, if a red object hits a red object, lets remove the second object.
Ok, but now we have a problem, what if the second object is the big red.
We need to program our code so that second object is always small red. This is where the categories come in. The category is an integer representation of what this object should be.
If we make our bigger object category masks lower than our smaller object category masks, we could write a formula like this:
let firstBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyA.node : contactBodyB.node) as! SKSpriteNode // registering as big blue square
let secondBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyB.node : contactBodyA.node) as! SKSpriteNode // registering as little blue square
which says let firstBody be the node of bodyA if A <= B or else bodyB if A > B and let secondBody be the node of bodyB if A <= B or else bodyA if A > B.
The way you have categoryBitMasks done now, it is not possible. You will have to create bitmasks so that your larger objects and smaller objects do not share the same mask.
Now we have our order preserved, so our code says exactly what we are looking for.
If you want to add a print out of what color was removed, then we just do a condition afterwards to check the color. See below for the final result.
func didBeginContact() {
let firstBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyA.node : contactBodyB.node) as! SKSpriteNode // registering as big blue square
let secondBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyB.node : contactBodyA.node) as! SKSpriteNode // registering as little blue square
if firstBody.color == secondBody.color { //if the colors collide, remove small one from the scene
label.text = "\(numPoints)" // points label increment
numPoints++ //points label increment
if(secondBody.color == UIColor.greenColor())
{
print("Green was removed")
}
if(secondBody.color == UIColor.redColor())
{
print("Red was removed")
}
if(secondBody.color == UIColor.blueColor())
{
print("Blue was removed")
}
if(secondBody.color == UIColor.yellowColor())
{
print("Yellow was removed")
}
secondBody.removeFromParent()
}
if firstBody.color != secondBody.color { // if colors don't match, call gameOver scene
//gameOver()
}
}
Now keep in mind, you never bother checking the type of collision that is happening, so if you decide in the future to add medium red that kills you on a color match, this will cause problems. Because in its current state, we only care that red hits red, we do not care if it was medium or small. So you need to use that switch method we talked about in your other question to first check what type of collision happened, before doing any processing:
func didBeginContact() {
let firstBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyA.node : contactBodyB.node) as! SKSpriteNode // registering as big blue square
let secondBody = ((contact.bodyA.categoryBitMask <= contact.bodyB.categoryBitMask) ? contact.bodyB.node : contactBodyA.node) as! SKSpriteNode // registering as little blue square
switch(firstBody.categoryBitMask | secondBody.categoryBitMask)
{
case BigObject | SmallObject:
if firstBody.color == secondBody.color { //if the colors collide, remove small one from the scene
label.text = "\(numPoints)" // points label increment
numPoints++ //points label increment
if(secondBody.color == UIColor.greenColor())
{
print("Green was removed")
}
if(secondBody.color == UIColor.redColor())
{
print("Red was removed")
}
if(secondBody.color == UIColor.blueColor())
{
print("Blue was removed")
}
if(secondBody.color == UIColor.yellowColor())
{
print("Yellow was removed")
}
secondBody.removeFromParent()
}
if firstBody.color != secondBody.color { // if colors don't match, call gameOver scene
//gameOver()
}
default:()
}
}

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.

Unexpected repeated collisions in SpriteKit

I'm making my first game with Swift and SpriteKit and while I've had collisions working properly for some time now, I recently noticed a huge bug. My collisions can either be the user with and enemy (spaceship against alien) user shooting an enemy (laser against alien). The latter works fine, but recently the collision detection when the ship touches an alien hasn't been working-- normally the alien should be removed from the scene when it touches the so that only a single life (1 of 3 total) is removed. However, the ship looses 3-6 lives upon touch now. Here's the code and where I'd assume the problem is:
This is one of a few contact functions that is then called in the general contact method.
func alien_ship_contact(contact:SKPhysicsContact){
var alien:SKNode? = nil
if contact.bodyA.categoryBitMask == PhysicsCategory.Alien && contact.bodyB.categoryBitMask == PhysicsCategory.Ship{
alien = contact.bodyA.node
}
else if contact.bodyB.categoryBitMask == PhysicsCategory.Alien && contact.bodyA.categoryBitMask == PhysicsCategory.Ship{
alien = contact.bodyB.node
}
else{
return
}
killOffAlien((alien)!)
aliensKilled = aliensKilled + 1
shipLives = shipLives-1
aShip.lives = aShip.lives - 1
print("ship/alien contact")
}
Here is the killOffAlien function:
func killOffAlien(alien:SKNode){
print("Kill off")
//alien.removeFromParent()
func stopMotion(){
alien.physicsBody?.categoryBitMask = 0
alien.physicsBody?.collisionBitMask = 0
alien.physicsBody?.contactTestBitMask = 0
alien.physicsBody?.dynamic = false
alien.physicsBody?.velocity = CGVector(dx:0, dy:0)
alien.removeActionForKey("facialMotion")
}
func removeAlien(){
alien.removeFromParent()
}
let stopMoving = SKAction.runBlock(stopMotion)
let fadeOut = SKAction.fadeOutWithDuration(1)
let removeFromParent = SKAction.runBlock(removeAlien)
let die = SKAction.sequence([stopMoving, fadeOut, removeFromParent])
alien.runAction(die)
}
And here is the general contact method:
func didBeginContact(contact:SKPhysicsContact){
alien_laser_contact(contact)
alien_ship_contact(contact)
....
Any help would be awesome, I would think that upon initial contact the alien has it's bitmask set off from Alien so that in itself would prevent future collisions as every alien should only be able to remove at max one life from the ship.

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