我正在创建一个与SpriteKit的游戏,它有两个身体之间的碰撞。在设置了主体之后,我实现了didBegin(_contact:)方法,如下所示:
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 Retro17606:735367 -PKPhysicsContact bodiesAreFromCategories:和::未识别的选择器发送到实例0x60000028b950 2017-07-18 13:44:18.563 iSnake Retro17606:735367 *终止应用程序由于未被识别的异常'NSInvalidArgumentException',原因:'-PKPhysicsContact bodiesAreFromCategories:和::未识别的选择器发送到实例0x60000028b950‘
发布于 2017-07-18 12:03:58
这显然是一个bug,在这里回答:https://stackoverflow.com/a/33423409/6593818
问题是,联系人的类型是PKPhysicsContact (正如您已经注意到的),即使您明确告诉它是SKPhysicsContact,并且扩展位于SKPhysicsContact上。您必须能够对PKPhysicsContact进行扩展才能工作。根据这个逻辑,我们可以说,目前没有实例方法在SKPhysicsContact扩展中工作。我想说这是SpriteKit的一个bug,你应该设置一个雷达。类方法仍然工作,因为您在类本身上调用它们。 同时,您应该能够将该方法移动到您的场景或其他对象中,并成功地将其调用到其中。 请注意,这并不是一个针对Swift的问题。如果您在SKPhysicsContact上的Objective类中使用相同的方法,您将得到相同的崩溃。
你可以向苹果提交一份错误报告:
https://developer.apple.com/bug-reporting/
并向社会报告:
https://openradar.appspot.com/search?query=spritekit
但是,您真正想要对代码做的是将类别掩码添加到一起。然后检查和(2 +4和4+2总是等于6,而不考虑bodyA和bodyB顺序)。
这就是你如何获得独特的联系人,如果你正确地设置你的面具的力量二(2,4,8,16等)
发布于 2017-07-18 11:57:12
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不应该触发任何联系人,您需要在其中有某种价值才能工作。这是一个超出作者问题范围的bug,所以我把它放在0和1,因为这是他/她的代码所做的,他(S)声称它可以工作。
https://stackoverflow.com/questions/45164773
复制相似问题