我正在用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'
答案 0 :(得分:2)
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
}
}
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等)正确设置了面具
,这就是独特联系人的方式