Sprite-Kit, registering multiple collisions for a single contact

OK - I'm sure this is a duplicate, and that Whirlwind or KnightOfDragons have posted the solution, but I cannot find it.

I am writing a Space Invader clown in Swift using the Sprite-Kit. The problem is that when an invader bomb hits my ship, the code sometimes detects 2 or 3 collisions, ending the game right away. Here's the 'didBeginContact section, which handles a bomb / ship collision:

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!") } 

and when I start the game, I see:

 Bomb hit ship! 2 ships left. 

after 1 bomb hit (this is correct)

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

after the 2nd bomb strike (which is wrong).

I have never had a contact that does NOT register, and sometimes (50%?) Works fine. At other times, I saw myself with -4 ships! I am sure this is something obvious / fundamental that I am wrong, though.

My comments regarding setting the TestBitMask contact to 0 for the bomb and ship are obviously wrong. I know that this should not be necessary, as I remove the bomb when contact occurs, so it should not appear again.

How can I guarantee that a contact is processed only once?

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

Update: I added 2 print statements to provide additional debugging information:

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

This is after the let bomb = contact.bodyA.category ... instruction and now I get:

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

after 1 bomb hit and:

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

after hitting the 2nd bomb. So, after the second collision, body A is zero, so I don’t understand why the Sprite-Kit actually detected the collision?

Any ideas?

+3
source share
1 answer

OK - it would seem that simply:

  if bomb == nil {return} 

- all that is required. This should be added as follows:

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

This works to prevent multiple collisions for the node that you removeFromParent in didBeginContact . If you don’t remove node but still register some collisions, use the node userData property to set some flag indicating that node I am s'anactive "Alternatively, subclass SKSPriteNode and add the custom property isActive, which I did to solve my problem with bullets passing on the side of the invader and pull out that invader and the one above it. This never happens with a direct hit.

It does not answer the main question: why does SK register several collisions, but this means that I can remove all the additional code regarding setting contactTestBitMasks to 0, and then return to what they should be later, etc.

Edit: Thus, it seems that if you deleted the node in didBeginContact, the node is deleted, but the physical body is not. Therefore, you should be careful, since the Sprite-Kit seems to create an array of physical contacts that have occurred, and then calls dBC several times, once for each contact. Therefore, if you are manipulating nodes and deleting them in dBC, keep in mind that you may run into a problem if you force unpack the node properties.

+1
source

Source: https://habr.com/ru/post/1260074/


All Articles