Search code examples
iossprite-kitcollision-detection

Avoiding collision in spriteKit on iOS while maintaining contact


I have 2 physicsBodies and don't want them to collide (ie they must pass through each other) but still want to be notified in case of contact, however when setting the collisionBitMask to 0, the contact event is not called anymore. What am I doing wrong ?

let stoneCategory  : UInt32 = 0x1 << 1
let birdCategory  : UInt32 = 0x1 << 2

physicsWorld.contactDelegate = self

stoneNode = SKSpriteNode(imageNamed: "Stone");
self.addChild(stoneNode)
stoneNode.physicsBody = SKPhysicsBody(rectangleOf: stoneNode.size);
stoneNode.physicsBody?.categoryBitMask = stoneCategory
stoneNode.physicsBody?.contactTestBitMask = birdCategory
stoneNode.physicsBody?.collisionBitMask = 0

birdNode = SKSpriteNode();
<...Set texture...> 
self.addChild(birdNode)
birdNode.physicsBody = SKPhysicsBody(rectangleOf: birdNode.size);
birdNode.physicsBody?.categoryBitMask = birdCategory
birdNode.physicsBody?.contactTestBitMask = stoneCategory
birdNode.physicsBody?.collisionBitMask = 0
birdNode.physicsBody?.isDynamic = false;

func didBegin(_ contact: SKPhysicsContact) {
    print("Contact between "+contact.bodyA.node!.name!+" and "+contact.bodyB.node!.name!); // --> Never called
}

Solution

  • You might have a different problem in your code elsewhere, because this is working for me. The bodies do not collide and the contact happens.

    Sample playground code:

    import PlaygroundSupport
    import SpriteKit
    
    class GameScene: SKScene, SKPhysicsContactDelegate {
        
        var stoneNode: SKShapeNode!
        var birdNode: SKShapeNode!
        
        override func didMove(to view: SKView) {
            
            let stoneCategory  : UInt32 = 0x1 << 1
            let birdCategory  : UInt32 = 0x1 << 2
    
            physicsWorld.contactDelegate = self
    
            stoneNode = SKShapeNode(circleOfRadius: 30)
            stoneNode.name = "stone"
            stoneNode.position = CGPoint(x: 0, y: 100)
            addChild(stoneNode)
            stoneNode.physicsBody = SKPhysicsBody(circleOfRadius: 30)
            stoneNode.physicsBody?.categoryBitMask = stoneCategory
            stoneNode.physicsBody?.contactTestBitMask = birdCategory
            stoneNode.physicsBody?.collisionBitMask = 0
    
            birdNode = SKShapeNode(circleOfRadius: 40)
            birdNode.name = "bird"
            birdNode.position = CGPoint(x: 0, y: -100)
            addChild(birdNode)
            birdNode.physicsBody = SKPhysicsBody(circleOfRadius: 40);
            birdNode.physicsBody?.categoryBitMask = birdCategory
            birdNode.physicsBody?.contactTestBitMask = stoneCategory
            birdNode.physicsBody?.collisionBitMask = 0
            birdNode.physicsBody?.isDynamic = false;
        }
        
        func didBegin(_ contact: SKPhysicsContact) {
            print("Contact between "+contact.bodyA.node!.name!+" and "+contact.bodyB.node!.name!); // --> Never called
        }
    }
    
    // Load the SKScene from 'GameScene.sks'
    let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
    if let scene = GameScene(fileNamed: "GameScene") {
        // Set the scale mode to scale to fit the window
        scene.scaleMode = .aspectFill
        
        // Present the scene
        sceneView.presentScene(scene)
    }
    
    PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
    

    And in the console, when the first body drops, being affected by gravity, it's printed:

    Contact between stone and bird