Coder1000 Coder1000 - 6 months ago 43
iOS Question

SpriteKit Swift: How to prevent a Crash when bodyA collisions with more than one bodyB at the same time?

SITUTATION:

Already searched extensively, didn't find a solution.

For example, this does not help: Swift/SpriteKit Multiple Collision Detection?

PROBLEM:

My code works fine except when the player hits two different PhysicsCategory Objects at the same time (falls and hits exactly the ground and a wall at the same time for example). This makes my app crash.




CODE:

struct PhysicsCategory {
static let player: UInt32 = 0x1 << 1
static let ground: UInt32 = 0x1 << 2
static let wall: UInt32 = 0x1 << 3
static let scoreWall: UInt32 = 0x1 << 4
}

func didBeginContact(contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB

if firstBody.categoryBitMask == PhysicsCategory.scoreWall && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.scoreWall {

score += 1
scoreLabel.text = "\(score)"

updatePlayerColor()

}

else if firstBody.categoryBitMask == PhysicsCategory.wall && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.wall {

lost = true

self.scene?.speed = 0

gameVC?.dismissViewControllerAnimated(false, completion: nil)

//playDeathAnimation with completion block self.dismiss(VC)
}

else if firstBody.categoryBitMask == PhysicsCategory.ground && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.ground {

lost = true

self.scene?.speed = 0

gameVC?.dismissViewControllerAnimated(false, completion: nil)

//playDeathAnimation with completion block self.dismiss(VC)
}
}


Debugger Error:

Fatal Error: Index out of range.

What I am looking for:

I just want to know if the double collision is accounted for in my code already or not. The debugger error refers to some other part of my code that is influenced by the collisions. But this would be too much code to add here. So please just answer on the following: how to account for double collisions in my SpriteKit game between ScoreWall and Wall ?

Answer

You don't have a double collision. You'll have 2 single collisions i.e. didBeginContact will be called once for the collision between the player and the ground and again for the collision between the player and the wall. An SKPhysicsContact can only have 2 bodies. Your crash is caused by something else, perhaps by the removal of the gameVC?

For an example of a 'cleaner' version of didBeginContact, try this:

 func didBeginContact(contact: SKPhysicsContact) {

        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask {
        // If the player and the scoreWall have collided:
        case .player | .scoreWall :
           score += 1
           scoreLabel.text = "\(score)"
           updatePlayerColor()

        // If the player and the wall have collided:
        case .player | .wall :
           lost = true
           self.scene?.speed = 0
           gameVC?.dismissViewControllerAnimated(false, completion: nil)

        // If the player and the ground have collided:
        case .player | .ground :
           lost = true
           self.scene?.speed = 0
           gameVC?.dismissViewControllerAnimated(false, completion: nil)

        default :
           print("Some other contact has occurred")
        }