swiftsprite-kitskphysicscontact

In SpriteKit SKPhysicsContactDelegate contact is not detected


I am trying to program a game with Spritekit in Swift. The aim is to escape with his character oncoming rectangles. Now I've made a mistake with the SKPhysicsContactDelegate (didBegin ()) method, so the figure's contact with one of the rectangles is not recognized. Can someone help me find the mistake?

    import SpriteKit

enum bodyType: UInt32 {
    case rechteckRechts = 1
    case rechteckLinks = 2
    case figur = 4
}

class PlayScene: SKScene, SKPhysicsContactDelegate {

    let figur = SKSpriteNode(imageNamed: "Punkt.jpg")

    @objc func addRechteck(){
        let rechteckRechts = SKSpriteNode(imageNamed: "Rechteck.gif")
        rechteckRechts.physicsBody = SKPhysicsBody()
        rechteckRechts.physicsBody?.isDynamic = false
        rechteckRechts.physicsBody?.categoryBitMask = bodyType.rechteckRechts.rawValue

        let rechteckLinks = SKSpriteNode(imageNamed: "Rechteck.gif")
        rechteckLinks.physicsBody = SKPhysicsBody()
        rechteckLinks.physicsBody?.isDynamic = false
        rechteckLinks.physicsBody?.categoryBitMask = bodyType.rechteckLinks.rawValue

        let groesse = arc4random_uniform(5)+1
        print(groesse)

        switch groesse {
        case 1:
            rechteckLinks.xScale = 0.5
            rechteckRechts.xScale = 1.5
        case 2:
            rechteckLinks.xScale = 1.5
            rechteckRechts.xScale = 0.5
        case 3:
            rechteckLinks.xScale = 1
            rechteckRechts.xScale = 1
        case 4:
            rechteckLinks.xScale = 1.25
            rechteckRechts.xScale = 0.75
        case 5:
            rechteckLinks.xScale = 0.75
            rechteckRechts.xScale = 1.25
        default:
            print("Fehler in der Wahrscheinlichkeit!!!")
        }
        rechteckRechts.position = CGPoint(x: frame.minX + (rechteckRechts.size.width / 2), y: frame.maxY)
        rechteckLinks.position = CGPoint(x: frame.maxX - (rechteckLinks.size.width / 2), y: frame.maxY)

        let moveDown = SKAction.moveBy(x: 0, y: -5000, duration: 20.0)
        rechteckLinks.run(moveDown)
        rechteckRechts.run(moveDown)

        self.addChild(rechteckRechts)
        self.addChild(rechteckLinks)
    }

    override func didMove(to view: SKView) {
        physicsWorld.gravity = .zero
        physicsWorld.contactDelegate = self

        figur.xScale = 0.4
        figur.yScale = 0.4
        figur.position = CGPoint(x: frame.midX, y: frame.maxY / 4)
        figur.physicsBody = SKPhysicsBody()
        figur.physicsBody?.isDynamic = false
        figur.physicsBody?.categoryBitMask = bodyType.figur.rawValue
        self.addChild(figur)

        self.backgroundColor = SKColor.white

        let wait1 = SKAction.wait(forDuration: 3)
        let timer = SKAction.repeatForever(SKAction.sequence([wait1, SKAction.run {
            self.addRechteck()
            }]))
        self.run(timer, withKey: "addRechteck")

    }

    func didBegin(_ contact: SKPhysicsContact) {
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask {
        case bodyType.figur.rawValue | bodyType.rechteckLinks.rawValue:
            print("contact")
        case bodyType.figur.rawValue | bodyType.rechteckRechts.rawValue:
            print("contact")
        default:
            return
        }
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches ){
            let location = touch.location(in: self)
            if figur.contains(location){
                figur.position = location
            }
        }
    }

    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        for touch in (touches ) {
            let location = touch.location(in: self)
            if figur.contains(location){
                figur.position = location
            }
        }
    }
}

Solution

  • You don’t appear to have set the collision and contactTest bit masks. These are properties of the physics body. The collisionBitMask controls which objects bounce off which other objects. By default, everything bounces off everything else.

    The contactTestBitMask is the important one in this siutuation, as it controls which objects invoke ‘didBegin‘ when contacting other objects. By default, this is 0 which means that no contacts are registered. See my answer here : https://stackoverflow.com/a/40596890/1430420 for a detailed explanation.

    In your specific example, you appear to want to know when figur makes contact with either rechteckLinks or rechteckRechts, so you would want to following contactTestBitMasks:

    figur.physicsBody!.cagegoryBitMask = bodyType.figur
    figur.physicsBody!.contactTestBitMask = bodyType.rechteckRechts | bodyType.rechteckLinks
    

    Edit: correcting the definition of figurs physics body:

    We change the ? to ! so that we get a crash should the physics body not exist. We also change the isDynamic property to true as physics bodies that are not dynamic cannot register contacts (I think). It’s ok for the other 2 to not be dynamic. We assign the collisionTestBitMask to the value of all the categories we want to be notified of collision with logically ‘OR’ed together:

    figur.physicsBody!.isDynamic = true 
    figur.physicsBody!.categoryBitMask = bodyType.figur.rawValue
    figur.physicsBody!.contactTestBitMask = bodyType.rechteckRechts.rawValue | bodyType.rechteckLinks.rawValue