Hello I have pored over the documentation and can not figure out how to set up collision detection in scene kit. Can some one please show an example. Please help I am very desperate to figure this out. Thank you!
Edit: Hello Thank you very much, I'm sorry I forgot to mention my project is in swift. No big deal I can translate my self for the most part.
I have the BitMasks working correctly as the objects collide and bounce with each other. However I can not seem to get the function to work
func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact){
let contactMask = contact.nodeA.physicsBody!.categoryBitMask | contact.nodeB.physicsBody!.categoryBitMask
if (contactMask == (CollisionBallCategory | CollisionTerminatorCategory)) {
println("Collided")
}
}
Looking at the documentation it appears i need to assign the scenes physics world delegate to this method somehow. I am not sure how to do that.
The main things to get about collision detection in SceneKit:
For example, you might state a bit of game design in plain English like this:
Asteroids hit each other (and make smaller asteroids). Missiles should pass through each other, but destroy rockets and asteroids. Rockets shouldn't do anything to missiles (only the other way around), but if one gets too close to another or to an asteroid you are having a bad problem and you will not go to space today.
The first step to realizing that with collision detection is to codify that design in terms of which pairs interact. You can do this with a table:
| Missile | Rocket | Asteroid
--------------------------------------
Missile | No | Yes | Yes
Rocket | No | Yes | Yes
Asteroid | No | No | Yes
Then you can turn the headers of the table into a set of category constants for use in your code.
typedef NS_OPTIONS(NSUInteger, CollisionCategory) {
CollisionCategoryMissile = 1 << 0,
CollisionCategoryRocket = 1 << 1,
CollisionCategoryAsteroid = 1 << 2,
};
missile.physicsBody.categoryBitMask = CollisionCategoryMissile;
rocket.physicsBody.categoryBitMask = CollisionCategoryRocket;
asteroid.physicsBody.categoryBitMask = CollisionCategoryAsteroid;
Use bitwise OR on these constants to create collisionBitMask
values that fill in the table.
missile.physicsBody.collisionBitMask =
CollisionCategoryRocket | CollisionCategoryAsteroid;
rocket.physicsBody.collisionBitMask =
CollisionCategoryRocket | CollisionCategoryAsteroid;
asteroid.physicsBody.collisionBitMask = CollisionCategoryAsteroid;
That's all you need to make SceneKit resolve collisions for you (that is, bounce objects off each other).
If you also want to be notified of collisions (so you can make missiles blow stuff up, and running your ship into an asteroid end the game), you'll need to set a contact delegate on your scene's physics world and implement one or more of the contact delegate methods that get called when a contact happens.
In your contact delegate method (say, physicsWorld:didBeginContact:
), you'll need to find out which categories of bodies were involved in the contact, and which was which, so you can get to your code that does whatever your game does for the collision:
- (void)physicsWorld:(SCNPhysicsWorld *)world didBeginContact:(SCNPhysicsContact *)contact
{
CollisionCategory contactMask =
contact.nodeA.physicsBody.categoryBitMask | contact.nodeB.physicsBody.categoryBitMask;
// first, sort out what kind of collision
if (contactMask == (CollisionCategoryMissile | CollisionCategoryRocket)) {
// next, sort out which body is the missile and which is the rocket
// and do something about it
if (contact.nodeA.physicsBody.categoryBitMask == CollisionCategoryMissile) {
[self hitRocket:contact.nodeB withMissile:contact.nodeA];
} else {
[self hitRocket:contact.nodeA withMissile:contact.nodeB];
}
} else if (contactMask == (CollisionCategoryMissile | CollisionCategoryAsteroid)) {
// ... and so on ...
}
}
Put this code in one of your classes (a view controller, maybe — wherever you keep your game logic is good), and make that class declare conformance to the SCNPhysicsContactDelegate
protocol.
@interface ViewController: UIViewController <SCNPhysicsContactDelegate>
Then assign that object to your scene's physics world as the contact delegate:
// in initial setup, where presumably you already have a reference to your scene
scene.physicsWorld.contactDelegate = self
There's a little bit about collision resolution in the SCNPhysicsBody reference documentation. And Apple has some sample code that uses collision detection — it's part of the smorgasbord of demos in the WWDC slides and demo sample apps, and in the vehicle physics demo, too.
Beyond that, SceneKit's collision handling model is almost exactly the same as SpriteKit's, so almost everything in the SpriteKit programming guide is also useful for understanding the same stuff in SceneKit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With