How To Create A Breakout Game Using SpriteKit

Learn how to create a breakout game for iOS using SpriteKit! By Barbara Reichart.

Leave a rating/review
Save for later
Share

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:

Adjust Device Orientation

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

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.

  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:
  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.
    -(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];
        }
    }
    
-(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];
    }
}

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 escape for the ball.

No pardon 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
Barbara Reichart

Contributors

Barbara Reichart

Author

Over 300 content creators. Join our team.