1

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
            }
        }
blue
  • 7,175
  • 16
  • 81
  • 179

3 Answers3

0

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.

Epic Defeater
  • 2,107
  • 17
  • 20
  • Comments are not for extended discussion; this conversation has been [moved to chat](http://chat.stackoverflow.com/rooms/74827/discussion-on-answer-by-epic-defeater-swift-contact-detection-between-2-nodes). – Taryn Apr 09 '15 at 12:47
  • No - this is not the correct way to make 2 bodies not collide. The correct way is to ensure that their respective`collisionBitMask`s do not contain each other's `categoryBitMask`. – Steve Ives Jun 19 '17 at 21:02
0

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.

Martin
  • 16,093
  • 1
  • 29
  • 48
  • Sort of - the correct answer is to switch off the bit representing the category of the object you *don't* want to collide with in the `collisionBitMask`. E.g. to stop chicken and saviour from colliding: `chicken.physicsBody?.collisionBitMask &= ~saviourCategory`and `saviour.physicsBody?.collisionBitMask &= ~chickenCategory`. This switches off the necessary bits to stop chicken and saviour from colliding, whilst leaving all of their other collision bits unaffected. Setting `collisonBitMask` to 0 means "collide with nothing". – Steve Ives Jun 19 '17 at 21:45
-1

This is how to do it:

  1. Set up your category bit masks:

    let saviorCategory: UInt32 = 0x1 << 0
    let chickenCategory: UInt32 = 0x1 << 1
    let groundCategory: UInt32 = 0x1 << 2
    
  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.

  1. 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")
        }
    }
    
  2. Don't forget to set your class as an SKPhysicsContactDelegate

  3. Check out the examples here:

Attack button in SpriteKit

Graham
  • 7,431
  • 18
  • 59
  • 84
Steve Ives
  • 7,894
  • 3
  • 24
  • 55