Swift - Removing specific spawned enemy - ios

My code currently spawns a new enemy every second so there are multiple spawned enemies on the screen at the same time. I am able to detect a collision but I cannot figure out how to detect which enemy was hit so that I can remove it from the screen. Currently when a collision occurs and I remove the node from the screen, the last spawn enemy is removed and not the specific enemy that was hit. Any ideas on how to detect which spawned enemy was hit?

I assume you're using SpriteKit?
When you create a new enemy, you should give it a name. To do this, do enemyChildNode.name = "enemy". Then, when a collision is detected, use enumerateChildNodesWithName to check which node has collided.
This is how you declare this method:
func enumerateChildNodesWithName(_ name: String,
usingBlock block: ((SKNode!,
UnsafeMutablePointer<ObjCBool>) -> Void)!)
For more information on this go here.
So, you should use it like this:
enumerateChildNodesWithName("enemy") { node, stop in
let enemy = node as! SKSpriteNode
//check if enemy is being hit
//if true: enemy.removeFromParent()
}
I hope this helps you out!

Loads of ways to achieve this, one of the easiest is to have your enemy-sprites, but in my mind the easiest is to use the contactDelegate for your scene's physicsWorld.
In didBeginContact(contact: SKPhysicsContact) you can get the two colliding nodes by accessing contact.bodyA.node & contact.bodyB.node. Then your enemyNodes only need to have a wasHit() function which runs a removeFromParent action. (Implemented either trough subclassing or an extension).
Now, you probably need some logic to sort out the different types involved in the collission, but you have the options of checking on both class-type and categoryBitMasks.

Related

SpriteKit SKPhysicsBody collision in one direction like a door you can only go through but not back

In SpriteKit SKPhysicsBody is it possible to have an object you can pass through but not go back.
The idea is their is no collision in one direction so you go through and not go back, like a trap door.
I'm not quite sure one way physics are possible, but you should be able to mess with a physics body's collision bit mask while the game is running to achieve a similar affect.
So you have have your door in an open state, and when it detects the player is touching it*, it changes the bit mask so the player will collide with it. That should allow the player to go through one way, but not come back.
*In reality, have the door detect when the player is no longer touching the door via the player's physics body, and test the x or y location depending on if this is a trap door, or regular door. If the location is far enough away from the door, change the collision bit mask of the door so that the player can't go through.
The solution is just to change the collisionBitMask
func platformSolid() {
self.physicsBody?.collisionBitMask = kBIT_MASK_PLAYER | kBIT_MASK_WALL | kBIT_MASK_PLATFORM
}
func platformThrough() {
self.physicsBody?.collisionBitMask = kBIT_MASK_PLAYER | kBIT_MASK_WALL
}
self in this example is player Collision Bit Mask
In the delegate:
func didEndContact(contact: SKPhysicsContact) {
if contact.bodyB.categoryBitMask == kBIT_MASK_PLATFORM {
player.platformSolid()
}
}
So once the player has passed ( didEndContact ) you make the platform ( door ) solid.
The most straightforward way to do that would be to add two child sprites to the node representing top and bottom of the trap door. That way you can test which direction a colliding sprite is coming from, and enable/disable dynamics on the other as needed.
In your contact test of door and object, you need to check the direction the object is traveling (you can use velocity to get this). If the object is traveling in the direction that the door would block them, then you place a value on the doors categoryBitMask (set it in a way that it will AND with the nodes collisionBitMask to create a value > 0), otherwise you need to remove the doors categoryBitMask (or set it in a way it will not AND the nodes collisionBitMask so that it creates a value of 0)

Detect collision between particles and nodes in SceneKit

I have few nodes with a Kinematic phyisicsBodyType and I want it to interact with some particles System, and by that I mean that I want to detect collision and execute some code at the moment when node collide with nay particle from an particle system. I've found a way by adding an event handler, but I'm not quite sure how can I use it(link to method here).
Can someone explain me how can I use that event handler(preferred would be to explain me in Swift), or otherwise can you give me another idea?
In the end was very simple. First, you have to assign an array of nodes to the colliderNodes property of particle system. After that, code in swift looks something like that:
particleSystem.handleEvent(SCNParticleEvent.Collision, forPropierties:[SCNParticlePropertyContactPoint], withBlock: {
(data: UnsabeMutablePointer<UnsafeMutablePointer<Void>>, dataStride: UnsafeMutablePointer<Int>, indicies: UnsafeMutablePointer<UInt32>, count:Int) in
//code on detection collision goes here
})
Every parameter is briefly explained right in apple documentation.

SceneKit: How to detect contact without collision iOS

I'm making a Space Shooter game on Scene Kit and I want the asteroids to explode when the ship gets contact with them, I don't want them to collide, I just want to know when they contact each other.
The problem is that I don't know how to implement a collision detection when the ship intersects the asteroid. Like for example, I want Xcode to log "COLLIDED" when they actually get contact with each other.
I already added the categoryBitMask and the collisionBitMask for both objects. So, how could I achieve this? By the way, I'm doing everything on Swift.
SceneKit doesn't offer an option for separating contact detection from collision resolution for dynamic bodies. (If one of your bodies is a kinematic body, it won't have collisions resolved against it, but it won't be movable through physics either.) File a feature request?
However, it sounds like your use case is compatible with collision resolution — because the asteroids are exploding, you don't need to care about the effects of the collision on an asteroid (just remove it from the scene and replace it with explosion VFX, smaller asteroids, space slug, whatever). If the ship is meant to survive the collision and you don't want it to be affected by the collision, just set the relative masses of the ship and asteroid so that the asteroid won't impart significant momentum.
To do things when a collision occurs, you need to set a contact delegate on your scene's physics world. In whatever class is serving as your contact delegate, implement the didBeginContact method to be notified when a collision occurs.
In that method, you'll need to look at the contact's nodeA and nodeB to find out what categories of bodies collided (and which is which). Once you know that, e.g., nodeA is a ship and nodeB is an asteroid (or vice versa), you can kill the asteroid, update your score, etc.
I got this to work with a much simpler answer.
On the node you want things to fall through, set the physics mass to a very small number:
ship.physicsBody.mass = 0.00000000000001;
At the end I figured out how to solve this.
First I added the categoryBitMask and the collisionBitMask for both objects, the spaceship and the asteroids.
ship.physicsBody?.categoryBitMask = 2
asteroid.physicsBody?.categoryBitMask = 4
ship.physicsBody?.collisionBitMask = 4
ball.physicsBody?.collisionBitMask = 2
Then I gave a dynamicBody() to both of them.
ship.physicsBody = SCNPhysicsBody.dynamicBody()
asteroid.physicsBody = SCNPhysicsBody.dynamicBody()
Then I added a NSTimer to help me with the contact detection to update each 0.1 seconds to see if there is a contact.
override func viewDidLoad()
{
NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "checkContact", userInfo: nil, repeats: true)
}
func checkContact()
{
if (self.scene.physicsWorld.contactTestBetweenBody(ship.physicsBody, andBody: asteroid.physicsBody, options: nil) != nil)
{
println("CONTACT!")
}
}
I didn't needed to add the SCNPhysicsContactDelegate to my view, but is better to add it to be sure there are no syntax problems or warnings.
And that's it!
NOTE: It's important to add a dynamicBody() or staticBody() to our 3D objects, otherwise it won't have a contact. And it's important to add the dynamicBody() or staticBody() to our 3D objects BEFORE we add them as a child to our scene.
Hope this helps someone!

Why are didBeginContact called multiple times?

In an iOS game that uses Sprite Kit along with the contact detection in Sprite Kit's build-in physics engine, I decrease the Hero's number lives by one each time he gets in contact with an enemy. This is done from the didBeginContact method.
However, it seems like that method is not just called once, when the contact begins, but called continuously as long as the Hero and the enemy overlaps: when I set a breakpoint in that method, I can see, that it is the exact same physics body instances that exist as contact.bodyA and contact.bodyB. The result is, that the Hero will lose multiple lives, even though he only passes one single enemy.
If the Hero meets the same enemy again later, he should get one more live subtracted, and therefore I cannot just maintain a seenEnemies hash set to deal with the problem above.
The question is now: how would you make sure that only one live is subtracted for each Hero/enemy contact?
The reason why the didBeginContact is being fired multiple times is because you have multiple contact points happening on concave shapes.
If you look at the picture below, you will see I have 2 sprites, a black star and a red rectangle. When the black star hits the red rectangle, it hits it on multiple points, circled in blue. Sprite Kit will then do a call for each line intersection, so that the developer can use the contactPoint variable for each of these contacts.
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.
I figured out easy solution:
Just change either body's categoryBitMask value to 0 or non-used value right after it detected contact.
For example:
if (firstBody.categoryBitMask == padCategory && secondBody.categoryBitMask == colorBallCategory) {
secondBody.categoryBitMask = 0;
// DO OTHER THING HERE
}
I came across the same issue. In my case the didBeginContact() was called many times (I counted up to 5 times) for one contact of a bullet with the enemy. As the bullet is a simple circle format, I agree with #SFX that it cannot be a bug just in Texture-Bodies. The tests have shown that there was no call to update() between the didBeginContact() calls. So the solution is simple (Swift):
var updatesCalled = 0
...
internal update() {
updatesCalled ++
}
...
internal func didBeginContact(contact: SKPhysicsContact) {
NSLog("didBeginContact: (\(contact.contactPoint.x), \(contact.contactPoint.y)), \(updatesCalled)")
if(updatesCalled == 0) {return} // No real change since last call
updatesCalled = 0
... your code here ...
}
I tried didEndContact() but that was not called at all. I didn't investigate further into this.
BTW: I just switched from Android, and I'm impressed by the easiness and stability of this System :-)
Here is an option that makes the player invulnerable after being hit for a set time:
A. Create a variable that makes the player invulnerable to losing a life after being hit for a few seconds.
Create a global Boolean variable called isInvuln (set to FALSE) and an NSTimeInterval called invulnTime.
In the method that handles the player and enemy making contact, check to see if isInvuln is False before taking a life. (if isInvuln is true ... do nothing)
If isInvuln is false, take a life then set isInvuln to true.
if(self.isInvuln == FALSE){
self.player.lives-=1;
self.isInvuln = True;}
Add to your updateWithCurrentTime:
if(self.isInvuln==True){
self.invulnTime += timeSinceLast;}
if (self.invulnTime > 3) {
self.isInvuln = FALSE:}
self.invulnTime= 0;
This will make it so that when an enemy and player collide, the player loses a life and becomes invulnerable 3 seconds. After that 3 seconds, the player can take damage again. If the enemy contacts the player within the 3 invulnerable seconds, the contact method does nothing. Hope this helps spark ideas to tackle your problem.
In my experience, didEndContact & didBeginContact are both called multiple times while the objects overlap. This is also happening in SceneKit using iOS 9, so I have to assume it's an intended behavior.

Two or more collisions at same time in Sprite Kit

I have a little problem and can't know by myself the solution. I'm handling collisions with Sprite Kit and I have a problem when my hero collides with two objects at same time (example with the ground and a cube in the air).
I got booleans that tell when the hero is jumping and when he is running at a great speed and when he is running slow (example when he collides with a wall made of cubes).
In this last example my booleans got crazy and sometimes my hero just pass over the cubes cause the speed don't slow down. Sometimes the boolean "is jumping" activates too, so in resume it goes crazy and I think it's because the handling collisions method (didBeginContact) only allows two contact bodies, contact.bodyA and contact.bodyB.
I would like to know if I can edit a file to add a contact.bodyC and what file do I need to edit? and if yes I will handle with this, I think with three contact bodies I will be able to program all the posible cases. If not then I suppose I will have to remove those cube walls or change their category bit mask...
Maybe queuing the contacts and handle then in -update is what you need. For example:
Declare an instance variable called NSMutableArray *_contactQueue;
Add the contacts to the array:
-(void) didBeginContact:(SKPhysicsContact *)contact
{
[_contactQueue addObject:contact];
}
Create a method to handle each contact in sync with your game ticks:
-(void)processContactsForUpdate:(NSTimeInterval)currentTime
{
for (SKPhysicsContact * contact in [_contactQueue copy]) {
[self handleContact:contact];
[_contactQueue removeObject:contact];
}
}
Call this method from update:
[self processContactsForUpdate:currentTime];
Then implement your handle method that will handle the contact.
-(void) handleContact:(SKPhysicsContact *)contact
{
// What you are doing in your current didBeginContact method
}
You can only handle the contact of two bodies, but in this way it's synchronized with every frame. I learned about this following a SpriteKit tutorial at this tutorial

Resources