How To Create A Breakout Game Using SpriteKit

Barbara Reichart Barbara Reichart
Your little Breakout game. Destroy all the blocks!

Breakout blocks at the beginning of the game – all in a row.

SpriteKit is Apple’s new game development framework for iOS and Mac OS. Not only does it come with some great graphics capabilities, but it also includes a physics engine which looks a lot like Box2D. Best of all, you do all the work using straight Objective-C!

There’s a lot you can do with SpriteKit, and a great way to start learning about how it works is to create a simple game.

In this tutorial, you are going to learn how to create a Breakout game using SpriteKit step-by-step, complete with collision detection, ball bouncing using physics effects, dragging the paddle via touches, and win/lose screens.

If you are new to SpriteKit, you should go through the SpriteKit Tutorial for Beginners before proceeding with this tutorial.

The SpriteKit World in Theory

Before you go any further, do you have a moment to talk… about physics?

In SpriteKit you work in two environments. The graphical world that you see on the screen and the physics world, which determines how objects move and interact.

The first thing you need to do when using SpriteKit physics is to change the world according to the needs of your game. The world object is the main object in SpriteKit that manages all of the objects and the physics simulation. It also sets up the gravity that works on physics bodies added to it. The default gravity is -9.81 thus similar to that of the earth. So, as soon as you add a body it would “fall down”.

Once you have created the world object, you can add things to it that interact according to the principles of physics. For this the most usual way is to create a sprite (graphics) and set its physics body. The properties of the body and the world determine how it moves.

Bodies can be dynamic objects (balls, ninja stars, birds, …) that move and are influenced by physical forces, or they can be static objects (platforms, walls, …) that are not influenced by those forces. When creating a body you can set a ton of different properties like shape, density, friction and many more. Those properties heavily influence how the body behaves within the world.

When defining a body, you might wonder about the units of their size and density. Internally SpriteKit uses the metric system (SI units). However within your game you usually do not need to worry about actual forces and mass, as long as you use consistent values.

Once you’ve added all of the bodies you like to your world, SpriteKit can take over and do the simulation. Now that you have a basic understanding of how things should work, let’s see it in code! Time for some Breakout!

Getting Started

Start by creating a new project. For this start up XCode, go to File\New\Project and choose the iOS\Application\SpriteKit Game template. Set the product name to BreakoutSpriteKitTutorial, select Devices>iPhone and then click Next. Select the location on your hard drive to save your project and then click Create.

Your game will need some graphics. You probably want to have at least a graphic for the ball, the paddle, the bricks, and a background image. You can download them from here. Drag and drop the files from Finder on to your XCode project. Make sure that the checkmark for Copy items into destination group’s folder (if needed) is ticked and press the Finish button.

Open MyScene.m. This class creates your game scene. The template includes some extra code that you will not need. So, replace the contents of the file with the following:

#import "MyScene.h"
 
static NSString* ballCategoryName = @"ball";
static NSString* paddleCategoryName = @"paddle";
static NSString* blockCategoryName = @"block";
static NSString* blockNodeCategoryName = @"blockNode";
 
@implementation MyScene
 
-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        SKSpriteNode* background = [SKSpriteNode spriteNodeWithImageNamed:@"bg.png"];
        background.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
        [self addChild:background];
    }
    return self;
}
 
@end

The code here is very basic. First, you define a few constants that will help you to identify the game objects. Then, initWithSize: initializes an empty scene with a specified size, creates a sprite using an image, positions it in the middle of the screen, and adds it to the scene.

Now you have an barebones project which displays a background image. However, the screen is still in portrait mode and you want Breakout to work in landscape mode instead. For this you need to do two things:

  1. Select the project root in Xcode, then select the BreakoutSpriteKitTutorial target, make sure that the General tab is selected, and set the orientation to just landscape by ensuring that only the two landscape checkboxes are checked as shown below:

    Adjust Device Orientation

  2. If you’ve done the first step and load the app, you will realize that it still looks weird. Parts of the background are not displayed on screen. To fix this, you need to switch to ViewController.m.

    Remove the implementation for viewDidLoad and instead, add the following code:

    -(void)viewWillLayoutSubviews {
        [super viewWillLayoutSubviews];
     
        // Configure the view.
        SKView * skView = (SKView *)self.view;
        if (!skView.scene) {
            skView.showsFPS = YES;
            skView.showsNodeCount = YES;
     
            // Create and configure the scene.
            SKScene * scene = [MyScene sceneWithSize:skView.bounds.size];
            scene.scaleMode = SKSceneScaleModeAspectFill;
     
            // Present the scene.
            [skView presentScene:scene];
        }
    }

    Setting up your scene in viewWillLayoutSubviews ensures that the view is in the view hierarchy and hence laid out properly. In contrast, this does not work correctly in viewDidLayout because the size of the scene is not known at that time. You can find a much more detailed explanation for this in the Switching to Landscape Orientation section of the SpriteKit Tutorial for Beginners.

An-Ever-Bouncing Ball

Once you have a nice clean scene in landscape mode, it is time to play around with the physics of SpriteKit. Open MyScene.m and add the following line of code to the end of initWithSize: (right after the line adding the background to the scene):

    self.physicsWorld.gravity = CGVectorMake(0.0f, 0.0f);

The above changes the gravity of the game world, with one line of code. Don’t let this kind of power go to your head ;). The default gravity in SpriteKit is 0 along the x-Axis and -9.8 along the y-Axis simulating that of the earth. However, for your Breakout game you do not want any gravity. So, you just set the gravity to zero along both axes.

Next you should create an invisible barrier around the screen. This will effectively cage the ball on screen, ensuring that it cannot escape.

No pardon for the ball.

No escape for the ball.

To do this, add the following code to the end of initWithSize: (right after the last line you added) in MyScene.m:

    // 1 Create a physics body that borders the screen
    SKPhysicsBody* borderBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
    // 2 Set physicsBody of scene to borderBody
    self.physicsBody = borderBody;
    // 3 Set the friction of that physicsBody to 0
    self.physicsBody.friction = 0.0f;
  1. You create an SKPhysicsBody. SKPhysicsBodies are used to add physics simulation to a node. In this case, you create an edge-based body which does not have mass or volume, and is unaffected by forces or impulses.
  2. You can set a physics body for every node. Here, you attach it to the scene. Note: The coordinates of the SKPhysicsBody are relative to the position of the node.
  3. Set the friction to 0.0f so that the ball will not be slowed down when colliding with the border barrier. Instead, you want to have a perfect reflection, where the ball leaves along the same angle that it hit the barrier.
Perfect reflection

Perfect reflection

At this point you have this amazing cage, but you cannot see its effects. To actually see how the cage works, you need to add the ball. Go ahead and add the following lines of code to the end of initWithSize: (right after the previous code):

    // 1
    SKSpriteNode* ball = [SKSpriteNode spriteNodeWithImageNamed: @"ball.png"];
    ball.name = ballCategoryName;
    ball.position = CGPointMake(self.frame.size.width/3, self.frame.size.height/3);
    [self addChild:ball];
 
    // 2
    ball.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:ball.frame.size.width/2];
    // 3
    ball.physicsBody.friction = 0.0f;
    // 4
    ball.physicsBody.restitution = 1.0f;
    // 5
    ball.physicsBody.linearDamping = 0.0f;
    // 6
    ball.physicsBody.allowsRotation = NO;
  1. No surprises here. You simply create a sprite, name it for later reference, set its position relative to the scene, and add it to the scene.
  2. You create a volume-based body for the ball. In contrast to the edge-based body you created to form the barrier around the screen, this physics body is affected by forces or impulses, and collisions with other bodies. Here you create a physics body with the form of a circle that has exactly the same size as the ball sprite.
  3. Next, you set up a few properties for the physics body. You’ve already worked with friction, and it should be quite clear what this line does – it simply removes all friction.
  4. Restitution refers to the bounciness of an object. You set the restitution to 1.0f, meaning that when the ball collides with an object the collision will be perfectly elastic. In plain English, this means that the ball will bounce back with equal force to the impact.
  5. LinearDamping simulates fluid or air friction by reducing the body’s linear velocity. In the Breakout game the ball should not be slowed down when moving. So, you set the restitution to 0.0f.
  6. AllowsRotation does exactly what the name implies. It either allows rotation of the body or not. Here you do not want the ball to rotate.

Note: Usually, it’s best to have the physics body be fairly similar to what the player sees. For the ball it’s very easy to have a perfect match. However, with more complex shapes you’ll have to get a bit more creative. This is where you’ll need to be careful since very complex bodies can exact a high toll on performance.

It’s time to get the ball rolling (bouncing, actually). Add the following code right after the previous lines:

    [ball.physicsBody applyImpulse:CGVectorMake(10.0f, -10.0f)];

This new code applies an impulse (think of it like the propulsion from a jet pack thruster) to the ball to get it moving in a particular direction (in this case, diagonally down to the right). Once the ball is set in motion, it will simply bounce around the screen because of the barrier around the screen!

Now it’s time to try it out! When you compile and run the project, you should see a ball continuously bouncing around the screen – cool!

They see me bouncin', they hatin' :D

They see me bouncin’, they hatin’ :D

Adding the Paddle

It wouldn’t be a Breakout game without a paddle, now would it?

Construct the paddle (and its companion physics body) in initWithSize: in MyScene.m by adding this code just after you create and configure the ball:

     SKSpriteNode* paddle = [[SKSpriteNode alloc] initWithImageNamed: @"paddle.png"];
     paddle.name = paddleCategoryName;
     paddle.position = CGPointMake(CGRectGetMidX(self.frame), paddle.frame.size.height * 0.6f);
     [self addChild:paddle];
     paddle.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:paddle.frame.size];
     paddle.physicsBody.restitution = 0.1f;
     paddle.physicsBody.friction = 0.4f;
     // make physicsBody static
     paddle.physicsBody.dynamic = NO;

Most of the code is similar to the code used when creating the ball. However, this time you use a rectangle to form the physics body as it more closely matches what is visible on screen.

Here you need to make sure that the paddle is static. This ensures that the paddle does not react to forces and impulses. You will soon see why this is important.

If you build and run, you’ll see your paddle in the scene, and the ball will bounce off it:

The most boring game ever :/

The most boring game ever :/

However, this isn’t much fun, because you can’t move the paddle yet!

Moving the Paddle

So let’s get moving! Moving the paddle is going to require detecting touches. You can detect touches in MyScene by implementing the following touch handling methods:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;
-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;

But, before you implement the above methods, you need to add a property. Add the following code just above the @implementation line in MyScene.m:

@interface MyScene()
 
@property (nonatomic) BOOL isFingerOnPaddle;
 
@end

This defines a property that stores whether the player tapped the paddle or not. You will need it to implement the dragging of the paddle.

Now, go ahead and add the code to implement touchesBegan:withEvent: to MyScene.m as follows:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    /* Called when a touch begins */
    UITouch* touch = [touches anyObject];
    CGPoint touchLocation = [touch locationInNode:self];
 
    SKPhysicsBody* body = [self.physicsWorld bodyAtPoint:touchLocation];
    if (body && [body.node.name isEqualToString: paddleCategoryName]) {
        NSLog(@"Began touch on paddle");
        self.isFingerOnPaddle = YES;
    }
}

The above code gets the touch and uses it to find the location on the scene where the touch occurred. Next, it uses bodyAtPoint: from physicsWorld to find the body (if any) at that location.

Next, it checks whether there was a body at the tap location and if yes, whether that body is the paddle. This is where the object names you set up earlier come in to play – you can check for a specific object by checking its name. If the object at the tap location is a paddle, then a log message is sent to the console and isFingerOnPaddle is set to YES.

Now you can build and run the project again. When you tap the paddle, you should see a log message in the console.

You successfully receive touches :)

You have touches :)

Now, go ahead and add the code for touchesMoved:withEvent::

-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
    // 1 Check whether user tapped paddle
    if (self.isFingerOnPaddle) {
        // 2 Get touch location
        UITouch* touch = [touches anyObject];
        CGPoint touchLocation = [touch locationInNode:self];
        CGPoint previousLocation = [touch previousLocationInNode:self];
        // 3 Get node for paddle
        SKSpriteNode* paddle = (SKSpriteNode*)[self childNodeWithName: paddleCategoryName];
        // 4 Calculate new position along x for paddle
        int paddleX = paddle.position.x + (touchLocation.x - previousLocation.x);
        // 5 Limit x so that the paddle will not leave the screen to left or right
        paddleX = MAX(paddleX, paddle.size.width/2);
        paddleX = MIN(paddleX, self.size.width - paddle.size.width/2);
        // 6 Update position of paddle
        paddle.position = CGPointMake(paddleX, paddle.position.y);
    }
}

This is where most of the paddle movement logic comes in.

  1. Check whether the player is touching the paddle.
  2. If yes, then you need to update the position of the paddle depending on how the player moves their finger. To do this, you get the touch location and previous touch location.
  3. Get the SKSpriteNode for the paddle.
  4. Take the current position and add the difference between the new and the previous touch locations.
  5. Before repositioning the paddle, limit the position so that the paddle will not go off the screen to the left or right.
  6. Set the position of the paddle to the position you just calculated.
Note: You might have noticed that the code directly manipulates the position of the paddle. You can do this because you made the paddle static. You should never change the position of a dynamic body directly, as it can break the physics simulation and lead to really weird behavior.

Don’t believe me? Make the paddle dynamic and set a low gravity, e.g. this

       self.physicsWorld.gravity = CGPointMake(-0.1, -0.1);

Looks quite messed up, doesn’t it?

The only thing left in touch handling is to do some cleanup in touchesEnded:withEvent: as follows:

-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
    self.isFingerOnPaddle = NO;
}

Here, you set the isFingerOnPaddle property to NO. This ensures that when the player takes their finger off the screen and then taps it again, the paddle does not jump around to the previous touch location.

Perfect! When you build and run the project now, the ball will bounce around the screen and you can influence its movement using the paddle.

SpriteKit Makes First Contact!

No! Not that type of first contact.(image by DeviantArt user hugoo13, Creative Commons Licensed)

No! Not that type of first contact. (image by DeviantArt user hugoo13, Creative Commons Licensed)

So far, you have a ball that bounces around the screen and a paddle you can move around via touch. While this is really fun to toy around with, to make it a game you need a way for your player to win and lose the game. Losing should happen when the ball touches the bottom of the screen instead of hitting the paddle. But how do you detect this scenario using SpriteKit?

SpriteKit can detect the contact between two physics bodies. However, for this to work properly, you need to follow a few steps to set things up a certain way. I’ll give you a short overview here and explain each of the steps in more detail later. So, here you go:

  • Set up physics body bit masks: In your game you might have several different types of physics bodies – for example, you can have the player, enemies, bullets, bonus items etc. To uniquely identify these different types of physics bodies, each physics body can be configured using several bit masks. These include:
    • categoryBitMask: This bit mask identifies the category a body belongs to. You use categories to to define a body’s interaction with other bodies. The categoryBitMask is a 32-bit integer, where each bit represents one category. So you can have up to 32 custom categories in your game. This should be enough for most games to set up a separate category for each object type. For more complex games it can be useful to remember that each body can be in several categories. So through smart design of the categories you could even overcome the limitation of 32 categories.
    • contactTestBitMask: Setting a bit in this bitmask causes SpriteKit to notify the contact delegate when the body touches another body assigned to that particular category. By default, all bits are cleared – you are not notified about any contacts between objects. For best performance you should only set bits in the contacts mask for interactions you are really interested in.
    • collisionBitMask: Here, you can define which bodies can collide with this physics body. You can use this, for example, to avoid collision calculations for a very heavy body when it collides with a much lighter body as this would only make negligible changes to the heavy body’s velocity. But you can also use it to allow two bodies to pass right through each other.
  • Set and implement the contact delegate: The contact delegate is a property of SKPhysicsWorld. It will be notified when two bodies with the proper contactTestBitMasks begin and end colliding.
Note: Bit masks?!? In case you’ve never worked with bit masks, don’t panic! At first glance they might look complicated, but they are really useful.

So what is a bitmask? A bitmask is a multi-digit binary number. Something like this: 1011 1000. Not so complicated at all.

But why are they useful? Well, they allow you to get state information out of a binary number and give you the ability to change a specific bit in a binary number to set a specific state. You can do this with the binary operators AND and OR, like so:

Bitmask power :)

Bitmask power :)

This allows you to store a lot of information in a really compact way using just one variable and still be able to access and manipulate the stored information.

So how do you do all this in code?

First, create constants for the different categories. Do this by adding the following lines below the other constants for the category names in MyScene.m:

static const uint32_t ballCategory  = 0x1 << 0;  // 00000000000000000000000000000001
static const uint32_t bottomCategory = 0x1 << 1; // 00000000000000000000000000000010
static const uint32_t blockCategory = 0x1 << 2;  // 00000000000000000000000000000100
static const uint32_t paddleCategory = 0x1 << 3; // 00000000000000000000000000001000

The above defines four categories. You do this by setting the last bit to 1 and all other bits to zero. Then using the << operator you shift this bit to the left. As a result, each of the category constants has only one bit set to 1 and the position of the 1 in the binary number is unique across the four categories.

For now you only need the category for the bottom of the screen and the ball, but you should set up the others anyway as you will probably need them later on as you expand the gameplay.

Once you have the constants in place, create a physics body that stretches across the bottom of the screen. Try to do this by yourself since this uses principles you've already learnt when creating the barriers around the screen edges. (Name the node containing the physics body bottom since you’ll be configuring that node in later steps.)

Solution Inside: Create an edge-based body that covers the bottom of the screen SelectShow

With the preparations out of the way, let’s get to the meat of establishing contact. First, set up the categoryBitMasks for the bottom, ball, and paddle by adding the following code to initWithSize::

    bottom.physicsBody.categoryBitMask = bottomCategory;
    ball.physicsBody.categoryBitMask = ballCategory;
    paddle.physicsBody.categoryBitMask = paddleCategory;

This is really straightforward code. It simply assigns the constants you created earlier to the corresponding physics body’s categoryBitMask.

Now, set up the contactTestBitMask by adding this (again to initWithSize:):

    ball.physicsBody.contactTestBitMask = bottomCategory;

For now you only want to be notified when the ball makes contact with the bottom of the screen. Therefore, you set the contactTestBitMask to bottomCategory.

Next, you need to create an SKPhysicsContactDelegate. As this is a rather simple game, you will just make MyScene the delegate for all contacts.

Go to MyScene.h and change this line:

@interface MyScene : SKScene

To this line:

@interface MyScene : SKScene<SKPhysicsContactDelegate>

This makes it official: MyScene is now an SKPhysicsContactDelegate and will receive collision notifications for all configured physics bodies. Hurrah!

Now you need to set MyScene as the delegate in physicsWorld. So, add this to initWithSize: in MyScene.m

    self.physicsWorld.contactDelegate = self;
Setting up the SKPhysicsContactDelegate

Setting up the SKPhysicsContactDelegate

Finally, you need to implement didBeginContact: to handle the collisions. Add the method to MyScene.m:

-(void)didBeginContact:(SKPhysicsContact*)contact {
    // 1 Create local variables for two physics bodies
    SKPhysicsBody* firstBody;
    SKPhysicsBody* secondBody;
    // 2 Assign the two physics bodies so that the one with the lower category is always stored in firstBody
    if (contact.bodyA.categoryBitMask &lt; contact.bodyB.categoryBitMask) {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    } else {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }
    // 3 react to the contact between ball and bottom
    if (firstBody.categoryBitMask == ballCategory &amp;&amp; secondBody.categoryBitMask == bottomCategory) {
        //TODO: Replace the log statement with display of Game Over Scene
        NSLog(@&quot;Hit bottom. First contact has been made.&quot;);
    }
}

This code might appear a little weird to you, so let me walk you through.

  1. Create two local variables to hold the two physics bodies involved in the collision.
  2. Check the two bodies that collided to see which has the lower categoryBitmask. You then store them into the local variables, so that the body with the lower category is always stored in firstBody. This will save you quite some effort when reacting to contacts between specific categories.
  3. Profit from the sorting that you did just before. You only need to check whether firstBody is in the ballCategory and whether secondBody is in the bottomCategory to figure out that the ball has touched the bottom of the screen, as you already know that secondBody could not possibly be in the ballCategory if firstBody is in the bottomCategory (because bottomCategory has a higher bit mask than ballCategory). For now react with a simple log message.

It’s time to try out your code again. Build and run your game again and if you’ve done everything correctly, you should see the log message in the console every time the ball misses the paddle and hits the bottom of the screen. Like this:

First contact has been made :)

First contact has been made :)

Adding a Game Over Scene

Unfortunately, your player cannot see log messages when they lose the game. Instead, when they lose, you want to show him/her some sort of visual indication on screen. You must create a little game over scene for that purpose.

Go to File\New\File…, choose the iOS\Cocoa Touch\Objective-C class template, and click Next. Name the class GameOverScene, make it a subclass of SKScene, click Next, and then Create.

Switch to GameOverScene.h and add the following method prototype before the @end line:

-(id)initWithSize:(CGSize)size playerWon:(BOOL)isWon;

This new initializer adds a parameter indicating whether the player has won or lost. This allows you to implement only one scene for both victory and defeat. Very convenient :)

Now, replace the code in GameOverScene.m with the following:

#import "GameOverScene.h"
#import "MyScene.h"
 
@implementation GameOverScene
 
-(id)initWithSize:(CGSize)size playerWon:(BOOL)isWon {
    self = [super initWithSize:size];
    if (self) {
        SKSpriteNode* background = [SKSpriteNode spriteNodeWithImageNamed:@"bg.png"];
        background.position = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
        [self addChild:background];
 
        // 1
        SKLabelNode* gameOverLabel = [SKLabelNode labelNodeWithFontNamed:@"Arial"];
        gameOverLabel.fontSize = 42;
        gameOverLabel.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame));
        if (isWon) {
            gameOverLabel.text = @"Game Won";
        } else {
            gameOverLabel.text = @"Game Over";
        }
        [self addChild:gameOverLabel];
    }
    return self;
}
 
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    MyScene* breakoutGameScene = [[MyScene alloc] initWithSize:self.size];
    // 2
    [self.view presentScene:breakoutGameScene];
}
 
@end

This code is pretty standard. So, I will only explain the commented parts that might be new to you.

  1. Creates a label to display the victory or defeat message. SKLabelNode is a very useful class used to display text using any font installed on the device.

    Note: You can find out which fonts are installed on a device using this helpful snippet.

  2. When a touch is detected on the game over scene, you display the game scene again so that the user is taken back to another session of the game.

The new scene is done. Time to add it to the game. Add the following import to the top of MyScene.m:

#import "GameOverScene.h"

Then, replace the NSLog statement line in didBeginContact: with the following code:

    GameOverScene* gameOverScene = [[GameOverScene alloc] initWithSize:self.frame.size playerWon:NO];
    [self.view presentScene:gameOverScene];

Now, build and run the game and play it till your paddle misses the ball:

Game Over

Alright, now you’re getting somewhere! But what fun is a game where you can’t win?

Adding Some Blocks – and They Are Gone…

Add the following code to initWithSize: in MyScene.m to introduce the blocks to the scene:

    // 1 Store some useful variables
    int numberOfBlocks = 3;
    int blockWidth = [SKSpriteNode spriteNodeWithImageNamed:@"block.png"].size.width;
    float padding = 20.0f;
    // 2 Calculate the xOffset
    float xOffset = (self.frame.size.width - (blockWidth * numberOfBlocks + padding * (numberOfBlocks-1))) / 2;
    // 3 Create the blocks and add them to the scene
    for (int i = 1; i &lt;= numberOfBlocks; i++) {
        SKSpriteNode* block = [SKSpriteNode spriteNodeWithImageNamed:@&quot;block.png&quot;];
        block.position = CGPointMake((i-0.5f)*block.frame.size.width + (i-1)*padding + xOffset, self.frame.size.height * 0.8f);
        block.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:block.frame.size];
        block.physicsBody.allowsRotation = NO;
        block.physicsBody.friction = 0.0f;
        block.name = blockCategoryName;
        block.physicsBody.categoryBitMask = blockCategory;
        [self addChild:block];
    }

This code creates three blocks with some padding so that they are centered on the screen.

  1. Some useful variables like the number of blocks you want and their width.
  2. Here you calculate the x offset. This is the distance between the left border of the screen and the first block. You calculate it by subtracting the width of all three blocks and their padding from the screen width and then dividing it by two.
  3. Create three blocks, configure each with the proper physics properties, and position each one using blockWidth, padding, and xOffset.

The blocks are now in place. Build and run your game and check it out!

Breakout blocks at the beginning of the game. Nice and orderly.

Breakout blocks at the beginning of the game. Nice and orderly.

This did not quite go as expected...

Not quite as expected…

Hmm … not quite what you wanted, right? The blocks move around instead of being destroyed when touched by the ball.

In order to listen to collisions between the ball and blocks, you must update the contactTestBitMask of the ball like this (note that this is an existing line of code in initWithSize: – you simply need to add an extra category to it.):

    ball.physicsBody.contactTestBitMask = bottomCategory | blockCategory;

The above executes a bitwise OR operation on bottomCategory and blockCategory. The result is that the bits for those two particular categories are set to one while all other bits are still zero. Now, collisions between ball and floor as well as ball and blocks will be sent to to the delegate.

The only thing left to do is to handle the delegate notifications accordingly. Add the following to the end of didBeginContact::

    if (firstBody.categoryBitMask == ballCategory &amp;&amp; secondBody.categoryBitMask == blockCategory) {
        [secondBody.node removeFromParent];
        //TODO: check if the game has been won
    }

The above lines check whether the collision is between the ball and a block. If this is the case, you remove the block involved in the collision.

Hopefully, you have a good understanding of bit masks in general and the contactTestBitMask in particular. As you read earlier, bodies also have a second bit mask – the collisionBitMask. It determines whether two bodies interact with each other. This allows you to control whether the ball bounces off the bricks or flies right through them, for instance.

If you want to practice working with bit masks, set the collisionBitMask of the ball so that it goes straight through blocks while destroying them.

Solution Inside: Using collisionBitMask SelectShow

Have you overcome the challenge and tasted the thrill of victory? Time to give your player the same satisfaction of tasting victory :]

Winning the Game

To let the player actually win the game, add this method to MyScene.m.

-(BOOL)isGameWon {
    int numberOfBricks = 0;
    for (SKNode* node in self.children) {
        if ([node.name isEqual: blockCategoryName]) {
            numberOfBricks++;
        }
    }
    return numberOfBricks &lt;= 0;
}

The new method checks to see how many bricks are left in the scene by going through all the scene’s children. For each child, it checks whether the child name is equal to blockCategoryName. If there are no bricks left, the player has won the game and the method returns YES.

Now, go back to didBeginContact: and replace the TODO line in the final if condition with the following:

    if ([self isGameWon]) {
        GameOverScene* gameWonScene = [[GameOverScene alloc] initWithSize:self.frame.size playerWon:YES];
        [self.view presentScene:gameWonScene];
    }

The code checks whether the player has won by calling the new method you just implemented. If he has won, you show the GameOverScene with a message indicating victory.

Finishing Touches

As you play the game, you may have noticed that sometimes the ball can get super-fast or super-slow, depending on how you hit it with the paddle.

You can prevent these speed variations by overriding the default update: method for MyScene.m like so:

-(void)update:(CFTimeInterval)currentTime {
    /* Called before each frame is rendered */
    SKNode* ball = [self childNodeWithName: ballCategoryName];
    static int maxSpeed = 1000;
    float speed = sqrt(ball.physicsBody.velocity.dx*ball.physicsBody.velocity.dx + ball.physicsBody.velocity.dy * ball.physicsBody.velocity.dy);
    if (speed &gt; maxSpeed) {
        ball.physicsBody.linearDamping = 0.4f;
    } else {
        ball.physicsBody.linearDamping = 0.0f;
    }
}

update: is called before each frame is rendered. In the case of MyScene.m, there is no update: method since the default implementation has been used till now. Here, you override it with your own implementation.

You get the ball and check its velocity, essentially the movement speed. If it’s too high, you increase the linear damping so that the ball will eventually slow down.

If you compile, run, and play the game, you should see the ball go back to a normal speed level when the speed increases too much.

Note: You might be tempted to prevent the ball from becoming too fast by influencing its velocity directly since that might give you a little more control over its movement. This was not allowed in Box2D, and is probably not a good idea in SpriteKit either.

Gimme the Code!

Here’s the full code for the SpriteKit Breakout Game that you’ve made in this tutorial.

Where To Go From Here?

Obviously, this is a quite simple implementation of Breakout. But now that you have this working, there’s a lot more you can do. You could extend this code to give the blocks hit points, have different types of blocks, and make the ball have to hit some of them (or all of them) a number of times before they are destroyed. You could add blocks which drop bonuses or power-ups, let the paddle shoot lasers toward the blocks, whatever you dream up!

Let me know if you have any tips or suggestions for better ways to do things, and hope this comes in handy!

Barbara Reichart
Barbara Reichart

Barbara Reichart is currently doing her PhD at TUM, where she teaches software engineering and iOS development. In her free time she develops games (Treeo Games). Her first published game is Tw!nkle. You can also follow her on Google+.

You can find Barbara on Twitter.

User Comments

12 Comments

  • Nice tutorial. But You can directly change the velocity of the body in box2d. I do this often in my games:
    if (body->GetLinearVelocity().Length() > SPEED_LIMIT)
    {
    body-SetLinearVelocity(0.9 * body->GetLinearVelocity()); // 10% slower
    }
    ahaha
  • Great tutorial, but I have a problem:
    When I try to move the paddle, it drifts off to the left. The more I move it, the bigger the offset is.
    Stefan_12
  • i love you forever really :C
    FanForever
  • Stefan, did you already fix your issue? If not, you could post the code, where you move the paddle. Maybe I can spot the error.
    Does the error also occur in the final project, when you download it?
    Barbara Reichartgebirgsbaerbel
  • Thanks for the tutorial, got it working just fine. I am wondering though, I have added extra blocks and the ball is slowing down too much. I have tried decreasing the linerDamping when the speed is greater than the maxSpeed and also increasing the maxSpeed, but the ball comes to a stand still, or it gets so slow where it would be non enjoyable to play. Any ideas on how to resolve this?
    stickynugz
  • HI there, I am hoping this is an active forum! I have a question about the best way to reanimate a bouncing ball. Using this (breakout) tutorial as a reference I have a number of circular shape nodes which continually bounce around a gravity-less environment. When the user touches one of them, it centers on the screen, stops moving, and transforms into something else. When the user touches it again, it is supposed to transform back into the circular shape node and then continue bouncing around the screen.

    I have it all working as I like except for reanimating the ball. The manner in which I stop the animation is simply to set the physicsBody to nil. Once I want to reanimate, I call the method that sets up the physicsBody for the node and I apply an impulse to it. But frustratingly, the impulse does not have the effect I think it should. Clearly, my expectations are incorrect.

    Here is the code in question:

    - (void)applyPhysics
    {
    // Set physics properties
    self.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:self.frame.size.width/2];
    self.physicsBody.friction = 0.0f;
    self.physicsBody.restitution = 1.0f;
    self.physicsBody.linearDamping = 0.0f;
    self.physicsBody.allowsRotation = NO;
    self.physicsBody.collisionBitMask = wallCategory;
    self.physicsBody.categoryBitMask = bubbleCategory;
    }

    - (void)morphPicker
    {
    BOOL check = NO;
    if (check) NSLog(@"morphPicker called.");

    [self runAction:[SKAction fadeAlphaTo:0.0 duration:.5]];

    if (self.flipped) {

    if (check) NSLog(@"The information side is showing.");
    self.fillColor = bubbleColors[self.index % bubbleColors.count];
    self.alpha = .9;

    // Resume physics:
    [self applyPhysics];
    [self.physicsBody applyImpulse:CGVectorMake(10.0f, -10.0f)];

    } else {

    // stop physics:
    self.physicsBody = nil;

    if (check) NSLog(@"The statistic side is showing.");
    self.fillColor = [SKColor blackColor];
    self.alpha = .9;
    [self transformToPickerNode];
    [self removeAllChildren];

    }

    self.flipped = !self.flipped;

    }
    So my questions are these:

    How should I be reanimating the ball if applying an impulse to it is not the correct method?

    Is there a more elegant way to stop the animation after centering the node than setting the physicsBody to nil? Even to my novice instincts it feels like a brutish method.
    zeeple
  • It's a little tricky to simulate but when the ball is close to the edge, the paddle has the possibility of pushing the ball out of the physics world. I've looked all over the internet and haven't found a good solution to this problem. I was hoping this version of breakout addressed that issue, but it doesn't. I had to turn of the winning and loosing conditions to get the ball in the right position to push it out of the world but the problem is still there. Any ideas how to fix that?
    Michael Hogenson
  • In the section: SpriteKit Makes First Contact

    It appears that the tutorial needs the following update:

    To this line:
    @interface MyScene : SKScene

    Needs to be:
    To this line:
    @interface MyScene : SKScene

    Thank you.....fun tutorial
    eaduart
  • Hi this is nice tutorials thank for that. I added score and health hud. I try to make like a breakout game. But i have a problem. I want to move paddle and same time before ball bouncing such a real breakout. How can i do? I look for library and other tutorials but i did not found it.
    Fraude
  • Overall this is a good tutorial but there is REALLY REALLY shoddy proofreading.

    In many places where the author SHOULD have written an ampersand (&) it appears as &amp;
    Similarly less than (<) is &lt; and quotations (") are &quot;.

    Then there is the part that says change this line:
    @interface MyScene : SKScene

    to this:
    @interface MyScene : SKScene

    Huh? they are the same! Someone forgot to write the delegate in the second. It should be

    @interface MyScene : SKScene <SKPhysicsContactDelegate>

    Then there is this line that doesn't have a semi-colon at the end:

    ball.physicsBody.collisionBitMask = paddleCategory

    This is really amateur hour!
    cph
  • How to remove SKSpriteNode from GameScene but not hidden in swift
    lokesh22
  • I have to add SKScene over another SKScene in spritKit Swift

    let obj = LevelSecondGameScene()
    let skView = self.view as SKView
    skView.showsFPS = false
    skView.showsNodeCount = false
    skView.ignoresSiblingOrder = false
    scene.scaleMode = .AspectFill
    //obj.didMoveToView(skView)
    skView.presentScene(obj)

    I have to use but screen is black and not add new Node?????

    How to use Scene within Scene????????
    lokesh22

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in September: iOS 8 App Extensions!

Sign Up - September

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

  • Sam Davies
  • Jake Gundersen

... 49 total!

Update Team

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 1 total!

Translation Team

  • Wilson Lin

... 33 total!

Subject Matter Experts

  • Richard Casey

... 4 total!