I have two SKNode objects. Their positions change when they collide.
How can I prevent that? At the same time, I still want to be able to respond to them contacting via - (void)didBeginContact;
I tried setting both their mass property to 0.0f but that didn't work.
You can achieve that by setting category, collision and contact bit masks.
uint32_t bodyABitMask = 1<<0;
uint32_t bodyBBitMask = 1<<1;
//A mask that defines which categories this physics body belongs to.
[bodyA setCategoryBitMask:bodyABitMask];
[bodyB setCategoryBitMask:bodyBBitMask];
//A mask that defines which categories of physics bodies
//can collide with this physics body.
[bodyA setCollisionBitMask:0];
[bodyB setCollisionBitMask:0];
//A mask that defines which categories of bodies cause
//intersection notifications with this physics body.
[bodyA setContactTestBitMask:bodyBBitMask];
[bodyB setContactTestBitMask:bodyABitMask];
In above case bodyA and bodyB cannot collide, but you will receive didBeginContact once they are in contact.
Related
I'm trying to create a single physics body from several other bodies using the SKPhysicsBody(bodies:) init.
I have nodes throughout my scene that have physics bodies attached to them, and I want to consolidate them into a single physics body. I'm enumerating through the nodes of the scene and picking out the nodes I want to target. I'm creating the physics body at the creation of those nodes like this:
node.physicsBody = SKPhysicsBody(rectangleOf: node.size)
node.physicsBody?.isDynamic = false
Then I add the physics body to an array of SKPhysicsBodies like this:
self.allNodePhysicsBodies.append(node.physicsBody)
I then create the conglomerate physics body like this:
let conglomeratePhysicsBody = SKPhysicsBody(bodies: self.allNodePhysicsBodies)
I've tried several different ways of adding the physics bodies to the scene: By creating an SKNode or SKSpriteNode and adding the physics bodies to it and the adding it to the scene, or setting the scene's physics body conglomeratePhysicsBody. All of these methods end up with the physics bodies all aligned at the bottom of the scene (not positioned around the scene like they should be). When I print out the conglomeratePhysicsBody to the console, I get this message: <SKPhysicsBody> type:<Compound> representedObject:[(null)]. Is there something I'm missing that is keeping the physics bodies from appearing where the nodes are?
I should add that I can see the physics bodies by using skView.showsPhysics = true.
I have two SKSpriteNode's, i know how to detect if they are in same place, but I cant figure out how to detect in which place of node they have collision. I particular want to know one of nodes collision place, because I want to add different applyImpulse on nodes height ends, so another node will change direction.
didBeginContact is passed an SKPhysicsContact when 2 bodies collide. SKPhysocsContact has a property contactPoint which is a CGPoint and is the contact point between the two physics bodies, in scene coordinates. From this and the positions of your 2 bodies when they collide, you could work out where exactly on the bodies the collision took place.
You can get the contact point like:
CGPoint collidedPoint = contact.contactPoint;
You can get the x & y points like below:
NSLog(#"collidedPoint x= %f | %f",collidedPoint.x,collidedPoint.y);
// Prints like: collidedPoint x= 424.855835 | 46.139378
Keep Coding........ :)
I'm looking for the best way (performace-wise) to detect contact between two objects that do not collide (not bounce off each other) in a SceneKit physics world.
I saw that SpriteKit has a contactTestBitMask and a collisionBitMask for physics bodies while SceneKit only has the latter. So there must to be another preferred way to get notified when objects have contact in SceneKit. I guess that calling contactTestBetweenBody:andBody:options: in each frame for each object is not the best way to do it?
UPDATE
With iOS 9.0, Apple has added contactTestBitMask to SCNPhysicsBody. So this question will become obsolete soon.
This question deserves a full tutorial. In short, each physics body has a categoryBitMask and collisionBitMask.
categoryBitMask
This is the bit that represents the body.
collisionBitMask
This is the bit that represents which bodies collide with it.
By default (when assigned a physicsBody) all bodies collide with the exception of a kinematicBody, which act special. Objects don't collide with it. But don't get confused, it can collide with other objects when manually moved (such as by dragging it with a finger).
How to handle!!!
Assign your bodies whether it be static or dynamic. Assign there category and collision mask. If the mask match up they collide. How about an example!
These bodies collide with each other
bodyA.physicsBody.categoryBitMask = 4;
bodyB.physicsBody.categoryBitMask = 8;
bodyA.physicsBody.collisionBitMask = 8;
bodyB.physicsBody.collisionBitMask = 4;
These don't collide
bodyA.physicsBody.categoryBitMask = 4;
bodyB.physicsBody.categoryBitMask = 8;
bodyA.physicsBody.collisionBitMask = 0;
bodyB.physicsBody.collisionBitMask = 0;
Noticed I used categories by power of two. This is because the contactDelegate uses bitwise AND to compare. Read up on bitwise if you don't understand. It will really help.
These bodies collide without physics
EXAMPLE: You have a hero that runs through a ghost and you want to know that it happened without either one being effected. Such as bouncing off each other.
bodyA.physicsBody.categoryBitMask = 4;
bodyB.physicsBody.categoryBitMask = 8;
bodyA.physicsBody.collisionBitMask = 0;
bodyB.physicsBody.collisionBitMask = 0;
So the following code is designed so that bodyA(your hero) runs through bodyB(ghost).
bodyB.physicsField.categoryBitMask = 4
Noticed that the above is a physicsField.catagoryBitMask. It is assigned a 4 so that it matches up with bodyA.
let collisionField = SCNPhysicsField.customFieldWithEvaluationBlock(){
(_, _, _, _, _) in
WHAT U WANT TO DO ON CONTACT
}
bodyB.physicsField = collisionField
The physicsField is not the shape of your geometry unfortunately. Its default is the shape of its bounding box or sphere/elliptical if you set the physicsField property usesEllipsoidalExtent to "true/yes"
The area of effect can be changed using the physicsFields halfExtent property like so...
bodyB.physicsField.halfExtent = SCNVector3Make(.5, .5, .5)
The above will extend the field of a box the size of (2, 2, 2) to (2.5, 2.5, 2.5).
EDIT: If they still collide, try removing the physicsbody from bodyB (this will remove all physics simulation from the node). I don't think it will be a problem as long as the catagory and collision bitmask are assigned properly.
This is the best method I could find. All coding is from my head, with the support of Apple docs, so may not be exactly right but I hope this helps!
I have found the best way is to just set the mass so small on a kinematic body that the other one will pass through it.
sensorBox.physicsBody.mass = 0.00000000001; // super tiny mass makes it a "sensor"
Don't forget your scene's physics world can call a "contactTestBetweenBody: andBody: withOptions... this works great.
Usage
[myScene.physicsWorld contactTestBetweenBody:(SCNPhysicsBody *) andBody:(SCNPhysicsBody *) options:(NSDictionary *)];
I'm working on a piece of code, and I want there to be gravity in the view but I want specific projectiles to defy gravity and fly across the screen. I know to get rid of the gravity on the whole view its just:
self.physicsWorld.gravity = CGVectorMake(0, 0);
But as stated I want gravity on the scene.
So I'm wondering if there is a way to take the gravity off one specific item? (i.e. the SKSpriteNode _debris item in my case)
By setting the physicsBody to not be affected by gravity.
E.g.
myNoGravityObject.physicsBody.affectedByGravity = NO;
See the documentation of SKPhysicsBody.
If you don't want a node to interact with physics calculations at all, but still want it to have a physicsBody (i.e. to make it begin to interact with things later on, or to check for collisions with other nodes), you can set
node.physicsBody.dynamic = NO;
This will cause the node to ignore gravity, as well as collisions, impulses, and the like. If you are setting up the contact delegate, note that at least one node in any given contact must be dynamic for the contact delegate to be notified of the event.
I have two SKNode objects. Their positions change when they collide.
How can I prevent that? At the same time, I still want to be able to respond to them contacting via - (void)didBeginContact;
I tried setting both their mass property to 0.0f but that didn't work.
You can achieve that by setting category, collision and contact bit masks.
uint32_t bodyABitMask = 1<<0;
uint32_t bodyBBitMask = 1<<1;
//A mask that defines which categories this physics body belongs to.
[bodyA setCategoryBitMask:bodyABitMask];
[bodyB setCategoryBitMask:bodyBBitMask];
//A mask that defines which categories of physics bodies
//can collide with this physics body.
[bodyA setCollisionBitMask:0];
[bodyB setCollisionBitMask:0];
//A mask that defines which categories of bodies cause
//intersection notifications with this physics body.
[bodyA setContactTestBitMask:bodyBBitMask];
[bodyB setContactTestBitMask:bodyABitMask];
In above case bodyA and bodyB cannot collide, but you will receive didBeginContact once they are in contact.