2
votes

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.

3
Are you actually using SpriteKit (2D) or SceneKit (3D)? SCNPhysicsBody doesn't have a contactTestBitMask.rickster
I'm using SceneKit, my bad, I wrongly changed categoryBitMask for contactTestBitMask, I'll change it right now.Charls Pico

3 Answers

2
votes

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.

1
votes

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;
-2
votes

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!