SKPhysicsContact when object collides with more than 1 object, handle first, ignore all others.. how? - sprite-kit

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.

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:
Removing the node from parent within the contact delegate, and triggering the explosion animation subsequently.
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.

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.

Related

SKEmitterNode tied to a moving SKNode

I am attempting to move a SKEmitterNode to follow a bullet in my game to give it a trailing effect however, no matter which way I attempt to implement this, it doesn't seem to work how I want it to and I'm at a loss for how to make this.
I have attempted to add the emitter to my main scene and manually moved the node a few times per second but it ends up not leaving a trail and keeping all the particles in one place like this:
Next I attempted to set the target node, however when I do this the trail goes for a bit then stops rather than following the bullet like it's supposed to. It also rotates and distorts from the rotation of the projectile like shown here:
For reference of the type of effect I'm looking for:
You should populate the targetNode property of your emitter with a node that is not moving like the scene.
emitterNode.targetNode = self // where self is the current scene

Spritekit contact detection crash(EXC_breakpoint)

I set up a game where the player controlls a ship and shoots the incomming enemies. When One Bullet and ONE enemy make contact, there is no crash but when two bullets hit 2 different enemis i got a crash in the following func.(EXC_Breakpoint) (all bullets has the same physicCategory and all enemy has the same physicsCategory.
How can I solve this?
Thanks!
if body1.categoryBitMask==PhysicsCategories.Bullet && body2.categoryBitMask==PhysicsCategories.Enemy && (body2.node?.position.x)!<self.size.width{
All Sprite-Kit collisions are between 2 bodies - you can’t have 2 bullets hit 2 enemies. If it looks as though 1 bullet has hit 2 enemies at the same time, what you will actually get is a call to didBegin() for the bullet and one enemy and another call for the bullet and the other enemy. However, if you do removeFromParent() for the bullet for the first collision, then you may have problems for the second collision as the bullet node will be nil, although the bullet’s physics body will still be there.
Search on SO for “Sprite Kit multiple collisions” as this is a common problem and there are several ways to handle it. The easiest way to describe is instead of doing removeFromParent for nodes that should be “destroyed”, add them to an array (or more properly, a set). Then in didFinishUpdate, iterate over this set and remove all the nodes that are in it.

PhyscisBody pass though another PhysicsBody while still detecting collision

I'm making a game with swift 3 and spritekit and I need a way to have an object with a physicsbody pass through another physicsbody while still detecting the collision but not bouncing off of it (sort of a checkpoint system so I can tell how many stages the player has gone through)
As pointed out by #PauloMattos; setting the contactTestBitMask of the two objects will fire the didBegin func where you can check which objects have collided and increment your stages if needed. If you don't have the collisionBitMask set for those two objects the objects will pass through each other vs. bouncing off each other.
It is also worth pointing out that when detecting contact the didBegin func will keep detecting the contact the whole time that the object is travelling through the other object. This could result in your stages getting incremented hundreds of times instead of once. What you can do is set a flag once you detect that contact so that you can filter out the rest of the contact between the two objects.

Instantaneous hit detection with SpriteKit

What is an effective method to perform instantaneous hit detection in SpriteKit? Using SpriteKit's built in physics engine I want to collect affected objects during a single frame for situations such as an explosion's blast radius.
I have considered adding an SKNode with SKPhysicsBody to the explosive object and accessing its allContactedBodies property when it explodes but this would add unnecessary collision detection to other frames.
I have also considered adding an SKNode with SKPhysicsBody to the scene or altering an existing one at the time of explosion and using an action to remove or restore the node after a short duration but this feels unnecessarily complex and may delay the hit detection until the next frame.
I have wondered if there is a means to extend SKPhysicsWorld to allow for enumerating bodies with a circle in addition to a rectangle - or to extend SKPhysicsBody to allow manual collision detection with another test body.
However, I do not see how to access an SKPhysicsBody's shape data to do either of these.
If I were to tackle this problem I would do it by creating a node with a physics body and then messing with its dynamic, categoryBitMask, and collisionBitMask properties. I would set dynamic to false since theoretically the collision/explosion doesn't move because it hits other objects. I would set its categoryBitMask so that every object generated a "didBeginContact" report when colliding with it. And I would set its collisionBitMask so that it never caused impulses because of collision. This way the physicsBody is more of a probe then an actual physics object, just being what is their.
At the end of that the physics body should cause collision reports but not repel any objects. Obviously you can create this body and just not have it added to the scene until it is actually time to detect things. Then after that frame is over and you know all the physics bodies it touched you can remove it again.
Then I would set the scene as a physicsContactDelegate and impliment the did begin contact method.
class GameScene: Scene, SKPhysicsContactDelegate {
func didBeginContact(contact: SKPhysicsContact)
{
var AName:NSString = NSString(string: contact.bodyA.node!.name!)
var BName:NSString = NSString(string: contact.bodyB.node!.name!)
}
}
Then I would have if statements checking if either AName or BName were the name of your "probing" node/physicBody. Then after that you can add code to do whatever you want as a result of that collision.
Good luck! If you are having troubles with the bit mask properties I would strongly suggest checking out this.

How to detect collision between three objects simultaneously in Box2D?

I am new to Objective-C. I am currently working on a game using Cocos2D and Box2D. My problem is that when 3 objects collide together, the game crashes. Now let me describe my game in details:
In my game I have a main character standing on top of a building. Below the building there's this the road. Enemies pass by the road at various random speeds entering the screen from right and exiting from the left. I have created the enemies as b2_kinematicBodies and set a random velocity for each of them using SetLinearVelocity(). The main character shoots the enemies. The projectile (the object being shot) is a b2_dynamicBody. When the projectile hits the enemies, both the projectile and the enemy are destroyed. During gameplay sometimes an enemy moving at a slow speed is crossed by one which is moving at a higher speed. If a projectile hits the two enemies just at the point when they are overlapping and one is about to pass the other one, the game crashes! Please help me with this.
I have detected collision using b2contactListener class.
One thing I didn't mention before is that I am not creating the enemies as individual distinct bodies. Instead, I am creating it once and making it move and I am calling this method (which creates the enemies and makes them move) inside init as below:
[self schedule:#selector(addRightTarget) interval:2.0];
I believe the issue is that the collisions are calculated before your handler gets any calls. Meaning that when your handler gets called, the bullet has hit 2 objects. So you get 2 call-backs as shown below.
Collision Detected: Bullet + Enemy1
Destroy Enemy1
Destroy Bullet
Collision Detected: Bullet + Enemy2
Destroy Enemy2
Destroy Bullet [CRAAAASH!!! You just tried to delete a non-existent object]
1st: You should not be removing anything except in your step function (as someone mentioned in another answer)
2nd: Pick one of these:
Make your list/array of objects-to-delete be a 'set' or implemented in such a way that duplicates are avoided.
Check for existence of your object in the world
The collision only happens between 2 objects in Box2D. So in your mentioned scenario your will get multiple collision events which could be,
Enemy-1 and Enemy-2
Enemy-1 and Bullet
Enemy-2 and Bullet
So one possible reason of crash could be that you are not expecting (Enemy-1 and Enemy-2) collision and you are handling it like you have collision between (Enemy-1 and Bullet) so you might be casting it into wrong class. Make sure you are checking the kind of class "isKindOf" before casting it.
Also you may want to use Contact Filtering and or assign category masks to your enemies so that they don't collide with each other and only collide with bullet.
But it will be more help full if you tell something about how and where you destroy your bodies (I hope its not inside your Collision Detection Functions) and also if you can share the exception text when your application crash, that will be helpful.
I used a rather cheap workaround. I alternately created enemy fixtures of different sizes(differing by few pixels). So now if i shoot them even when they overlap, the app doesn't crash(because only the bigger object collides and gets destroyed). This serves my purpose. Thanx a llot for your help. I really appreciate it! :)