Search code examples
iosxcodeswiftcollision-detectioncollision

Collision detection interrupting another collision detection - Swift


As of now, I have an SKSpriteNode that detects collisions with my ball and increments my score by + 1 when they collide. Also in the collision is the code that detects if my ball hits a wall.

    let scoreNode = SKSpriteNode()

    scoreNode.size = CGSize(width: 750, height: 10)
    scoreNode.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 100)
    scoreNode.physicsBody = SKPhysicsBody(rectangleOfSize: scoreNode.size)
    scoreNode.physicsBody?.affectedByGravity = false
    scoreNode.physicsBody?.dynamic = true
    scoreNode.physicsBody?.categoryBitMask = PhysicsCat.Score
    scoreNode.physicsBody?.collisionBitMask = 0
    scoreNode.physicsBody?.contactTestBitMask = PhysicsCat.Ball
    scoreNode.color = SKColor.clearColor()

func didBeginContact(contact: SKPhysicsContact) {


    let firstBody = contact.bodyA
    let secondBody = contact.bodyB



    if firstBody.categoryBitMask == PhysicsCat.Score && secondBody.categoryBitMask == PhysicsCat.Ball{

        score += 1
        scoreLbl.text = "\(score)"
        firstBody.node?.removeFromParent()


    }

    else if firstBody.categoryBitMask == PhysicsCat.Ball && secondBody.categoryBitMask == PhysicsCat.Score {

        score += 1
        scoreLbl.text = "\(score)"
        secondBody.node?.removeFromParent()


    }
    else if firstBody.categoryBitMask == PhysicsCat.Ball && secondBody.categoryBitMask == PhysicsCat.Wall || firstBody.categoryBitMask == PhysicsCat.Wall && secondBody.categoryBitMask == PhysicsCat.Ball{

        enumerateChildNodesWithName("wallPair", usingBlock: ({
            (node, error) in

            node.speed = 0
            self.removeAllActions()

        }))

        if died == false{
            died = true
            createBTN()
            fallDie()
        }
    }

    else if firstBody.categoryBitMask == PhysicsCat.Ball && secondBody.categoryBitMask == PhysicsCat.Wall {

        enumerateChildNodesWithName("wallPair", usingBlock: ({
            (node, error) in

            node.speed = 0
            self.removeAllActions()

        }))
        if died == false{
            died = true
            Ball.physicsBody?.velocity = CGVectorMake(0, 0)

            createBTN()
        }
    }
}

I need a second collision detection that is completely separate from the above code^^. How do I make them separate? You can't have two didBeginContact's I don't think. I hope this isn't too vague or unclear. So obviously I need a second node, calling it colorNode. How would I detect a collision between my ball and colorNode (colorNode is about 200 pixels below my scoreNode, so they aren't in the same position), without messing up my code that detects collision between the ball and the wall?


Solution

  • You do not need a separate collision detection. What you need to do is to handle things in didBeginContact. All those if-else checks with their || and && becomes quite unwieldy. (Exemplified by the fact that your last else performs a check that's already been performed in the former else).

    The below code is an OK-ish attempt to make the if-logic more sensible. Creating a Bool to handle the presence for each of the types we're interested in.

    func didBeginContact(contact: SKPhysicsContact) {
        let firstBody = contact.bodyA
        let secondBody = contact.bodyB
    
        let ballWasContacted = firstBody.categoryBitMask == PhysicsCat.Ball || secondBody.categoryBitMask == PhysicsCat.Ball
        let wallWasContacted = firstBody.categoryBitMask == PhysicsCat.Wall || secondBody.categoryBitMask == PhysicsCat.Wall
        let scoreWasContacted = firstBody.categoryBitMask == PhysicsCat.Score || secondBody.categoryBitMask == PhysicsCat.Score
    

    Now that this logic has been defined in a fairly reasonable manner you come to the actual collision-checking where you really reap the rewards:

    if ballWasContacted {
        if scoreWasContacted {
            score += 1
            scoreLbl.text = "\(score)"
            let scoreNode = firstBody.categoryBitMask == PhysicsCat.Score ? firstBody.node : secondBody.node
            scoreNode!.removeFromParent()
        } else if wallWasContacted {
            enumerateChildNodesWithName("wallPair", usingBlock: ({
                (node, error) in
                node.speed = 0
                self.removeAllActions()
            }))
            if died == false {
                died = true
                createBTN()
                fallDie()
            }
        }
    }
    

    This should make it a lot easier to handle another ball vs. something collision. You just need a PhysicsCat.Color and another Bool. Then just hook another else if onto the last.

     else if colorWasContacted {
                // Do stuff
            }
    

    Note: It's a good idea to also follow conventions. I'm thinking about your naming, do not abbreviate words. scoreLabel not scoreLbl PhysicsCategory not PhysicsCat*

    *PhysicsCat? Is that Mr. Schroedinger's late pet?