Spritekit contact detection crash(EXC_breakpoint) - swift

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.

Related

Unity - two human players, how to detect which player did most damage to AI enemy?

I truly apologize for I have no code to offer here.
I am completely stumped, I’m still a coding noob and trying to run a simple exercise to test a game mechanic idea via prototype.
I’ll use a simple example:
2 players vs. 2 AI enemies
both enemy ai have 400 points of health
both human players have guns that do 20 points of damage per trigger
press.
both enemies are dead after a quick battle.
I want to reward the player who did the most damage to the enemies.
This is what I am trying to achieve:
How do I go about detecting, which player, did the most damage to the enemy AI?
Any help would be appreciated, once I can grasp the concept of how to even go about doing this, I can then move forward on how to code it.
Thanks.
The question is too general - there are a lot of ways to do this. Let's stick to OOP: let's make the "damage" object (script, class), which contains the following info: damage amount, player id. Wheh player hits trigger, lets assume, the bullet prefab is instantiated. It has a script (MonoBehaviour) on it, called "DamageContainer". When you instantiate a bullet, you also create your "damage" object, set correct values, and put it into bullet's "damage container". Then, when bullet collides with enemy, you get this info from bullet. Damage amount you use to reduce enemy's health. For counting damage, you need the counter itself. It can be a static class, a scriptable object, singleton, or something else. Let's use a static class, which is not the best practice, but simplest one. You need a simple static class, called "DamageCounter", and containing two public fields: Player1Damage and Player2Damage. When bullet collides with enemy, you need to add dealt damage to proper field of "DamageCounter", depending of damage.PlayerId field.
And don't forget to reset static class values on start of each battle.

Check if a specific node is near another one SpriteKit, Swift

I'm currently working on a game and when an enemy is shot I want to check if there's a protector enemy to take the damage instead of the one shot.
How can I check if there's this type of enemy within a certain distance of the enemy shot ?
I thought about enumerateChildNodes but I should change the name of the protectors and this doesn't help to count them as enemy in many functions
Thank you !
Is a "protector" enemy always associated with an enemy? Can you link the two with a protector optional property?
If not, you'll need to search using the radius from the enemy's position
Then search that array of nodes for the protector enemy, and pick the first (or one at random) to damage instead.

How to track multiple collisions between 2 sprites?

Here's an example, just for ease of understanding:
Sprite A is a ball. Sprite B is a cube. When the ball touches the cube once, I want the label to say first contact. When the same ball touches the same cube again, I want the label to say second contact. When the same ball , touches the same cube again, I want the label to say third contact.
How do I accomplish this?
It seems Sprite kit only allows 1 hit collisions between sprites to be programmed, which is enormously limited, in my opinion. Especially, since I want to create an enemy that actually changes behaviour dependant on the amount of hits it receives from the player, not just the same action for every collision.
Figured out a way. If you assign sprite A with points and use a cumulative score to keep track of the points you can then then use "score" as a collision counter. So each time sprite A touched Sprite B the score would increment by 10 points, simply then saying if score == 100 for example ... program something or if score == 150 ... program something (did begin method) and it worked, allowing you to program different actions or whatever at each point of collision with the same sprites! Awesome. Didn't think it would work but it did :)

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

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.

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! :)