Search code examples
iosswiftswiftuisprite-kitskphysicsbody

Why aren't contacts working in SpriteView


I'm trying to get to know when two sprites contact each other but I'm not being able to get it to work.

The code below reproduces the problem. I expected the contact delegate methods to fire when I tap the red square and the yellow square reaches it. However, nothing happens. The code seems like a lot but is actually quite simple. I've added comments to make it easier to read:

class GameScene: SKScene, SKPhysicsContactDelegate {
    private var node: SKSpriteNode!
    
    override func didMove(to view: SKView) {
        // Set contact delegate to this class
        physicsWorld.contactDelegate = self

        // Have the Game Scene be the same size as the View
        size = view.frame.size

        // Create a yellow square with a volume based physics body that isn't dynamic
        node = SKSpriteNode(color: .yellow, size: CGSizeMake(50, 50))
        node.position = CGPointMake(100, 100)
        node.physicsBody = SKPhysicsBody(rectangleOf: CGSizeMake(50, 50))
        node.physicsBody!.isDynamic = false

        // Set it's contact bit mask to any value (default category bitmask of 
        // SKSpriteNode is 0xFFFFFFFF so any value over here would do)
        node.physicsBody!.contactTestBitMask = 1

        // Add it to the Scene
        addChild(node)
        
        // Create a red square with a volume based physics body that isn't dynamic
        let otherNode = SKSpriteNode(color: .red, size: CGSizeMake(50, 50))
        otherNode.physicsBody = SKPhysicsBody(rectangleOf: CGSizeMake(50, 50))
        otherNode.physicsBody!.isDynamic = false

        // Set the position to be 100 pts to the right of the yellow square
        otherNode.position = CGPointMake(200, 100)

        // Add it to the Scene
        addChild(otherNode)
    }
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        // Moves yellow square to where you tapped on the screen
        guard let finger = touches.first?.location(in: self) else { return }
        node.run(.move(to: finger, duration: 1))
    }

    func didBegin(_ contact: SKPhysicsContact) {
        print("did begin contact")
    }
}
struct ContentView: View {
    var body: some View {
        VStack {
            Text("Game")
            SpriteView(scene: GameScene(), debugOptions: [.showsPhysics, .showsNodeCount])
        }
        .padding()
    }
}

Can anyone tell me what I'm doing wrong?

Thanks in advance


Solution

  • didBegin(contact:) won't fire if .isDynamic = false so delete those lines and add physicsWorld.gravity = .zero to keep nodes from falling.