In our last installment, we ran into a problem trying to get collisions to work correctly with the obstacle. We want it to interact with the penguin, but not the game world. If we turn on physics, either the
edgeLoop
on the scene blocks the obstacle from entering the scene by , or causes very jittery obstacle. A more selective collision system will remedy this. In Sprite Kit, there are two kinds of collisions
- Collisions where the physics engine bounces the objects apart. We have that now as the penguin bounces off the walls.
- Contact where some other action is necessary. In SlippyFlippy, the game should end when the penguin hits the top and bottom boundaries. In a role-playing game, a character coming into contact with a door should move the game to another room.
There are several steps to setting up collisions
- Create categories of collisions
- Tell the sprites what they collide with and what they don’t
- Create the delegate methods to handle when contact begins and ends.
Add the Physics Contact Delegate
Collision detection uses the delegate SKPhysicsContactDelegate
. Add the collision delegate in the header (.h
) file:
@interface MFSMyScene : SKScene
Next, tell the physicsWorld
there is a delegate. Add this in initWithSize:
under the other physicsWorld
assignment.
self.physicsWorld.contactDelegate = self;
Make the Bit Mask Categories
The Physics engine uses a 32 bit integer to interpret collisions. Each bit is a flag for a category of sprite or other SKNode.
Create a list of categories and code the bitmap with constants. Group nodes into categories with similar behaviors for contact and collision. For SlippyFlippyPenguin, we have the following categories:
- Penguin
- World
- Obstacle
- Boundary
Create constants for these categories as bit masks.
//constants for the collision bitmap static const uint32_t penguinCategory = 1 << 0; static const uint32_t worldCategory = 1 << 1; static const uint32_t obstacleCategory = 1 << 2;
Set Sprites to Collision Categories
Using these constants, set the categories for the sprites. We assign to the categoryBitMask
property of the physicsBody
the category. In our code for defining a penguin, add this after we set up physics:
//collision and contact detection penguin.physicsBody.categoryBitMask = penguinCategory; //is a penguin
In our code for defining the world, add:
//collision and contact detection self.physicsBody.categoryBitMask = worldCategory; self.name=@“world”
We added the name world to the parent sprite self. For identification in the delegate methods, the name is a good identifier.
For the obstacles, we didn’t set up physics last time. We need to set up physics on the lower and upper obstacle, then assign the bit mask. For obstacle1
, add:
//physics and collision detection obstacle1.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle1.size]; obstacle1.physicsBody.dynamic = NO; //no gravity obstacle1.physicsBody.categoryBitMask = obstacleCategory;
For obstacle2
, add
//physics and collision detection obstacle2.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:obstacle2.size]; obstacle2.physicsBody.dynamic = NO; //no gravity obstacle2.physicsBody.categoryBitMask = obstacleCategory;
For each, we made a solid physics body, and turned off gravity, then assigned the obstacle category to the lower and upper obstacle, not the parent obstacle. This way, the penguin can get through the gap, but will collide with the obstacle.
Set Collisions and Contact
After defining all nodes in categories, decide how the nodes will react with each other. In this case, the only active sprite is the penguin, which will crash into the world walls and the obstacle. The other nodes doesn’t need any code. Change the collision code in initWithSize:
for the penguin to:
//collision detection penguin.physicsBody.categoryBitMask = penguinCategory; penguin.physicsBody.collisionBitMask = worldCategory | obstacleCategory; penguin.physicsBody.contactTestBitMask = worldCategory | obstacleCategory;
Code didBeginContact: for the Delegate
Set up the delegate method when a contact occurs. The delegate method is optional. We don’t need it yet, but will be informative on how collisions happen.
- (void)didBeginContact:(SKPhysicsContact *)contact { NSLog(@"Body A: %@ contacting Body B: %@",contact.bodyA.node.name, contact.bodyB.node.name); }
The delegate gets the names of our nodes and prints them out. The SKPhysicsContact
object has properties listing the two contacting bodies. We can then use logic on those two bodies to change what we do. In the original Flappy Bird, any contact would end the game. SlippyFlippyPenguin will work differently. Build and run the app.

This is starting to look like a game. SlippyFlippy crashes into the obstacles, and we can avoid them by tapping on the screen enough for him to pass through the gap. If he hits an obstacle, the physics engine starts spinning and bouncing him out of control. The obstacles try to push SlippyFlippy around and can push him off the frame completely. Set up some simple logic for the two contact events. Change the delegate to the following:
- (void)didBeginContact:(SKPhysicsContact *)contact { NSString *bodyA = contact.bodyA.node.name; NSString *bodyB = contact.bodyB.node.name; NSLog(@"Body A: %@ Body B: %@",bodyA, bodyB); if ([bodyA isEqualToString:@“penguin"]){ //collision into world NSLog(@"THUD!!\n\n"); } if ([bodyB isEqualToString:@"penguin"]) { //collision into obstacle NSLog(@"BOING!!!\n\n"); } }
The penguin when it hits a wall will now print BOING!! or THUD!!! when it hits an an obstacle. That is the beginning of collision detection. There is a lot more that we can do with this, which I’ll explore in later lessons. For SlippyFlippy, the four boundaries of the world do not make for good game play. We want three sides for collision and the left side open. That we will address next time.
Leave a Reply