As far as I\'m aware the default for Physics bodies is to bounce off each other when they hit each other until you set their collisionBitMask to an equal number.
How
You can't get desired behaviour because you haven't set category, contact and collision bit masks properly. Here is an example on how you can set this to work:
greenBall.physicsBody?.categoryBitMask = GreenBallCategory //Category is GreenBall
greenBall.physicsBody?.contactTestBitMask = RedBarCategory | WallCategory //Contact will be detected when GreenBall make a contact with RedBar or a Wall (assuming that redBar's masks are already properly set)
greenBall.physicsBody?.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory //Collision will occur when GreenBall hits GreenBall, RedBall or hits a Wall
redBall.physicsBody?.categoryBitMask = RedBallCategory //Category is RedBall
redBall.physicsBody?.contactTestBitMask = GreenBarCategory | GreenBallCategory | WallCategory //Contact will be detected when RedBall make a contact with GreenBar , GreenBall or a Wall
redBall.physicsBody?.collisionBitMask = RedBallCategory | GreenBallCategory | WallCategory //Collision will occur when RedBall meets RedBall, GreenBall or hits a Wall
let borderBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = borderBody
self.physicsBody?.friction = 0
borderBody.contactTestBitMask = RedBallCategory | GreenBallCategory //Contact will be detected when red or green ball hit the wall
borderBody.categoryBitMask = WallCategory
borderBody.collisionBitMask = RedBallCategory | GreenBallCategory // Collisions between RedBall GreenBall and a Wall will be detected
I would recommend you to read docs about categoryBitMask which is a mask that defines which categories a physics body belongs to:
Every physics body in a scene can be assigned to up to 32 different categories, each corresponding to a bit in the bit mask. You define the mask values used in your game. In conjunction with the collisionBitMask and contactTestBitMask properties, you define which physics bodies interact with each other and when your game is notified of these interactions.
contactTestBitMask - A mask that defines which categories of bodies cause intersection notifications with a current physics body.
When two bodies share the same space, each body’s category mask is tested against the other body’s contact mask by performing a logical AND operation. If either comparison results in a nonzero value, an SKPhysicsContact object is created and passed to the physics world’s delegate. For best performance, only set bits in the contacts mask for interactions you are interested in.
collisionBitmask - A mask that defines which categories of physics bodies can collide with this physics body.
When two physics bodies contact each other, a collision may occur. This body’s collision mask is compared to the other body’s category mask by performing a logical AND operation. If the result is a nonzero value, this body is affected by the collision. Each body independently chooses whether it wants to be affected by the other body. For example, you might use this to avoid collision calculations that would make negligible changes to a body’s velocity.
So basically, to set up all these, you should ask your self something like:
Okay, I have a green ball, and a red ball , and wall objects on the scene. Between which bodies I want collisions to occur, or when I want to register contacts? I want a green and a red ball to collide with each other and to collide against the walls. Not a problem. I will first set up categories properly, and then I will set collision bit masks like this:
greenBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory; //greenBall will collide with greenBall, redBall and a wall
redBall.collisionBitMask = GreenBallCategory | RedBallCategory | WallCategory
wall.collisionBitMask = GreenBall | RedBall
Now, I want to detect when some contacts occur (in didBeginContact
: method)... But I don't want to get notified about all possible contacts, but rather to be notified just about contacts between balls (contacts between balls and a wall will be ignored). So lets set contactTestBitMasks
to achieve this:
greenBall.contactTestBitMask = GreenBallCategory | RedBallCategory;
redBall.contactTestBitMask = GreenBallCategory | RedBallCategory;
And that's it. The important thing is when you not using contact detection, you should not set contactTestBitMask
. This is because of performance reasons. If you don't need collision detection, and you are interested only in detecting contacts, you can set collisionBitMask = 0
.
Important:
Make sure you have set physics world's contact delegate in order to use didBeginContact
and didEndContact
methods:
self.physicsWorld.contactDelegate = self; //where self is a current scene
Hope this helps a bit.
Just want to add something here, that if the contact or collision are not able to work properly, you need to make sure that you assign the physicsBody shape first before applying the bitMasks.
Example of not working bitmask:
SKSpriteNode *bird = [SKSpriteNode spriteNodeWithImageNamed:@"bird1.png"];
bird.name = @"bird";
bird.physicsBody.categoryBitMask = birdCategory;
bird.physicsBody.contactTestBitMask = wallCategory | scoreCategory;
bird.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:bird.size.width/2.7];
bird.position = CGPointMake(_mySize.width/3.0, 2*_mySize.height/3.0);
[self addChild:bird];
And working one:
SKSpriteNode *bird = [SKSpriteNode spriteNodeWithImageNamed:@"bird1.png"];
bird.name = @"bird";
bird.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:bird.size.width/2.7];
bird.physicsBody.categoryBitMask = birdCategory;
bird.physicsBody.contactTestBitMask = wallCategory | scoreCategory;
bird.position = CGPointMake(_mySize.width/3.0, 2*_mySize.height/3.0);
[self addChild:bird];
Anyway probably just a newbie mistake, but I'd share here cause this is what caused mine not to work properly.