Detecting when two of the same colors collide - 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).
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.

Related

Swift Spritekit physicsBodies do collision bit masks in the SKScene editor

I have two balls. I don't want them to collide with each other. I want them to collide with everything else. I made the two balls have different category bit masks of 2 and 3. All the other objects have the same category bit mask of 1. I have tried setting the collision bit masks of both balls to 1. I also read something that said that an operation is done to the collision bit mask and the category bit mask and if it is nonzero then there is a collision, so I made the balls have the collision bit mask as the category bit mask of the other. So they would be 0 and everything else would be nonzero and collide. None of this works, so how do I actually make them so it works the way I want them to.
These are some of the masks I tried
Do it in code, it's so much easier to read.
class GameScene: SKScene, SKPhysicsContactDelegate {
weak var ball1: SKSpriteNode?
weak var ball2: SKSpriteNode?
let noCategory:UInt32 = 0
let ball1Category:UInt32 = 0b1
let ball2Category:UInt32 = 0b1 << 1
let wall1Category:UInt32 = 0b1 << 2
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
ball1 = self.childNode(withName: "ball1") as? SKSpriteNode
ball2 = self.childNode(withName: "ball2") as? SKSpriteNode
wall1 = self.childNode(withName: "wall1") as? SKSpriteNode
ball1?.physicsBody?.categoryBitMask = ball1Category
ball1?.physicsBody?.collisionBitMask = noCategory
ball2?.physicsBody?.categoryBitMask = ball2Category
ball2?.physicsBody?.collisionBitMask = noCategory
wall1?.physicsBody?.categoryBitMask = wall1Category
wall1?.physicsBody?.collisionBitMask = ball1Category | ball2Category
}
}
Now you can easily see that wall1 collides with the ball1 and ball2 but the balls themselves don't collide with anything. With collisions only one of the physicsbodies needs to have the collisionbitmask set. Therefore you could add the ball1 and ball2Category to all physicsbodies collisionbitmasks except the opposite ball and the balls with collide with those physicsbodies but not each other.

Inconsistent contact detection in Swift 3 using SpriteKit

I'm having an issue with contact detection in Swift 3 using SpriteKit. The contact detection is working...sometimes. It seems purely random as to when it fires and when it doesn't.
I have a yellow "bullet" that moves up on the screen to hit a red sprite named targetSprite. The desired behavior is to have the bullet removed when it hits the target, but sometimes it just passes through underneath.
I've found many questions about contact detection not working at all, but I haven't found any dealing with inconsistent detection.
What can I do to fix this?
Here's the code:
import SpriteKit
import GameplayKit
enum PhysicsCategory:UInt32 {
case bullet = 1
case sprite1 = 2
case targetSprite = 4
// each new value should double the previous
}
class GameScene: SKScene, SKPhysicsContactDelegate {
// Create sprites
let sprite1 = SKSpriteNode(color: SKColor.blue, size: CGSize(width:100,height:100))
let targetSprite = SKSpriteNode(color: SKColor.red, size: CGSize(width:100,height:100))
let bullet = SKSpriteNode(color: SKColor.yellow, size: CGSize(width: 20, height: 20))
// show the bullet?
var isShowingBullet = true
// Timers
//var timer:Timer? = nil
var fireBulletTimer:Timer? = nil
// set up bullet removal:
var bulletShouldBeRemoved = false
let bulletMask = PhysicsCategory.bullet.rawValue
override func didMove(to view: SKView) {
// Physics
targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.centerRect.size)
targetSprite.physicsBody?.affectedByGravity = false
bullet.physicsBody = SKPhysicsBody(rectangleOf: bullet.centerRect.size)
bullet.physicsBody?.affectedByGravity = false
// Contact Detection:
targetSprite.physicsBody?.categoryBitMask = PhysicsCategory.targetSprite.rawValue
targetSprite.physicsBody?.contactTestBitMask =
//PhysicsCategory.sprite1.rawValue |
PhysicsCategory.bullet.rawValue
targetSprite.physicsBody?.collisionBitMask = 0 // no collision detection
// bullet physics
bullet.physicsBody?.categoryBitMask = PhysicsCategory.bullet.rawValue
bullet.physicsBody?.contactTestBitMask =
PhysicsCategory.targetSprite.rawValue
bullet.physicsBody?.collisionBitMask = 0 // no collision detection
// execute once:
fireBulletTimer = Timer.scheduledTimer(timeInterval: 1,
target: self,
selector: #selector(self.fireBullet),
userInfo: nil,
repeats: false)
// Add sprites to the scene:
self.addChild(sprite1)
self.addChild(bullet)
self.addChild(targetSprite)
// Positioning
targetSprite.position = CGPoint(x:0, y:300)
// Note: bullet and sprite1 are at 0,0 by default
// Delegate
self.physicsWorld.contactDelegate = self
}
func didBegin(_ contact: SKPhysicsContact) {
print("didBegin(contact:))")
//let firstBody:SKPhysicsBody
// let otherBody:SKPhysicsBody
// Use 'bitwise and' to see if both bits are 1:
if contact.bodyA.categoryBitMask & bulletMask > 0 {
//firstBody = contact.bodyA
//otherBody = contact.bodyB
print("if contact.bodyA....")
bulletShouldBeRemoved = true
}
else {
//firstBody = contact.bodyB
//otherBody = contact.bodyA
print("else - if not contacted?")
}
/*
// Find the type of contact:
switch otherBody.categoryBitMask {
case PhysicsCategory.targetSprite.rawValue: print(" targetSprite hit")
case PhysicsCategory.sprite1.rawValue: print(" sprite1 hit")
case PhysicsCategory.bullet.rawValue: print(" bullet hit")
default: print(" Contact with no game logic")
}
*/
} // end didBegin()
func didEnd(_ contact: SKPhysicsContact) {
print("didEnd()")
}
func fireBullet() {
let fireBulletAction = SKAction.move(to: CGPoint(x:0,y:500), duration: 1)
bullet.run(fireBulletAction)
}
func showBullet() {
// Toggle to display or not, every 1 second:
if isShowingBullet == true {
// remove (hide) it:
bullet.removeFromParent()
// set up the toggle for the next call:
isShowingBullet = false
// debug:
print("if")
}
else {
// show it again:
self.addChild(bullet)
// set up the toggle for the next call:
isShowingBullet = true
// debug:
print("else")
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if bulletShouldBeRemoved {
bullet.removeFromParent()
}
}
}
Sorry for the inconsistent indentation, I can't seem to find an easy way to do this...
EDIT:
I have found that using 'frame' instead of 'centerRect' makes the collision area the size of the sprite. For example:
targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.centerRect.size)
should be:
targetSprite.physicsBody = SKPhysicsBody(rectangleOf: targetSprite.frame.size)
First advice - Do not use NSTimer (aka Timer) in SpriteKit. It is not paired with a game loop and can cause different issues in a different situations. Read more here ( answer posted by LearnCocos2D)
So, do this:
let wait = SKAction.wait(forDuration: 1)
run(wait, completion: {
[unowned self] in
self.fireBullet()
})
What I have noticed is that if I run your code in Simulator, I get the behaviour you have described. didBegin(contact:) is being fired randomly. Still, this is not happening on a device for me, and device testing is what matters.
Now, when I have removed Timer and did the same thing with SKAction(s) everything worked, means contact were detected every time.
Have you tried adding
.physicsBody?.isDynamic = true
.physicsBody?.usesPreciseCollisionDetrction =true
SpriteKit physics engine will calculate collision correctly if you do following:
1) set "usesPreciseCollisionDetection" property to true for bullet's physics body. This will change collision detection algorithm for this body. You can found more information about this property here, chapter "Working with Collisions and Contacts".
2) move your bullet using applyImpulse or applyForce methods. Collision detection will not woking correctly if you move body by changing it's position manually. You can find more information here, chapter "Making Physics Bodies Move".

Swift - Random collisions are not detected

In my game, I use SKSprite. Some collisions are not detected. I did 10 tries, collisions are working well but about 25% of collisions that are supposed to be detected are not detected. I have NO idea why, I tried many things. Collisions are only with nodes of the same category.
I have no idea why randomly some collisions are not made when I can obviously see them, do you have any idea? Thanks for your help.
Here is the code of didBeginContact:
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody = contact.bodyA
var secondBody: SKPhysicsBody = contact.bodyB
if firstBody.categoryBitMask == secondBody.categoryBitMask {
listContacts.append([firstBody.node!,secondBody.node!])
}
}
}
Here is the code of didEndContact:
func didEndContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody = contact.bodyA
var secondBody: SKPhysicsBody = contact.bodyB
if contact.bodyA.categoryBitMask == contact.bodyB.categoryBitMask {
for i in listContacts{
if (i.contains(firstBody.node!) && i.contains(secondBody.node!)){
let findIndex = listContacts.indexOf { $0 == i }
listContacts.removeFirst(findIndex!)
}
}
}
Finally when I declare a new SKSpriteNode I set this:
rectangle.physicsBody = SKPhysicsBody(rectangleOfSize: rectangle.size)
rectangle.physicsBody?.dynamic = true
rectangle.physicsBody?.collisionBitMask = PhysicsCategory.None
usesPreciseCollisionDetection = true doesn't change anything so I don't use usePrecisionCollisionDetection
Every SKSpriteNode has his categoryBitmask and contactTestBitmask equal because only same SKSpriteNodes are supposed to collide.
Also:
physicsWorld.gravity = CGVectorMake(0, 0)
physicsWorld.contactDelegate = self
Finally here is a short video of my game if you want to understand easily what happens (problem of collisions are between rectangles) https://www.youtube.com/watch?v=-pbmKwQiE9U
You seem to be checking if the categoryBitMask of body A equals body B.
if firstBody.categoryBitMask == secondBody.categoryBitMask {
listContacts.append([firstBody.node!,secondBody.node!])
}
}
This will only run an action if a node hits a node with the same categoryBitMask
You should be checking the collisionBitMasks to see if you have a collision, or you can check the name.
For an example using categoryBitMask you can do something like this:
func didBeginContact(contact: SKPhysicsContact) {
var sprite: SKSpriteNode!
if contact.bodyA.categoryBitMask == <your category bitmask> {
sprite = contact.bodyA.node! as! SKSpriteNode
}
else if contact.bodyB.categoryBitMask == <your category bitmask> {
sprite = contact.bodyB.node! as! SKSpriteNode
}
// Do something with sprite....
// You can also create another sprite, and assign it to the other body, and perform functions on it, or both A and B.
// It is good to have different functions you send can send the nodes to once you find out which ones they are.
}
You can do these checks to see which sprites are hitting each other.
I just fixed it! The reason was that in the function "touchesEnded", I had a recursive function that was deleting bad connections in the listContacts!

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

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:()
}
}

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