Sprite-Kit为单个接触记录多个碰撞



OK -我确定这是一个副本,Whirlwind或knighttofdragons已经发布了解决方案,但我找不到它。

我正在使用Sprite-Kit在Swift中编写《Space invaders》的克隆版本。我遇到的问题是,当入侵炸弹击中我的飞船时,代码有时会记录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是nil,所以我不明白为什么Sprite-Kit实际上注册了一个碰撞?

任何想法?

OK -看起来一个简单的:

        if bomb == nil {return}

是所有需要的。应该按如下方式添加:

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

这可以防止在didBeginContactremoveFromParent的节点发生多次碰撞。如果您不删除节点,但仍然注册多个碰撞,然后使用节点的userData属性设置某种标志,表明节点是"非活动的"。或者,子类SKSPriteNode并添加自定义的"isActive"属性,这就是我所做的,以解决我的问题子弹传递到入侵者的一边,取出入侵者和它上面的一个。"直接命中"不会发生这种情况。

它没有回答关于为什么 SK正在注册多个碰撞的潜在问题,但它确实意味着我可以删除所有关于设置contacttestbitmask为0的额外代码,然后回到它们应该是什么等。

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

最新更新