2016-09-15 40 views
3

好的 - 我确定这是重复的,Whirlwind或KnightOfDragons发布了一个解决方案,但我找不到它。Sprite-Kit为单个联系人注册多个冲突

我正在使用Sprite-Kit在Swift中编写Space Invader的克隆。我遇到的问题是,当入侵者的炸弹击中我的船时,代码有时会发生2或3次碰撞,立即结束游戏。下面是处理炸弹/船舶碰撞“didBeginContact”的部分:

case category.bomb.rawValue | category.ship.rawValue: 
     print("Bomb hit ship!") 
     let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node 
     bomb?.physicsBody?.contactTestBitMask = 0 // Seems to prevent multiple contacts with same bomb 
     ship.physicsBody!.contactTestBitMask = 0 // We'll reset this after the death animation 
     bomb?.removeAllActions() 
     ship.removeAllActions() 
     bomb?.removeFromParent() 
     ships -= 1 

     if ships == 0 { endScene(won: false, withMessage: "A bomb got you!") } 

,当我跑这场比赛我看:

Bomb hit ship! 
2 ships left. 

后1重弹击(这是正确的)

Bomb hit ship! 
1 ships left. 
Bomb hit ship! 
0 ships left. 

第二次炸弹袭击后(这是错误的)。

我从来没有联系方式没有被注册,有时(50%?)它完美的作品。其他时候我已经看到自己有四艘船!我相信这是明显的/基本的,但我却错了。

我对将炸弹和船舶设置为contactTestBitMask为0的意见显然是错误的。我知道这不应该是必要的,因为当接触发生时我移除了炸弹,所以它不应该再次发生。

如何保证联系人只处理一次?

================================

更新:我添加2个print报表提供更多调试信息:

 print("bodyA is \(contact.bodyA.node!.name)") 
     print("bodyB is \(contact.bodyB.node!.name)") 

这是let bomb = contact.bodyA.category ...语句之后,现在我得到:

Bomb hit ship! 
bodyA is Optional("bomb") 
bodyB is Optional("playerShip") 
1 ships left. 

后1弹击中,并且:

Bomb hit ship! 
fatal error: unexpectedly found nil while unwrapping an Optional value 

第二次炸弹袭击后。所以在第二次碰撞后,bodyA是零,所以我不明白为什么Sprite-Kit实际上发生了碰撞?

任何想法?

+0

Sprite-Kit已经排队等待船与炸弹之间的多重碰撞(它不应该但是嘿,谁知道),然后SK每次碰撞时都会调用dBC,因为我把炸弹第一次,第二次和以后都是零。所以我需要在炸弹下落时将其标记为激活状态,检查炸弹是否在我检测到碰撞时激活,并将其设置为不激活而不是在dBC中删除它? –

+0

从我所看到的情况来看,didBeginContact在两个物体之间有多个接触点时被多次触发。当您从纹理创建物体或者即使物体是圆形时,也可能发生这种情况。我目前无法真正找到自己的答案(我正在使用手机),但是这个解释了您遇到的崩溃:http://stackoverflow.com/a/37003007解决问题的方法很少。一种方法是检查node.parent是否为零,如果为true,则从didBeginContact返回。另一种方法是在子弹节点上标记。也许还有其他一些方法,我不记得更多。 – Whirlwind

+0

是@Whirlwind说过的,请记住,您确实不想在didcontactbegin阶段从父项中移除,因为可能有些情况下您需要节点仍然在场景中进行第二次联系(一个子项击中2个重叠敌人,也许你想要一个幽灵,谁知道)我个人喜欢保留categoryBitMask位31处理活着或死亡,并在物理检查期间,跳过这些节点 – Knight0fDragon

回答

1

确定 - 它会出现一个简单的:

 if bomb == nil {return} 

是所有的需要。这应该被添加如下:

 let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node 
     if bomb == nil {return} 

这工作,防止多次碰撞为您removeFromParentdidBeginContact一个节点。如果不删除节点但仍然注册多个冲突,则使用节点的userData属性来设置某种标志,指示该节点是我安全的(或者,子类SKSPriteNode并添加一个自定义的'isActive'属性,它就是我为解决我的问题而将子弹从一个入侵者身边移开,然后把那个入侵者和上面的那个入侵者取出来。这绝不会发生在'直接命中'上。

它不会回答的基本问题为为什么 SK正在注册多次碰撞,但它确实意味着我可以删除所有关于设置contactTestBitMasks为0,然后额外的代码回应该是什么以后等

编辑:所以看起来,如果删除了doBeginContact中的一个节点,该节点将被删除,但物理体不是。所以你必须小心,因为Sprite-Kit似乎建立了已发生的一系列physicsContacts,然后多次调用dBC,每次接触一次。因此,如果您正在操作节点并在dBC中删除它们,请注意,如果您强制展开节点的属性,则可能会遇到问题。

+0

这不会帮助你,你只是幸运。如果bodyA是炸弹呢?这意味着bodyA现在是零,这意味着你会碰撞'let bomb = contact.bodaA。categoryBitMask' – Knight0fDragon

+0

我以为炸弹将被设置为contact.bodyA.node,如果contact.bodyA.categoryBitMask == category.bomb.rawValue,否则它将被设置为contact.bodyB.node –

+0

E.G. bodyA是炸弹。在第一关中,你杀了炸弹,在第二个通过身体A现在死了,所以它是零。您现在会在'contact.bodyA.categoryBitMask == category.bomb.rawValue'上崩溃,因为您正在执行'nil.categoryBitMask == category.bomb.rawValue',这是不允许的,因为contact.bodyA不是可选的。如果它是可选的,那么炸弹就会变成另一个精灵,这也是不受欢迎的 – Knight0fDragon