Extension for SKPhysicsContact crashing

I am creating a game with SpriteKit that has a collision between two bodies. After setting up the bodies, I implemented the method didBegin(_contact:)

as shown below:

func didBegin(_ contact: SKPhysicsContact) {
    if contact.bodyA.categoryBitMask == 0 && contact.bodyB.categoryBitMask == 1 {
        gameOver()
    }
}

      

and it worked great.

Later, while checking the documentation for this method, I discovered the following:

Two physical bodies described in the contact parameter are not transmitted in a guaranteed order .

So, to be on the safe side, I extended the class SKPhysicsContact

with the categoryBitMask swaps function between both bodies as shown below:

extension SKPhysicsContact {

    func bodiesAreFromCategories(_ a: UInt32, and b: UInt32) -> Bool {
        if self.bodyA.categoryBitMask == a && self.bodyB.categoryBitMask == b { return true }
        if self.bodyA.categoryBitMask == b && self.bodyB.categoryBitMask == a { return true }
        return false
    }
}

      

The problem is, when the function is called, the application crashes and I get the following error:

2017-07-18 13: 44: 18.548 iSnake Retro [17606: 735367] - [PKPhysicsContact bodyAreFromCategories: and:]: unrecognized selector posted to instance 0x60000028b950

2017-07-18 13: 44: 18.563 iSnake Retro [17606: 735367] *** Application terminated due to uncaught exception "NSInvalidArgumentException", reason: '- [PKPhysicsContact organs of AreFromCategories: and:]: unrecognized selector sent to instance 0x60000028b950

+3


source to share


2 answers


This appears to be a bug, as it says here: fooobar.com/questions/1234820 / ...

The problem is that the contact type is PKPhysicsContact (as you noticed), even if you explicitly state that it is SKPhysicsContact and the extension is SKPhysicsContact. You should be able to make an extension for PKPhysicsContact for this. From this logic, we can tell that no instance methods will work in SKPhysicsContact extensions at the moment. I would argue that this is a bug with SpriteKit and you should file the radar. The class methods still work since you call them on the class itself.

In the meantime, you should transfer this method to your scene or other object and call it there successfully.

For the record, this is not a Swift related issue. If you do the same method in the Objective-C category in SKPhysicsContact you get the same crash.

You can submit a bug report to apple:

https://developer.apple.com/bug-reporting/



And let the community know:

https://openradar.appspot.com/search?query=spritekit

However, what you really want to do with your code is to add the category masks together. And then check the sum (2 + 4 and 4 + 2 are always 6, no matter which one has bodyA and bodyB).

This is how you get unique pins if you set up your masks correctly over two (2, 4, 8, 16, etc.)

+2


source


SKPhysicsContact

is a wrapper class for PKPhysicsContact

, you are extending SKPhysicsContact

, but you actually need to extend PKPhysicsContact

(which you cannot do)

To keep order in your contact methods, simply do:

let bodyA = contact.bodyA.categoryBitMask <= self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB

let bodyB = contact.bodyA.categoryBitMask > self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB

      

This way, when you need to check for a specific node, you know what to push the node, so

func didBegin(_ contact: SKPhysicsContact) {
    if contact.bodyA.categoryBitMask == 0 && contact.bodyB.categoryBitMask == 1 {
        gameOver()
    }
}

      



becomes

func didBegin(_ contact: SKPhysicsContact) {

    let bodyA = contact.bodyA.categoryBitMask <= self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB

    let bodyB = contact.bodyA.categoryBitMask > self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB
    if bodyA.categoryBitMask == 0 && bodyB.categoryBitMask == 1 {
        gameOver()
    }
}

      

Then you can add to your code as you now know the individual bodies.

func didBegin(_ contact: SKPhysicsContact) {

    let bodyA = contact.bodyA.categoryBitMask <= self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB

    let bodyB = contact.bodyA.categoryBitMask > self.bodyB.categoryBitMask ? contact.bodyA : contact.bodyB
    if bodyA.categoryBitMask == 0 && bodyB.categoryBitMask == 1 {
        gameOver()
        //since I know bodyB is 1,  let add an emitter effect on bodyB.node
    }
}

      

By the way, for people who are seeing this answer, categoryBitMask 0 shouldn't launch any contacts, you need some value to work. This is a bug that is beyond the scope of the authors' question, so I left it at 0 and 1 as this is what his / her code does and (a) it claims it works.

+2


source







All Articles