Swift Spritekit I Detect a Collison But It Reads the Collision Mulitple Times

Sprite-Kit registering multiple collisions for single contact

OK - it would appear that a simple:

        if bomb == nil {return}

is all that's 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 a node that you removeFromParent in didBeginContact. If you don;t remove the node but are still registering multiple collisions, then use the node's userData property to set some sort of flag indicating that the node i s'anactive' Alternately, subclass SKSPriteNode and add a custom 'isActive' property, which is what I did to solve my problem of bullets passing up the side of an invader and taking out that invader and the one above it. This never happens on a 'direct hit'.

It doesn't answer the underlying question as to why SK is registering multiple collisions, but it does mean that I can remove all the extra code concerning setting contactTestBitMasks to 0 and then back to what they should be later etc.

Edit: So it appears that if you delete a node in didBeginContact, the node is removed but the physics body isn't. So you have to be careful as Sprite-Kit appears to build an array of physicsContacts that have occurred and then calls dBC multiple times, once for each contact. So if you are manipulating nodes and also removing them in dBC, be aware that you might run into an issue if you force unwrap a node's properties.

Why are didBeginContact called multiple times?

I had the same problem (score increasing multiple times for a single enemy destroyed and multiple life points being lost for a single instance of damage.) A user on the Apple forums thinks that it's a bug in [SKPhysicsBody bodyWithTexture:size:] but I don't believe that's the case, because it was happening with other constructors too.

First off, the categoryBitMask and contactTestBitMask are very important, obviously. Take a look at Apple's SpriteKit Physics Collisions sample code:

// Contacts are often a double dispatch problem; the effect you want is based on the type of both bodies in the contact. This sample this in a brute force way, by checking the types of each. A more complicated example might use methods on objects to perform the type checking.

// The contacts can appear in either order, and so normally you'd need to check
each against the other. In this example, the category types are well ordered, so
the code swaps the two bodies if they are out of order. This allows the code
to only test collisions once.

What I did to solve it was setting a flag after handling each condition. In my case, I was testing whether bodyA.node.parent was nil in didBeginContact, because I called removeFromParent() on the missile/enemy nodes to destroy them.

I think you should expect the event to fire multiple times and your code in there has to make sure it's processed only once.

Collision detection leading to color detection?

My suggestion is that your change your "pair" of walls to become a trio of walls instead. This third wall should have a different categoryBitMask. (PhysicsCategory.wallSpace seems to fit with your current naming scheme.)

This "wallSpace" needs to be positioned between the two existing walls. It should be given the same color as its siblings through your color-change logic, but here comes the trick: set it's alpha to 0.

This way you can check for collisions between this invisible wall and your ball and perform actions based on the color-information.

SpriteKit crash: how can physics body lose association with SKNode?

An SKSPhysicsBody is an object in itself and perfectly capable of being created yet not associated with an SKSpriteNode (although perhaps not of much use :-) )

In your didBallTileHit(), do you removeFromParent() any of the nodes? If so, this is probably the cause of your crash in that Sprite-Kit has generated multiple collisions between 2 objects and is calling didBegin() several times for the 2 nodes. If you then go and remove one of the nodes in the 1st call to didBegin(), it won't be there for the 2nd and subsequent calls.

The way to handle it (you can't get sprite-kit to NOT call didBegin multiple times in some circumstances) is to make sure that your contact code accommodates this and that handling the contract multiple times does not cause a problem (such as adding to the score multiple times, removing multiple lives, trying to access a node or physicsBody that has been removed etc).

For more detail and possible solutions, see this answer : https://stackoverflow.com/a/44384390/1430420

SpriteKit's didBeginContact can't be called

Find out the reason. Need use

s1.physicsBody!.dynamic = true
s2.physicsBody!.dynamic = true


Related Topics



Leave a reply



Submit