可选展开 SKPhysics 错误

Posted

技术标签:

【中文标题】可选展开 SKPhysics 错误【英文标题】:Optional unwrapping SKPhysics error 【发布时间】:2017-03-17 03:29:03 【问题描述】:

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

我有一个玩家试图防御的核心,你可以从它发射小激光来防御来袭的流星。好吧,我已经完成了所有设置和工作(大部分时间),但是当激光击中流星并且我的碰撞处理功能试图移除射击节点和流星节点时,它会抛出这个错误:

fatal error: unexpectedly found nil while unwrapping an Optional value

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

这是我的 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)!)
    


这是我的碰撞函数:

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 中删除节点时才会引发这些错误,并且我尝试了许多不同的方法来解决此问题,但我终生无法弄清楚。任何帮助表示赞赏,谢谢!

【问题讨论】:

【参考方案1】:

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

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

查看此答案是否有帮助:Sprite-Kit registering multiple collisions for single contact

如果您在 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' 接触会发生什么?

【讨论】:

我也很怀疑!!当我尝试调试时,我收到了多次调用 didBegin 但我不知道如何解决它。非常感谢您,我一定会查看您链接的答案。还要感谢清理我的 collisionBetween 函数,这很令人困惑,你的方法确实清理了一堆。非常感谢!

以上是关于可选展开 SKPhysics 错误的主要内容,如果未能解决你的问题,请参考以下文章

Swift 错误致命错误:在展开可选值时意外发现 nil

SpriteKit 展开可选错误 (Swift)

为啥我收到错误:致命错误:在展开可选值时意外发现 nil?

带有 `\(var)` 的字符串会导致“展开可选值”错误

致命错误:在展开可选值时意外发现 nil - 为啥?

SWIFT 致命错误:在展开可选值 (lldb) 时意外发现 nil