1
votes

Okay I have some physics objects, and they are all nicely categorized, and my didBeginContact is properly fired, and does what it is supposed to do. The problem is this:

I have two categories of objects, say ball and paddle.... When the ball touches a paddle the ball should explode... simple enough.. The problem lies in that the ball could touch 2 paddles at the same time... So, more than one didBeginContact gets called, and as such more than 1 explosion happens (1 per paddle the ball contacted with).. So the problem I am trying to figure out is, how do I remove/ignore all subsequent contacts with paddles from being handled if the code has already handled a collision involving the original ball? Removing the SKSpriteNode from parent before starting the explosion does not nullify the other contacts, they still get handled... so how do I tell it.. HEY PHYSICS CONTACTS STUFF... that body is no longer in the picture... so just throw those contacts away and don't worry about them?

I suppose I could explicitly check that the parent still has the SKSpriteNode available in the contact code before doing the explosion etc, but that seems kludgy at best, though I suppose it would work... Is there another/better way to handle this? I have to believe there is.

2
you can use a flag for that if you want and set it as soon as the body collides for the first time and on the basis of that set flag you can perform an action then reset it,this is just one way to do it.spider1983
yes, and reset the flag in didSimulatePhysics or in updateLearnCocos2D
While that might save a few cycles of processing time, that's really no different than in the collision simply checking to see if the sprite node is still in the parent... Thanks for the suggestion though.Speckpgh

2 Answers

0
votes

The moment you get the contact, set the contactBitMask of the ball node's physicsBody as 0. I am assuming the node needs to be destroyed and does not need to be reused.

This should prevent multiple contacts from appearing for the same node.

If the above doesn't work, you can try the following methods:

  1. Removing the node from parent within the contact delegate, and triggering the explosion animation subsequently.
  2. Subclass SKSpriteNode or SKPhysicsBody for the ball nodes and add a property for eg. alreadyTouched. Then you can check and set the property from within the contact delegate.
0
votes

If you have three physicsBodies (ball, paddle1 and paddle2) and ball is set to collide with paddles (but paddles do not collide with each other) and the ball collides with 2 paddles during the same update cycle, then the game engine will generate 2 separate SKPhysicsContact objects - ball & paddle1 and ball & paddle2.

didBegincontact (Swift2) or didBegin(contact:) (Swift 3) (dBC for brevity) will then be called twice during the same update() cycle i.e. there will be 2 calls to dBC between calls to update()- firstly for the SKPhysicsContact between ball & paddle1 and then for the contact between ball & paddle2. You can do ball.removeFromParent() during the first contact, and the ball will be removed from the node tree but this will not prevent the second call to dBC for the ball & paddle2 collision and you will likely perform the same actions against ball (exploding, removing the score etc).

The simplest thing to do is to create a subclass of SKSPriteNode for your ball (ballNode?) and add a single property isActive, initialised to true. This is very easy.

In dBC, when the ball hits the paddle, check its isActive property and if false, simply return. If it's true, perform the normal collision actions and then set ball.isActive to false. When dBC is called the second time, the check against isActive will prevent any duplicate actions.

You could also use the ball's userData (part of SKSpriteNode) to store the isActive values to prevent subclassing, if you'd prefer that.

There are other ways to handle this issue, but so far I've found this one to work and to be the simplest.