SKPhysicsContact崩溃

时间:2017-07-18 10:55:55

标签: ios swift sprite-kit crash skphysicscontact

我正在用SpriteKit创建一个游戏,它在两个物体之间发生碰撞。设置完尸体后,我已经实现了didBegin(_contact:) moethod,如下所示:

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

它完美无缺。

稍后,在查看此方法的文档时,我发现了以下内容:

  

联系参数中描述的两个物理主体不会以保证顺序传递

为了安全起见,我使用函数扩展了SKPhysicsContact类,在两个实体之间交换了categoryBitMask,如下所示:

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

问题是当调用该函数时,应用程序崩溃了,我收到以下错误:

  

2017-07-18 13:44:18.548 iSnake Retro [17606:735367] - [PKPhysicsContact bodiesAreFromCategories:and:]:无法识别的选择器发送到实例0x60000028b950

     

2017-07-18 13:44:18.563 iSnake Retro [17606:735367] ***由于未捕获的异常'NSInvalidArgumentException'终止应用程序,原因:' - [PKPhysicsContact bodiesAreFromCategories:和:]:无法识别的选择器发送到实例0x60000028b950'

2 个答案:

答案 0 :(得分:2)

SKPhysicsContactPKPhysicsContact的包装类,您正在扩展SKPhysicsContact但实际上您需要扩展PKPhysicsContact(您无法做到)

要保持联系方式的顺序,请执行以下操作:

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

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

这样,当您需要检查特定节点时,您知道要命中的节点,所以

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

变为

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

然后,您可以添加到您的代码,因为您现在知道各个机构。

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's add an emitter effect on bodyB.node
    }
}

BTW,对于看到这个答案的人来说,categoryBitMask 0不应该触发任何联系人,你需要某种价值才能发挥作用。这是一个超出作者问题范围的错误,因此我将其保留为0和1,因为这是他/她的代码所做的以及他声称它有效。

答案 1 :(得分:2)

这显然是一个错误,如下所示: https://stackoverflow.com/a/33423409/6593818

  

问题是,联系方式是PKPhysicsContact(正如您已经注意到的那样),即使您明确告诉它是SKPhysicsContact,并且扩展名在SKPhysicsContact上。您必须能够对PKPhysicsContact进行扩展才能实现此目的。从这个逻辑来看,我们可以说目前没有实例方法可以在SKPhysicsContact扩展中起作用。我说它是SpriteKit的一个错误,你应该提交雷达。类方法仍然有效,因为你在类本身上调用它们。

     

与此同时,您应该能够将该方法移动到场景或其他对象中并成功调用它。

     

为了记录,这不是特定于Swift的问题。如果你在SKPhysicsContact的Objective-C类别中使用相同的方法,你将会遭遇同样的崩溃。

您可以向Apple提交错误报告:

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

并向社区报告:

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

但是,您真正要对代码执行的操作是将类别掩码添加到一起。然后检查总和(2 + 4和4 + 2总是等于6,不管bodyA和bodyB顺序)。

如果你以2的幂(2,4,8,16等)正确设置了面具

,这就是独特联系人的方式