提问人:Fayyouz 提问时间:7/18/2017 最后编辑:CommunityFayyouz 更新时间:7/18/2017 访问量:82
SKPhysicsContact 崩溃的扩展
extension for SKPhysicsContact crashing
问:
我正在用 SpriteKit 创建一个游戏,它在 2 个身体之间发生碰撞。设置好身体后,我实现了moetod,如下所示:didBegin(_contact:)
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == 0 && contact.bodyB.categoryBitMask == 1 {
gameOver()
}
}
它工作得很好。
后来,在检查此方法的文档时,我发现了以下内容:
接触参数中描述的两个物理实体不按保证顺序传递。
因此,为了安全起见,我使用一个函数扩展了该类,该函数在两个主体之间交换 categoryBitMask,如下所示:SKPhysicsContact
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:and:]:无法识别的选择器发送到实例0x60000028b950”
答:
SKPhysicsContact
是一个包装类,你正在扩展,但实际上你需要扩展(你不能这样做)PKPhysicsContact
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
}
}
顺便说一句,对于看到这个答案的人来说,categoryBitMask 0 不应该触发任何联系人,你需要某种值才能工作。这是一个超出作者问题范围的错误,所以我将其保留在 0 和 1 处,因为这是他/她的代码正在做的事情,并且他声称它有效。
评论
这显然是一个错误,正如这里回答的那样: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 等)正确设置口罩,这就是您获得唯一联系人的方式
评论
The two bodies described in the contact parameter are not passed in a guaranteed order.
评论
0 | 1