Ios 来自纹理的SKPhysicsBody在Spritekit中碰撞时提供null

Ios 来自纹理的SKPhysicsBody在Spritekit中碰撞时提供null,ios,swift,sprite-kit,skspritenode,skphysicsbody,Ios,Swift,Sprite Kit,Skspritenode,Skphysicsbody,我正在创建一个游戏,在游戏中角色跳跃并收集点(一些物体)。点击角色时,从atlas执行一些动画。当它接触到分数时,分数增加1。我正在使用SKTexture创建角色的物理体。当我的角色接触到这个点时,它崩溃并显示这个错误 fatal error: unexpectedly found nil while unwrapping an Optional value //代码 Cat = SKSpriteNode(imageNamed: "cat"); Cat.size = CGSize(wi

我正在创建一个游戏,在游戏中角色跳跃并收集点(一些物体)。点击角色时,从atlas执行一些动画。当它接触到分数时,分数增加1。我正在使用SKTexture创建角色的物理体。当我的角色接触到这个点时,它崩溃并显示这个错误

fatal error: unexpectedly found nil while unwrapping an Optional value 
//代码

 Cat = SKSpriteNode(imageNamed: "cat");
  Cat.size = CGSize(width: 100, height: 100)
  Cat.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)

  //physics 
  Cat.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "cat"), size:CGSizeMake(100, 100))
但如果我从矩形或圆形创建Physicsbody,它就可以正常工作。也许这与我用来为角色设置动画的地图集有关

Cat.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.width/2)
当角色接触蘑菇时,它会崩溃。
工作演示:

代码的问题是,
didBeginContact
被多次调用。。。您可以通过将
print()
语句放入
if
块中来检查这一点

如您所知,
SKPhysicsBody
对象有一个名为
node
的属性。它是可选属性。它表示此实体连接到的节点。在您的例子中,这是一个蘑菇节点

因此,当第一次调用
didBeginContact
时,因为您从其父节点删除了一个蘑菇节点,
bodyA.node
将变为
nil
。下次执行
bodyA.node!。removeFromParent()
将产生崩溃,因为正如我所说,
bodyA.node
现在为nil,但您正在使用强制展开来访问可选值的基础值

仅当基础值不是零(或者在开发阶段有意触发错误)为100%正时,才使用强制展开。否则,请使用可选绑定或可选链接。像这样:

func didBeginContact(contact: SKPhysicsContact) {

    var firstBody, secondBody: SKPhysicsBody

    //Do this to avoid double checking
    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {

        firstBody = contact.bodyA
        secondBody = contact.bodyB
    } else {

        firstBody = contact.bodyB
        secondBody = contact.bodyA
    }

    //No need for double-checking now
    if ((firstBody.categoryBitMask & PhysicsCategory.Panda) != 0 &&
        (secondBody.categoryBitMask & PhysicsCategory.Score != 0)) {

            //This will fail gracefully if node property is nil
            secondBody.node?.removeFromParent()
    }
}
func-didBeginContact(联系人:skphysiccontact){
var firstBody,secondBody:SKPhysicsBody
//这样做可以避免重复检查
如果contact.bodyA.categoryBitMask
看看这是否有任何帮助:@whirwind it not helpOK,那么哪一行代码崩溃了?bodyA.removeFromParent()@AliBeadle
convency init
imageNamed`cannot return nil。它搜索捆绑包中的图像,然后如果需要,继续搜索地图册,如果搜索失败,它将创建一个占位符纹理图像(缺少资源图像)。感谢您的帮助。我将尝试这个,并将其标记为有用的答案。你们能解释一下,当物理体被指定为圆形或矩形时,为什么会这样做吗?@Nakib我无法详细说明,因为SpriteKit内部并没有记录如何处理不同形状物理体的接触检测。。。在你的例子中,我能看到的是,如果你创建一个矩形物理体,
didBeginContact
只被调用一次。因此,您永远不会遇到
bodyA.node
nil
的情况。这就是它工作的原因(意味着没有崩溃)。不过,正如您所看到的,强制展开并不是最安全的方式。这修复了崩溃,但我在didbeginContact中安装了scoreGenerator()。一旦蘑菇被移除,它会在任意位置再次生成蘑菇。通过将代码更改为上方,它现在正在连续调用该函数。@Nakib我假定您的意思是
generateScoreNode()
,而不是
scoreGenerator()
。如果是这样,您所看到的与您的代码逻辑相关。您每次都在同一位置创建蘑菇。当一个新的蘑菇产卵时,蘑菇和玩家之间会发生接触,因为玩家实际上正在移动。所以蘑菇得到繁殖,然后立即移除,然后繁殖,等等。一个无限循环。我不清楚你希望看到什么。你看到的是你自己定义的(意思是你没有在代码中另外说明)。在演示中,它在固定位置生成蘑菇,但在实际游戏中,它在随机位置生成蘑菇。谢谢,尽管我现在一切正常:)