Sprite-Kit为单个接触注册多个冲突

好的 – 我确定这是重复的,旋风或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.

1枚炸弹袭击后,:

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

在第二枚炸弹袭击之后.所以在第二次碰撞之后,bodyA是零,所以我不明白为什么Sprite-Kit实际上已经注册了碰撞?

有任何想法吗?

最佳答案 好的 – 看起来很简单:

        if bomb == nil {return}

就是这一切.这应该添加如下:

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

这可以防止您在didBeginContact中删除了ofFromParent的节点发生多次冲突.如果你没有删除节点但仍在注册多个冲突,那么使用节点的userData属性来设置某种标志,指示节点我是主动的’或者,子类SKSPriteNode并添加一个自定义’isActive’属性,是我所做的,以解决我的子弹从入侵者的一侧传递并取出入侵者及其上方的问题.这种情况从未发生在“直接命中”上.

它没有回答SK为什么注册多个冲突的基本问题,但它确实意味着我可以删除所有关于将contactTestBitMasks设置为0的额外代码,然后再回到它们应该在以后的内容等.

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

点赞