Sprite kit Sprite套件记录单个触点的多个碰撞

Sprite kit Sprite套件记录单个触点的多个碰撞,sprite-kit,collision-detection,Sprite Kit,Collision Detection,好的-我确信这是一个复制品,Whirlwind或KnightOfDragons发布了一个解决方案,但我找不到它 我正在用精灵工具包用Swift写一个太空入侵者的克隆。我的问题是,当入侵者炸弹击中我的飞船时,代码有时会记录2到3次碰撞,立即结束游戏。以下是“didBeginContact”中处理炸弹/船只碰撞的部分: case category.bomb.rawValue | category.ship.rawValue: print("Bomb hit ship!")

好的-我确信这是一个复制品,Whirlwind或KnightOfDragons发布了一个解决方案,但我找不到它

我正在用精灵工具包用Swift写一个太空入侵者的克隆。我的问题是,当入侵者炸弹击中我的飞船时,代码有时会记录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次后(这是正确的)

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

我从来没有接触过没有注册,有时(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
中从父节点移除的节点发生多次冲突。如果你没有;t删除该节点,但仍在注册多个冲突,然后使用该节点的
userData
属性设置某种标志,指示该节点为'anaactive',或者子类SKSPriteNode并添加自定义'isActive'属性,这就是我所做的,来解决我的问题,子弹从入侵者一侧飞过,然后干掉那个入侵者和它上面的那个入侵者。“直接命中”时不会发生这种情况

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


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

答案是Sprite Kit排队等待飞船和炸弹之间的多次碰撞(不应该,但嘿,谁知道),然后SK为每次碰撞调用dBC,因为我第一次移除了炸弹,所以第二次和后续时间都是零。因此,我需要在炸弹掉落时将其标记为活动状态,在检测到碰撞时检查炸弹是否处于活动状态,并将其设置为非活动状态,而不是在dBC中将其移除?根据我所见,当两个实体之间存在多个接触点时,会多次触发didBeginContact。这可能发生在从纹理创建实体时,或者即使实体是圆形的。我现在真的找不到自己的答案(我在打电话),但这一条解释了你正在经历的崩溃:解决问题的方法很少。一种方法是检查node.parent是否为nil,如果为true,则从didBeginContact返回。另一种方法是在项目符号节点上设置标志。可能还有其他方式,我记不清了。是的@Whirlwind说了什么,记住,你真的不想在didcontactbegin阶段从父节点移除,因为可能有这样的情况,当你需要节点仍然在场景中进行第二次接触时(一颗子弹击中两个重叠的敌人,可能你想要一个幽灵,谁知道呢)我个人喜欢保留categoryBitMask位31来处理活人或死人,在物理检查期间,跳过这些nodes@Knight0fDragon也许吧,但我不想让炸弹到处乱窜——我想让它消失。这里肯定只有两个节点,我无法想象在幕后发生了什么。在一个测试项目中,我甚至尝试了3路碰撞,将3个sprite节点放置在彼此的顶部,dBC仍然会自己运行,被调用3次:一次用于a和B之间的碰撞,一次用于B和C之间的碰撞,另一次用于a和C之间的碰撞。如果我在第一次碰撞时移除节点A,它仍然可以工作…@Whirlwind-我看到的与您描述的匹配-两个实体之间的多个接触(都是由纹理创建的)。我不确定当其中一个实体为零时如何调用dBC,这对你没有帮助,你只是幸运而已。如果bodyA是炸弹呢?这意味着bodyA现在为零,这意味着您将在
let bomb=contact.bodaA.categoryBitMask
上崩溃,我认为如果contact.bodyA.categoryBitMask==category.bomb.rawValue,bomb将被设置为contact.bodyB.nodeE.G,则bomb将被设置为contact.bodyA.nodeE.node。身体是炸弹。在第一关你杀死了炸弹,在第二关bodyA现在死了,所以它是零。您现在将在
contact.bodyA.categoryBitMask==category.bomb.rawValue
崩溃,因为您正在执行
nil.categoryBitMask==category.bomb.rawValue
,这是不允许的,因为contact.bodyA不是可选的。如果它是可选的,那么bomb将成为另一个精灵,它也是可选的undesired@Knight0fDragon往回看一点,但是contact.bodyX.nodes中的一个肯定可以在接触期间设置为“nil”,尽管“contactTestBitMask”仍然设置。一个是第一次接触两个节点
        let bomb = contact.bodyA.categoryBitMask == category.bomb.rawValue ? contact.bodyA.node : contact.bodyB.node
        if bomb == nil {return}