swift didBeginContact 错误,如果 运行 较新 iPhone 在模拟器中
swift error in didBeginContact if running newer iPhone in 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" 模拟中工作,并在更高版本中失败并显示此错误消息:
“致命错误:在展开可选值时意外发现 nil
(lldb)"
这是标记为红色的行:
if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000004"{
很高兴知道:
名称为“1000004”的对象是我在 "GameScene" class 中创建的 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"class中的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 位以确定精灵是活的还是死的,然后在 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
}
Seift 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
}
这是"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" 模拟中工作,并在更高版本中失败并显示此错误消息:
“致命错误:在展开可选值时意外发现 nil (lldb)"
这是标记为红色的行:
if contact.bodyA.node!.name == "0" && contact.bodyB.node!.name == "1000004"{
很高兴知道:
名称为“1000004”的对象是我在 "GameScene" class 中创建的 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"class中的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 位以确定精灵是活的还是死的,然后在 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
}
Seift 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
}