Create a breakout game with Swift and Sprite Kit (Part 1)

By February 27, 2015 Tutorial No Comments

In this part of the tutorial, we will start working on a breakout game using Swift and Sprite Kit.

We will see how to create the different elements of the game:

  • Ball
  • Paddle
  • BottomWall
  • Bricks

We will create a class for each of these elements which will contains their specificities. We will write a few methods to display all our objects (nodes) on the screen. We will see how we can capture the user inputs and modify the game state in consequence. Finally, we will see how to show to the user when they have lost or won the game.

To create a game that looks like the below.

Breakout_Swift_SpriteKit

First things first, we need to create a new project for our game.

I- Create a game project in Xcode.

Open Xcode and create a new ‘Game’ project.
NewProject

By choosing a ‘Game’ project Xcode will provide us a bit of boilerplate code to get us started writing out application, then click ‘Next’.

ProjectOptions

On the next screen we need to choose a name for our project. I simply called mine Bricks but feel free to use a different name. We also need to select a language which in our case is ‘Swift’ and a game technology ‘Sprite Kit’. Sprite Kit offers out of the box a lot of the most common features required to build a game, we will only see the basics on this tutorial but you should have a look at the introduction on the Apple developer website to have an idea of what is possible to do with it.

II- Setting up our main view (GameViewController.swift)

First we need to modify the way the GameScene is initialised in our GameViewController. The GameViewController allow us to specify how the view is presented to the user. In our case we just want our game to be full screen at all time, also our GameScene will not be archived in anyway so that is something we game remove from the code that is provided with our new project.

override func viewDidLoad() {
    super.viewDidLoad()
    if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
        // Configure the view.
        let skView = self.view as SKView
        skView.showsFPS = true
        skView.showsNodeCount = true
        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true
        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .AspectFill
        skView.presentScene(scene)
    }
}

There is a few important things in the code above, first you will notice that our scene is added to the view in the viewDidLoad() method. You will also notice that certain properties of the view are set to true. The two properties showFPS and showNodeCount are very useful for debugging purpose, it is displayed on the bottom right corner of the screen as you can see on the first image.

The code above need to be replaced with :

override func viewDidLoad() {
        super.viewDidLoad()      
        let scene = GameScene(size: self.view.frame.size)
        let skView = self.view as SKView
        skView.showsFPS = true
        skView.showsNodeCount = true    
        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true       
        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .AspectFill
        skView.presentScene(scene)     
    }

The code extracting the scene from an archive has been removed and the scene is initialised to the size of our view.

III- Building our scene

1- Starting from scratch

If we build our project at this point we have a working game that will create a new ‘Spaceship’ every time we touch the screen. This is obviously not what we want, so the first step before we can get started on our scene is to delete everything in the didMoveToView and touchesBegan methods.

override func didMoveToView(view: SKView) {}
 
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {}

Now that we have removed all the unnecessary code, we can start loading our assets and create the objects needed to build our game.

2- Loading our assets

Xcode make loading assets really easy as long as you name then correctly, you will just have to drag and drop your images in the Images.xcassets directory.

You can download all the images for the game from the link below.
Download images assets

Take the 3 images of the ball and drop the files in the images list view.

Assets

You should now see something like the below.ball_assets

Now that we have the image of our ball we can create a class for it so we can define a few properties for the object and display the ball on the screen.

3- Creating the first object, the ball

To create a new class, we need to create a new Swift file. Go to the menu or press ⌘N
new_file

Name your file Ball.swift, by convention the first letter of a class name is uppercase. You should now have a file with the a few comments at the top and one line of code.

import Foundation

Foundation is a framework that defines a base layer of Objective-C classes, it will allow us to access all the base classes for IOS.

Let’s add a few line of codes to our file.

import Foundation
import SpriteKit

class Ball : SKSpriteNode {
}

First we are importing SpriteKit which is Apple’s framework to build games. Remember that is the type of project that we choose at the beginning of the tutorial.
Then we create our new class and make sure that our class extend SKSpriteNode, nodes are element that can be added to the scene. At this point our class is not really doing anything useful.

Now we are adding the properties that will define our class.

let ballCategoryName = "ball"
    
    override init() {
        let imageTexture = SKTexture(imageNamed: ballCategoryName)
        super.init(texture: imageTexture, color: nil, size: imageTexture.size())
        self.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.width / 2)
        self.name = ballCategoryName
        self.physicsBody?.friction = 0
        self.physicsBody?.restitution = 1
        self.physicsBody?.linearDamping = 0
        self.physicsBody?.allowsRotation = false
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

First we define a new constant ballCategoryName, we assign the string “ball” to it. We purposely chose the same name as the asset that we have loaded earlier because we use that constant later to create the imageTexture constant.
Then we call the initialiser of the superclass with the newly created image texture as an argument. The rest of the class define a few more properties specific to the SKSpriteNode class that we extend.

We also have to implement a second init method which is required, this is only the case because we have overridden the init method. In Swift we automatically inherit from the super call initialisers unless we override one of them which is our case.

The initialiser having coder as an argument is used when we load elements from the story board, it is not our case which is why we simply throw an error if the method is used.

Our whole class is only 20 lines of codes long.

//
//  Ball.swift
//  Bricks
//
//  Created by Thomas Carlier on 25/01/2015.
//  Copyright (c) 2015 Thomas Carlier. All rights reserved.
//

import Foundation
import SpriteKit

class Ball : SKSpriteNode {
    
    let ballCategoryName = "ball"
    
    override init() {
        let imageTexture = SKTexture(imageNamed: ballCategoryName)
        super.init(texture: imageTexture, color: nil, size: imageTexture.size())
        self.physicsBody = SKPhysicsBody(circleOfRadius: self.frame.width / 2)
        self.name = ballCategoryName
        self.physicsBody?.friction = 0
        self.physicsBody?.restitution = 1
        self.physicsBody?.linearDamping = 0
        self.physicsBody?.allowsRotation = false
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

2- Using our Ball class

In Swift, we don’t need to import the classes that we want to use even if they are defined in a different file. Let’s go back to our game scene and add a ball to the scene.

We need to edit the GameScene.swift file.
First we need to create the ball object.

class GameScene: SKScene, SKPhysicsContactDelegate {
    var ball = Ball()
    ...
}

Note that we define our ball as variable (var), we mostly have been using constant (let) until now. It is a best practice to use constant when it is possible, because it will make your code run faster and avoid some errors.

Creating the object itself doesn’t make it appear on screen, for the ball to appear on screen we need to add a few more lines of code.

override func didMoveToView(view: SKView) {
        // Initialise the scene
        self.backgroundColor = SKColor.whiteColor()
        
        // Add the ball to the scene
        ball.position = CGPoint(x: CGRectGetMidX(view.frame), y: CGRectGetMidY(view.frame))
        self.addChild(ball)
}

We change the background color to white and place the ball in the middle of the screen using CGRectGetMidX and CGRectGetMidY, all the methods starting with CG are Core Graphics methods. We will see them a lot as they mostly used to display things on screen.
The last line of code add the ball to the game scene.
Now if we build our project we should see a white screen with our ball in the middle.

In the next part part of the tutorial we will add the paddle to the scene and make the ball move.

Leave a Reply