Two or more collisions at same time in Sprite Kit - ios

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

Related

Swift - Removing specific spawned enemy

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.

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!

How to make a jump sprite

I'm building a Mega Man clone for a school project and I just finished the code to make my character jump and it works perfectly. But I need it to display the actual jump sprite of Mega Man. This is the whole code in Game1:
http://pastebin.com/py7Y7mtD
The AnimatedSprites jt helps you decide the direcrtion and display the sprite. Doesn't matter right now if it's efficient. It's just for starts. When I'll get to more complex stuff I'll work on it.
MegamanJump has the jump sprite(5 or 6 sprites displayed from left to right)
MegamanJump_Flip is the same thing but to the left(again, forget about efficiency).
Basically you want to switch out the current drawable sprite with the sprite you want to draw depending on moving direction or moving direction + jump.
Since you already have a running update method, all you have to do is write another method that does this for you, a state variable to track what is happening and the actual states it can have, preferrably in an enum for clarity.
Essentially
private void swapSprite() {
if(state == CharacterState.LEFT) {
sprite = leftDrawable;
}
//etc other single ifs
if(state == CharacterState.LEFTJUMPING) {
sprite = leftJumpDrawable;
}
}
Change the states on button press combinations, call this method after checking for movement.
I hope this helped!

Blast Radius Spritekit

Im trying to create an explosion that when a certain object is hit, objects in the nearby radius also get destroyed. For example, in a brick breaker game, the ball hits a brick and then the brick explodes but also explodes 2 bricks in every direction as well. How can this be accomplished? Any help is appreciated.
There are lots of ways to do this, but the spritekit way is to create a blast sprite node. You can animate it as needed with SKAction and use the same SpriteKit Physics Contact logic as with other sprites.
Add a physics contact category bit mask for the blast nodes.
When an event occurs that should create the blast, call a method that creates a blast node at the point of the event.
Set the blast node position to the point.
Add any actions to the blast node.
Add the blast node to the scene.
Its actions will run.
In the physics contact delegate method, didBeginContact: you test for for contact with any nodes of categories that should react to contacting the blast node.
If contact is made, basic thing is to tell the contacted node to removeFromeParent.
Once you have that working, you can get fancy.
Your blast node should probably get a physics body of a circle based on a CGPath.
You should probably experiment with actions that scale it up and down.
You can get more sophisticated by adding actions that provide animation, sound etc to the destruction of the other nodes, prior to removing them.
If they are custom subclasses, it's a good time for a protocol that defines the method name to be blown up and removed. Then have each class implement that.
Sounds like work but keeps your game logic code clean.
This overall process is going to be common and one you will get familiar with.

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.

Resources