Book Image

Getting Started with SpriteKit

By : Jorge Jordán
Book Image

Getting Started with SpriteKit

By: Jorge Jordán

Overview of this book

SpriteKit is Apple’s game engine to develop native iOS games. Strongly boosted by the Apple Inc., Cupertino, it has increased in popularity since its first release. This book shows you the solutions provided by SpriteKit to help you create any 2D game you can imagine and apply them to create animations that will highlight your existing apps. This book will give you the knowledge you need to apply SpriteKit to your existing apps or create your own games from scratch. Throughout the book, you will develop a complete game. The beautiful designs implemented in the game in this book will easily lead you to learn the basis of 2D game development, including creating and moving sprites, and adding them to a game scene. You will also discover how to apply advanced techniques such as collision detection, action execution, playing music, or running animations to give a more professional aspect to the game. You will finish your first game by learning how to add a main menu and a tutorial, as well as saving and loading data from and to the player’s device. Finally, you will find out how to apply some mobile games techniques such as accelerometer use or touch detection.
Table of Contents (13 chapters)
Getting Started with SpriteKit
Credits
About the Author
About the Reviewer
www.PacktPub.com
Preface
Index

Running the project for first time


To execute the project, you just need to click on the Run icon at the top left of the Xcode screen, and it will run the project on an iPhone 6 on the iOS Simulator; the result is shown in the following screenshot:

Well, with a little effort, we have created our first Hello, World project using SpriteKit. Now, it's time to look at the code and understand why the preceding screenshot is the result of these files.

Note

From now on, we are going to assume that we are running the game on the iOS Simulator.

How the default project looks like

In this section, you are not supposed to understand everything. The aim of this section is to understand the responsibility of each class in a default SpriteKit project.

The entry point of our game is the AppDelegate class, which is the same as that of all iOS applications. Let's take a look at its content:

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

Tip

Downloading the example code.

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

I've just pasted the top block of the file because it is the important one. As you can see, we imported the UIKit framework that will provide the window and the view architecture needed to build an application. It also provides our project with the event-handling infrastructure that is needed to respond to user input and the app model needed to drive the main run loop and interact with the system.

The next line contains an odd-looking instruction, which is @UIApplicationMain. This tells Xcode which is the main file of the project.

Then, you will see that the AppDelegate class inherits from UIResponder and UIApplicationDelegate, which is what happens with all iOS applications. We declared a UIWindow optional variable to avoid runtime errors in case of nil content.

Note

As per Apple's documentation ( https://developer.apple.com/library/mac/documentation/Swift/Conceptual/Swift_Programming_Language/OptionalChaining.html), optional chaining is a Swift process that is used to call properties and methods on an optional that might currently be nil. If the optional contains a value, the call succeeds, and if the optional is nil, the call returns nil.

Finally, you will see that the only method implemented is application(application:, launchOptions:). This is the point where we can apply some instructions that we want the game to execute as soon as it's launched.

There is nothing more to remark on this class. So let's take a look at the class that will be called just after AppDelegate: GameViewController.

To understand why this class is called, as soon as the main screen is launched, we need to keep in mind that the project is configured to show Main.storyboard as the main interface. In the Project Explorer, select the File and look at the Utilities panel on the right-hand side of screen, and choose the Identity Inspector to have a look at its configuration, as shown in the following screenshot:

This means that the interface is linked to the GameViewController class. It's time to open the class and discover what it contains:

import UIKit
import SpriteKit

class GameViewController: UIViewController {
override func viewDidLoad() {
        super.viewDidLoad()

        if let scene = GameScene(fileNamed:"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)
        }
    }

As you can see at the top of the file, the view controller is a subclass of the UIViewController class, which is commonly seen in many iOS applications. However, the difference is that here, we imported the SpriteKit framework (apart from UIKit), to provide game characteristics to the project.

This class overrides the viewDidLoad method, where we create a scene by using a file called GameScene. This file corresponds to GameScene.sks. If it succeeds, we create a view (an instance of the SKView class), setting the showsFPS and showsNodeCount attributes to True.

This is the reason why we can see these labels at the bottom right of the game's screen; they show the amount of draw calls (node count), and frame rate respectively.

Note

The frame rate value measures how smooth our game will be. In iOS, the maximum frame rate is 60 Hz.

The number of draw calls and the frame rate are values that you need to take care of, as they will let us know if our game will run smoothly.

We will have a look at the last view's configuration (ignoresSiblingOrder), and the scaleMode property later in the chapter, as we just want to have an overview the project. Once the view is configured, we can load the scene by calling the presentScene method.

Next, in the file, you will see four more methods. Take a look at the following two methods:

override func shouldAutorotate() -> Bool {
        return true
   }

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return .AllButUpsideDown
        } else {
            return .All
        }
   }

This code means that the user can rotate the device, and the screen will adapt itself automatically to the new orientation with one restriction, due to the AllButUpsideDown property: the game's screen won't rotate when we hold the iPhone or iPod devices upside down.

Have a look at the following method:

override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
   }

This method should look familiar to you if you have developed an iOS application previously. It's raised by the system when the amount of available memory is low. It allows us to release some memory to avoid an application crash.

Finally, we have the following method that has to do with the way the game is shown:

override func prefersStatusBarHidden() -> Bool {
        return true
   }

This method keeps the status bar hidden, as our application is a game and we want to use the full screen to show it.

We have previously seen that this class creates a scene by calling the constructor method in the GameScene class. Therefore, it's time to open the file:

 import SpriteKit

 class GameScene: SKScene {
    override func didMoveToView(view: SKView) {
        /* Setup your scene here */
        let myLabel = SKLabelNode(fontNamed:"Chalkduster")
        myLabel.text = "Hello, World!";
        myLabel.fontSize = 65;
        myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
        
        self.addChild(myLabel)
    }

As you can see, this class also imports the SpriteKit framework, but the most important thing about this is the class that it is inheriting SKScene. We will study it in detail further in this chapter, but for now, you need to understand that an instance of SKScene or its subclass is the object that will represent a scene of content in a SpriteKit game.

The didMoveToView method means that its code will be executed as soon as the scene is presented by a view. This is the perfect place to initialize a scene and, as we can see, in the default project, we are creating a new label using a font called Chalkduster and configuring some of its properties to set the size, text, and desired position. Adding the label to the scene is as easy as executing the addChild method.

The next method in the class looks like this:

 override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
       /* Called when a touch begins */
        
        for touch in touches {
            let location = touch.locationInNode(self)
            
            let sprite = SKSpriteNode(imageNamed:"Spaceship")
            
            sprite.xScale = 0.5
            sprite.yScale = 0.5
            sprite.position = location
            
            let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
            
            sprite.runAction(SKAction.repeatActionForever(action))
            
            self.addChild(sprite)
        }
    }

This method is called when the user touches somewhere on the screen. It is also one of the methods that we can override to handle touches. There are three more methods, namely touchesMoved, touchesEnded, and touchesCancelled, which will be covered in detail in Chapter 2, What Makes a Game a Game? As soon as user touches on the screen and this whole process gets completed, it gets the location of the touch, creates an SKSpriteNode instance using the Spaceship texture, sets its size to half of the texture's original size, and places it on the touch position. You will find the image that is used to create the spaceship in the Assets.xcassets folder of the Project Navigator.

Then, it applies a rotation to the spaceship by creating an action method, and calling the rotateByAngle method, which accepts an angle value as an input parameter, and running this action on the spaceship. Finally, it adds the ship to the scene.

Note

The SKSpriteNode instance is one of the most used classes in SpriteKit game development as it provides a visual representation and a physical shape to the objects in view.

The last method looks like this:

 override func update(currentTime: CFTimeInterval) {
        /* Called before each frame is rendered */
    }

This is one of the most important methods when developing games with SpriteKit, as it is called just before each frame is rendered and it is the place where we can perform important operations and actions.

If you run the project again and touch anywhere on the screen, you will see something that is similar to what's shown in the following screenshot:

As expected, a spaceship has been created and it has begun to rotate in a counterclockwise direction. Another important thing to note at this point is the number of nodes, which has increased and corresponds to the draw of the scene, the text label, the spaceship, and the background.

Now that we had an overview of the initial project code, it's time to go deeper into some of the classes that we saw earlier. We have seen that the default project creates instances of SKScene, SKLabelNode, and SKSpriteNode, which are subclasses of SKNode, one of the most important classes of the SpriteKit framework. You will understand why if you keep reading.