可选展开 SKPhysics 错误

Optional unwrapping SKPhysics error

在我被否决票钉在十字架上之前,让我说我已经对此进行了研究,但我仍然不明白为什么我会收到这个错误。

我有一个玩家试图防御的核心,您可以从中发射小激光来防御即将到来的流星。好吧,我已经设置好一切并正常工作(无论如何大部分时间),但是每隔一段时间当激光击中流星并且我的碰撞处理函数试图移除射击节点和流星节点时,它会抛出这个错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

同样,我对此进行了大量研究,但似乎无法弄清楚。

这是我的开始:

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)!)
    }

}

这是我的 collisionBetween 函数:

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
    }

}

我已经尝试解决这个错误一段时间了,我觉得我对可选值有了基本的了解。只有当我尝试从父节点 self 中删除节点时才会抛出这些错误,并且我尝试了很多不同的方法来解决这个问题,但终究无法解决。感谢任何帮助,谢谢!

我强烈怀疑这是由于SpriteKit 为同一个联系人生成多个联系人事件造成的。 (即它调用 didBegin())同一个 bodyA 和 bodyB 两次或更多次)

第一次调用,一切正常;第二次,东西已被删除,一些节点 and/or 主体为零。

检查此答案是否有帮助:

如果您在 didBegin() 中放置一些打印语句,例如

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

您可能已经在日志中看到:

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

仅发生 1 次接触时。

此外,您的 didBegin()collisionBetween() 函数看起来过于复杂(加上 collisionBetween 实际上应该称为 contactBetween())。

我发现一种更简洁的编码方式 didBegin() 是:

 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")
        }  
    }

只有当您的节点一次只属于一个类别时,这才是真正安全的,具体由您决定。

如果 'core' 和 'mMeteor' 接触会怎样?