swiftsprite-kitskphysicsbodyskphysicsworldskphysicscontact

iOS SpriteKit Collision Detection Fails After Decode Save


I have a game where Falling Nodes fall down and hit the Base Number Sprite Node and game logic is run from there. When I set up a new game from scratch the collision detection works exactly how it should. My problem occurs when I create a game from a previous save using NSCoding. In both cases (new game and continue from save game) the physics bodies are the same - dynamic, same size body, same contactTestBitMask, same categoryBitMask. I have tested all of this so I know it is true. The physics contact delegate is also set to the right object. In a game continued from a save, however, the contacts are not registered and I cannot figure out why. The only thing I can think of, but am unable to figure out is object which is set as my physics contact delegate and is the parent of the objects I want collision detection for gets loaded/unarchived without me actually calling decodeObjectForKey for it.

Any help would be much appreciated

    func initBaseNumberSpritePhysicsBody() {
        baseNumberSprite.physicsBody = nil
        baseNumberSprite.physicsBody = SKPhysicsBody(rectangleOfSize: baseNumberSprite.size)
        baseNumberSprite.physicsBody!.categoryBitMask = baseNumberCategory
        baseNumberSprite.physicsBody!.contactTestBitMask = fallingNodeCategory
        baseNumberSprite.physicsBody!.collisionBitMask = 0
        baseNumberSprite.physicsBody!.usesPreciseCollisionDetection = true
        baseNumberSprite.physicsBody!.allowsRotation = false
    }

    func initPhysicsBodyForFallingNode(node: NumberNode) {
        node.physicsBody = nil
        node.physicsBody = SKPhysicsBody(rectangleOfSize: node.size)
        node.physicsBody!.categoryBitMask = fallingNodeCategory
        node.physicsBody!.contactTestBitMask = baseNumberCategory
        node.physicsBody!.collisionBitMask = 0
        node.physicsBody!.allowsRotation = false
        node.physicsBody!.velocity = nodeVelocity
    }

    func didBeginContact(contact: SKPhysicsContact) {

        if isContactBetween(fallingNodeCategory, and: baseNumberCategory, contact: contact) {
            handleContactBetweenFallingNodeAndBaseNumber(contact)
        } else {
            print("\nUNKNOWN CONTACT OCCURED\n")
        }

        updateInternalState()
        checkGameOverCondition()
    }


    required init?(coder aDecoder: NSCoder) {
//        gameZone = aDecoder.decodeObjectForKey(gameZoneKey) as! GameZone
        super.init(coder: aDecoder)

        gameZone = self.children[0] as! GameZone  //Not decoded by itself but somehow decoded with the this GameScene Object (the "self" object here)
        gameZone.delegate = self
        self.physicsWorld.contactDelegate = gameZone
    }

    override func encodeWithCoder(aCoder: NSCoder) {
        super.encodeWithCoder(aCoder)
        aCoder.encodeObject(gameZone, forKey: gameZoneKey)  //Gets coded
    }

Solution

  • I was able to figure out my own problem here. A fundamental understanding I was lacking is the SKNodes encode their own child nodes.

    //        gameZone = aDecoder.decodeObjectForKey(gameZoneKey) as! GameZone
    

    The gameZone object is a child node. So I was encoding it as well as other key objects twice which was leading to my problem. The problem was had nothing to do with the physics world contact delegate or encoding/decoding.