如果在模拟器中运行较新的 iPhone,didBeginContact 中会出现快速错误

标签 swift sprite-kit contacts simulator

这是“didBeginContact”方法中的代码:

        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask
    {

        if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000003"{

            contact.bodyB.node!.removeFromParent()
        }
        if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000004"{

            contact.bodyB.node!.removeFromParent()
        }

    }

    else

    {
        if contact.bodyB.node!.name == "0" && contact.bodyA.node!.name == "1000003"{

            contact.bodyA.node!.removeFromParent()
        }
        if contact.bodyB.node!.name == "0" && contact.bodyA.node!.name == "1000004"{

            contact.bodyA.node!.removeFromParent()
        }
    }

它在“iPhone 4s”和“iPhone 5”模拟中工作,并在更高版本中失败并显示此错误消息:

“ fatal error :在展开可选值时意外发现 nil (lldb)”

这是标记为红色的行:

if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000004"{

很高兴知道: 名称为“1000004”的对象是我在“GameScene”类中创建的 SKSpriteNode:let TestPixel = SKSpriteNode(imageNamed: "6")

此对象的属性位于“touchesBegan”方法中。 这是代码:

            TestPixel.name = "1000004"
            TestPixel.anchorPoint = CGPointMake(0.5, 0.5)
            TestPixel.userInteractionEnabled = false
            TestPixel.zPosition = 1000003
            TestPixel.size = CGSizeMake(1, 1)
            TestPixel.position = CGPointMake(positionInScene.x, positionInScene.y)
            TestPixel.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "6"), size: TestPixel.size)
            TestPixel.physicsBody?.categoryBitMask = ClickOnCategory
            TestPixel.physicsBody?.contactTestBitMask = BuildingsCategory
            TestPixel.physicsBody?.affectedByGravity = false
            TestPixel.physicsBody?.dynamic = true
            TestPixel.physicsBody?.collisionBitMask = 0
            addChild(TestPixel)

如果此 SpriteNode(name:"1000004") 命中我在“didMoveToView”方法中创建的另一个 SpriteNode,则会发生错误,代码如下:

func addBG(){

        let background = SKSpriteNode(imageNamed: "0")
        background.name = "0"
        background.anchorPoint = CGPointMake(0.5, 0.5)
        background.zPosition = 1
        background.position = CGPointMake(CGRectGetMinX(self.frame)+self.frame.width/4,CGRectGetMaxY(self.frame)-self.frame.height/4)
        background.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "0"), size: background.size)
        background.physicsBody?.categoryBitMask = BuildingsCategory
        background.physicsBody?.affectedByGravity = false
        background.physicsBody?.dynamic = true
        background.physicsBody?.collisionBitMask = 0
        self.addChild(background)

    }

    addBG()

在“didMoveToView”中也是:

physicsWorld.contactDelegate = self

“GameScene”类中的categoryBitMask是这样设置的:

class GameScene: SKScene, SKPhysicsContactDelegate{

let BuildingsCategory  : UInt32 = 0x1 << 1
let ClickOnCategory : UInt32 = 0x1 << 2

是的,正如我所说,它可以在“iPhone 4s”&&“iPhone 5”的模拟器中运行,但不能在更高版本中运行……有什么想法吗? 谢谢

最佳答案

是的,我可以告诉你原因:

if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000003"{
    contact.bodyB.node!.removeFromParent() <----PROBLEM
}
if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000004"{
    contact.bodyB.node!.removeFromParent()
}

发生了什么事,你正在点击你的第一个 if 语句,它从父级中删除,然后你试图再次访问它。好吧,如果你从父节点中删除,是什么在内存中维护节点?可能什么都没有,所以在第一行,它消除了节点。然后你的代码继续进入另一个 if 条件,你现在正试图打开一个 nil。这是您将使用 ELSE IF 而不是 if 的地方。

我强烈建议使用 sprite kit 做的另一件事是永远不要在接触阶段移除节点。您可能会发生多个联系,并且您可能需要处理所有这些联系情况,因此最好让节点保持事件状态。

相反,每当您想要删除节点时,将它们放入队列(数组或集合),然后在您的 didFinishUpdate 方法中循环遍历队列并删除所有节点。

我做的另一个技巧是,我在 categoryBitMask 上保留第 31 位以确定 Sprite 是活的还是死的,然后在 didContact 方法上,我对其进行了防范。

例如

func didBeginContact(contact: SKPhysicsContact!)
{
    guard let bodies = (a:contact.bodyA,b:contact.bodyB) where a.categoryBitMask < 1 << 31 && b.categoryBitMask < 1 << 31
    else
    {
        return
    }
    // do other work here
}

赛夫特 3.0

func didBeginContact(contact: SKPhysicsContact!)
{
    guard let bodies = (a:contact.bodyA,b:contact.bodyB, a.categoryBitMask < 1 << 31 && b.categoryBitMask < 1 << 31
    else
    {
        return
    }
    // do other work here
}

关于如果在模拟器中运行较新的 iPhone,didBeginContact 中会出现快速错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39082179/

相关文章:

swift - 与社交媒体分享高分

android 添加联系人到手机

swift - 在 Swift 的 Sprite 工具包中制作一个弹出窗口

ios - 如何停止将超链接移动到新行 UITextView

ios - SpriteKit SKPhysicsBody applyTorque 导致 Sprite 位置改变

ios - 场景更改后音乐停止播放 SKAudioNode Xcode 8

iOS-如何获取位置和联系信息的权限

android - 如何在android中识别本地电话联系人和SYNC电话联系人?

json - Swift:使用 Alamofire 访问 JSON 中的字典和模型中的私有(private)变量

ios - 为什么在 Swift 中初始化类时不需要所有对象?