好的 - 我确定这是重复的,Whirlwind或KnightOfDragons已发布解决方案,但我找不到它。
我正在使用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%?)它完美无缺。其他时候我看到自己有-4艘船!我确定这是明显/基本的,但我错了。
关于将炸弹和船舶的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.
在一次炸弹袭击之后,并且:
Bomb hit ship!
fatal error: unexpectedly found nil while unwrapping an Optional value
第二枚炸弹袭击后。所以在第二次碰撞之后,bodyA是零,所以我不明白为什么Sprite-Kit实际上已经发生碰撞?
有什么想法吗?
答案 0 :(得分:1)
好的 - 看起来很简单:
if bomb == nil {return}
是所有必需的。这应该添加如下:
let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node
if bomb == nil {return}
这可以防止removeFromParent
中didBeginContact
的节点发生多次冲突。如果你没有删除节点但仍在注册多个冲突,那么使用节点的userData
属性来设置某种标志,表明节点是“非活动的”。或者,子类SKSPriteNode并添加一个自定义&#39; isActive&#39;属性,这就是我所做的解决我的子弹传递到入侵者一边并取出入侵者和上面的那个问题的问题。这绝不会发生在&#39;直接命中&#39;。
它没有回答为什么 SK正在注册多个冲突的基本问题,但它确实意味着我可以删除有关将contactTestBitMasks设置为0然后再返回的所有额外代码什么他们应该是以后等等。
编辑:所以看来如果你删除了didBeginContact中的一个节点,那么该节点就被删除了,但是物理主体并没有。所以你必须要小心,因为Sprite-Kit似乎构建了一个已经发生的physicsContacts数组,然后多次调用dBC,每次接触一次。因此,如果您正在操作节点并在dBC中删除它们,请注意,如果您强制解包节点的属性,则可能会遇到问题。