Optional unwrapping SKPhysics error

让人想犯罪 __ 提交于 2019-12-11 09:49:54

问题


Before I'm crucified with downvotes let me say I have done research into this and I still cannot understand why I am getting this error.

I have a core that the player is trying to defend and you can shoot little lasers out from it to defend against incoming meteors. Well, I have everything set up and working (most of the time anyways), but every once and while when a laser hits a meteor and my collision handling function tries to remove the shot node and meteor node, it throws this error:

fatal error: unexpectedly found nil while unwrapping an Optional value

Again I have done a lot of digging into this and I cannot seem to figure it out.

Here's my didBegin:

func didBegin(_ contact: SKPhysicsContact) {
    if (contact.bodyA.node?.name == "shot") { // shot A
        collisionBetween(first: (contact.bodyA.node)!, second: (contact.bodyB.node)!)
    } else if (contact.bodyB.node?.name == "shot") { // shot B
        collisionBetween(first: (contact.bodyB.node)!, second: (contact.bodyA.node)!)
    }
    if (contact.bodyA.node?.name == "core") { // core A
        collisionBetween(first: (contact.bodyA.node)!, second: (contact.bodyB.node)!)
    } else if (contact.bodyB.node?.name == "core") { // core B
        collisionBetween(first: (contact.bodyB.node)!, second: (contact.bodyB.node)!)
    }

}

and here's my collisionBetween function:

func collisionBetween(first: SKNode, second: SKNode) {

    if first.name == "shot" && second.name == "sMeteor" {
        first.removeFromParent()    // these two only throw the error
        second.removeFromParent()   // every once and a while
    } else if first.name == "sMeteor" && second.name == "shot" {
        first.removeFromParent()    // these two throw the error also
        second.removeFromParent()   // but only on occasion
    } else if first.name == "mMeteor" && second.name == "shot" {
        second.removeFromParent()
    } else if first.name == "shot" && second.name == "mMeteor" {
        first.removeFromParent()
    }
    if first.name == "core" && second.name == "sMeteor" {
        second.removeFromParent() //always throws the error
    } else if first.name == "sMeteor" && second.name == "core" {
        first.removeFromParent() //always throws the error
    }

}

I've been trying to figure this error out for a while now, and I feel like I have a basic understanding of optionals. These errors are only thrown when I try to remove the nodes from the parent self and I have tried many different approaches to solving this problem but cannot for the life of me figure it out. Any help appreciated, thanks!


回答1:


I strongly suspect that this is caused by SpriteKit generating multiple contact events for the same contact. (i.e. it's calling didBegin()) 2 or more times with the same bodyA & bodyB)

The first time it is called, everything is fine; the second time, things have been removed and some nodes and/or bodies are nil.

Check this answer to see if it helps : Sprite-Kit registering multiple collisions for single contact

If you'd put some print statements in your didBegin() e.g.

func didBegin(_ contact: SKPhysicsContact) {
    print("Contact between \(contact.bodyA.node?.name) & \(contact.bodyB.node?.name)")
    if (contact.bodyA.node?.name == "shot") { // shot A

you'd probably have seen in the log:

Contact between shot and sMeteor
Contact between shot and sMeteor
Contact between shot and sMeteor

when only 1 contact has occurred.

Also, your didBegin() and collisionBetween()functions look overly complicated (plus collisionBetween should really be called contactBetween()).

I find a neater way to code didBegin() is :

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

            switch contactMask {

            case categoryBitMask.shot | categoryBitMask.sMeteor:
               print("Collision between shot and sMeteor")
               contact.bodyA.removeFromParent()
               contact.bodyB.removeFromParent()

            case categoryBitMask.shot | categoryBitMask.mMeteor:
               print("Collision between shot and mMeteor")
               let shot = contact.bodyA.categoryBitMask == categoryBitMask.shot ? contact.bodyA.node! : contact.bodyB.node!
               shot.removeFromParent()

            case categoryBitMask.core | categoryBitMask.sMeteor:
               print("Collision between core and sMeteor")
               let meteor = contact.bodyA.categoryBitMask == categoryBitMask.sMeteor ? contact.bodyA.node! : contact.bodyB.node!
               meteor.removeFromParent()

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

This is really only safe if your nodes only belong to one category at a time, which is up to you to determine.

What happens if 'core' and 'mMeteor' make contact?



来源:https://stackoverflow.com/questions/42848719/optional-unwrapping-skphysics-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!