SpriteKit: Project Set Up

Posted in series: SpriteKit Masterclass

First lesson is now free! Enjoy.

right-500

In this SpriteKit Masterclass series, you’ll create a 2D SpriteKit game named Gloop’s Revenge. This game pays homage to Kaboom!, a classic Atari 2600 game designed by Larry Kaplan and published by Activision in 1981.

In Kaboom! the goal was to catch the bombs the mad bomber was dropping. In Gloop’s Revenge, however, you won’t be catching bombs; you’ll be catching sticky Gloop Drops!

In this first lesson, you’ll start with the basics:

  • Project set up.
  • Working with the Asset Catalog.
  • Adding the background and foreground.

Create the Project

The first step is to create the Xcode project using a default template. From Xcode’s main menu bar, select File > New > Project….

center-500

When prompted to choose a new template for your project, select the iOS Game template and click Next.

center-500

You’re then asked to enter some options for your new project.

center-500

For the Product Name, type Gloop. For the Language, select Swift, and for the Game Technology, select SpriteKit. Since you won’t be integrating GameplayKit or adding unit or UI tests for this project, you can uncheck those options. For the Team, Organization Name, and Organization Identifier, enter your company information.

Note: The Organization Identifier uses a reverse domain name structure and is the basis for the Bundle Identifier.

When you’re done entering everything, click Next and move on to the final step.

center-500

Select a location to save your project, and verify “Create Git repository on my Mac” is not checked. Then, click Create.

Fantastic! Your project is set up and ready for you to explore.

center-max

Explore the Default Template

Before going any further, you should review the default game template to understand how things are set up.

Set the active scheme to iPhone 8 simulator, and build and run the game.

center-500

Note: To build and run the game, use Product > Run from the main menu, or use the Run button in the top-left Toolbar (it looks like a play button).

center-500

With the boilerplate iOS Game template, you get a single scene with some “Hello, World!” text. When you tap the screen, the text shrinks and expands, and an animated colored shape appears.

Sure, it’s kind of neat, but it’s not an interesting game. -[:)]

Rather than work through the details of how this demo scene was put together, you’ll tear it down and remove the demo code.

Clean Up the Default Template

There are two files you won’t need for this game. In the Project Navigator, select GameScene.sks and Actions.sks. Then, right-click and choose Delete.

center-350

When prompted about their removal, select Move to Trash.

Next, open GameScene.swift. There’s a lot going on here, and you’ll learn how to do all of it, but for now, delete everything in that file, and replace it with this:

import SpriteKit

class GameScene: SKScene {

  override func didMove(to view: SKView) {

  }
}

This code imports the SpriteKit framework and declares a GameScene class with a single, empty function: didMove(to:). You’ll learn more about that function later.

Open GameViewController.swift and remove all of the code inside viewDidLoad() except super.viewDidLoad():

When you’re done, it’ll look like this:

override func viewDidLoad() {
  super.viewDidLoad()

}

So what’s with that call to super.viewDidLoad()? When you override a subclass, most times you’ll want to use the existing superclass implementation—this is how you do it.

Finally, delete the import GameplayKit statement at the top since you won’t be using GameplayKit.

That’s it! You’re ready to start building Gloop’s Revenge.

Set Supported Device Orientation

You may have noticed when you tested the default template that its orientation is set for portrait and landscape. Gloop’s Revenge, however, was designed for landscape only, so you need to restrict the device orientation.

In the Project Navigator, select the Gloop project and look at the Deployment Info section in the Project Editor. There are a few options you need to set.

First, verify Devices is set to Universal.Gloop’s Revenge is designed for both the iPhone and the iPad, so you’ll need to let the compiler know.

Next, uncheck Portrait and check Requires full screen.

center-500

You might think this is enough to force landscape orientation on all devices—but, it’s not!

From Devices, select iPad from the drop-down and set up the same options you set before.

center-500

Although you shouldn’t have to change anything for the iPhone (because these are picked-up from the Universal settings), it’s a good idea to confirm them anyway.

There’s one more thing you need to do.

In GameViewController.swift, modify the supportedInterfaceOrientations property from this:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
  if UIDevice.current.userInterfaceIdiom == .phone {
    return .allButUpsideDown
  } else {
    return .all
  }
}

To this:

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
  return .landscape
}

This instance property returns all of the interface orientations that the view controller supports. Gloop’s Revenge only supports landscape, so it makes sense to only return that one.

After checking all of the device settings, be sure to switch back to *Universal**.

Build and run, and behold… a boring grey screen! But hey, at least it’s in landscape now, right? -[:)]

center-500

Time to get this show on the road. Er, I mean scene on the screen.

Create a Scene

Before building your first scene, it’s important to understand the key components that make up a SpriteKit scene:

  • SKView: This is the primary view for a SpriteKit scene. If you’ve developed UIKit apps for iOS, this is comparable to a UIView. In fact, SKView inherits from UIView (or NSView on macOS apps).
  • SKScene: This is the root node of the scene and is presented by a view. SKScene includes many properties and methods that define how to present content and process animation.

There are two ways in which to create a scene: visually with the Scene Editor or programmatically in code. For Gloops’s Revenge, you’ll build the scene programmatically.

Open GameViewController.swift, and in viewDidLoad(), add the following code:

// Create the view
if let view = self.view as! SKView? {

  // Create the scene
  let scene = GameScene(size:view.bounds.size)

  // Set the scale mode to scale to fill the view window
  scene.scaleMode = .aspectFill

  // Set the background color
  scene.backgroundColor =  UIColor(red: 105/255,
                                   green: 157/255,
                                   blue: 181/255,
                                   alpha: 1.0)

  // Present the scene
  view.presentScene(scene)

  // Set the view options
  view.ignoresSiblingOrder = false
  view.showsPhysics = false
  view.showsFPS = true
  view.showsNodeCount = true
}

The first step is to cast the view as an SKView. From there, you create the SKScene and set its size and scaleMode. The size of the scene depends largely on your game design and whether you want it to work across all devices. For now, you’ll set the scene size to match the view size, and you’ll scale the content to fill the view.

Note: You’ll learn more about universal scene design later and how size and scaling matter.

You’re also setting a background color, although this isn’t required.

When everything is set up, you call presentScene(_:) on the view, which presents the scene.

Finally, you set some standard view options:

  • showsPhysics: When set to true, you’re able to see the physics shapes attached to your sprites.
  • showsFPS: If you’d like to see the FPS (frames per second) count, set this to option to true. Otherwise, keep the default setting of false.
  • showsNodeCount: If you’re interested in knowing the number of nodes in your scene, set this to true. Otherwise, keep the default setting of false.

These settings are known as performance stats. There are three others: showsDrawCount, showsQuadCount, and showsFields. You won’t be using these three, so their default values of false will work, and you don’t need to add them.

The other setting, ignoresSiblingOrder, is slightly more complex and has to do with the Z-position of your nodes. When you start adding content, you’ll learn more about this property.

Build and run.

center-500

Beautiful, right? But it’s still very boring! Time to fix that.

Create Your First SKSpriteNode

A scene without content is like a game without a player. So, how do you add content? With SKNode objects.

Everything you see within a SpriteKit scene is a subclass of SKNode. However, an SKNode object does not render (draw) any visual content. To draw content, you can use:

  • SKSpriteNode: Perhaps the most widely used, this type of node draws a rectangle texture, image, or color.
  • SKShapeNode: If you need some other shape, you can use this type of node along with a Core Graphics path.
  • SKLabelNode: Need some text? Use this type of node to draw a text label.
  • SKVideoNode: How about video? This node type lets you display video content.
  • SKCropNode: Sometimes you need to mask pixels; for that, you can use this type of node.
  • SKReferenceNode: This is a special node in which you can create reusable content.

Although SKNode objects don’t provide the visuals, they do provide the baseline behavior for each of its predefined subclasses, and of course, custom subclasses that inherit from SKNode. This includes:

Position

  • frame: A rectangle within the parent’s coordinate system.
  • position: Its position within the parent’s coordinate system.
  • zPosition: Its height relative to its parent. With this setting, you can have content overlap in a specific order.

Scale & Rotation

  • xScale: The scaling factor of the X-axis (width).
  • yScale: The scaling factor of the Y-axis (height).
  • zRotation: The axis of rotation, known as a Euler axis, specified in radians.

Note: What’s a radian? The radian is the standard unit for measuring angles. Wikipedia® has a great explanation is you’re interested: https://en.wikipedia.org/wiki/Radian

There are many other properties and methods available, and you’ll learn more about them as you go, but for now, this is a good start!

Ready to create your first node?

Add Image Assets

Although it’s possible to create an SKShapeNode and colorize it, Gloop’s Revenge requires a bit more flair and style, so you need to add some images to the project.

There are several ways in which to add and use images in SpriteKit. For now, you’ll stick with the basics.

In the Project Navigator, select Assets.xcassets.

Next, launch a Finder window, and navigate to the resources folder included with the materials for this lesson. Once there, select the three background images:

  • background_1.png
  • background_1@2x.png
  • background_1@3x.png

And drag the images into Assets.xcassets.

center-max

Asset catalogs are a great way to manage and organize your assets. For a large background asset—like the one you added—it’s generally OK to add it like you did, as an Image Set. With an Image Set, you can have different image variations depending on their resolution.

In the Outline View (that’s the view to the right of the Project Navigator), select the two Image Sets you added and look at the Detail Area (to the right of the Outline View).

center-500

The background image you added includes variations for @1x, @2x, and @3x. This, however, is not mandatory, and many developers take different approaches when supplying their image assets; it depends on the original design.

The @3x variants work with the following devices:

  • iPhone XS Max.
  • iPhone XS.
  • iPhone X.
  • iPhone 8 Plus.
  • iPhone 7 Plus.
  • iPhone 6s Plus.

But Image Sets aren’t your only option; You can also add other types, like:

  • Data Set.
  • Color Set.
  • Texture Set.
  • Sprite Atlas.
  • And more.

You’ll learn about some of the other types as you work through this project.

Add the Background

With the background image assets ready and waiting, you can get them added to the scene as part of the node tree.

A node tree is an ordered list of related parent-child nodes. You create this tree by adding nodes to other nodes, essentially nesting them within each other. Because the order of the child nodes in the tree affects many things, it’s important to keep things orderly. You’ll learn more about the node tree as you add more objects to the scene.

Open GameScene.swift, and locate didMove(to:).

The function, didMove(to:), is one of two functions that automatically gets called when presenting a scene. In order, they are:

  • sceneDidLoad(): Called after the scene is initialized.
  • didMove(to:): Called after the scene is presented by a view.

There’s another function that’s automatically called too, but this one happens when a scene is removed from a view:

  • willMove(from:): Called before the scene is removed from a view.

In didMove(to:), add the following code:

// Set up background
let background = SKSpriteNode(imageNamed: "background_1")
background.position = CGPoint(x: 0, y: 0)
addChild(background)

This declares a constant named background and uses the standard initializer to init a textured sprite using the background_1 Image Set. The position is set to (x: 0, y: 0). Finally, it adds the node to the scene using addChild() on the parent node, in this case, the scene.

Note: Technically, you don’t need to set a (0,0) position, because it’s the default value. However, for clarity and instruction, it’s being set by the code.

Now, switch the active scheme to **iPad Pro (12.9-inch) (2nd generation). Then, build and run.

center-500

The background image shows up, but it’s not where it needs to be.

Position, Coordinates & Anchor Points

When you add objects to a scene and set their position information, knowing how the coordinate system works in SpriteKit is key to avoiding frustration.

In SpriteKit, the unit coordinate system puts the origin (0,0) at the bottom left corner and the top right at (1,1) as shown in the following illustration.

center-350

When you position a node, you need to consider its anchorPoint property, which defaults to (0.5,0.5).

Look at the following sprite node whose position is set to (0,0) position. Notice how changing the anchorPoint can affect the node’s position.

center-500

The image on the left is using the default anchorPoint value of (0.5,0.5), while the image on the right is using (0,0). Notice the left side image looks a lot like the background image in the previous build and run.

When you set a node’s position, it places the node at this position using the anchorPoint. In other words, the anchorPoint is what’s positioned at that point.

Still in didMove(to:), after this line:

let background = SKSpriteNode(imageNamed: "background_1")

Add this line to set the background node’s anchorPoint to location (0,0).:

background.anchorPoint = CGPoint(x: 0, y: 0)

Note: In the last two code blocks you set a (0,0) location using CGPoint(x: 0, y: 0). If you’s like, you can instead use the special value of .zero. For many developers, using .zero is preferred.

Build and run, and the background now looks proper. Well, almost.

center-500

Notice the blue strip down the right side. Clearly, something is wrong! But, before fixing it, switch the active scheme back to the iPhone 8. Then, build and run the game again.

center-500

This looks even worse! Everything is scaled up way too big. What’s happening?

The quick answer is this: The assets were designed for a scene size of 1336×1024. However, the scene size is set using the size of the view’s bounds:

let scene = GameScene(size:view.bounds.size)

This is a mismatch because the size of the view’s bounds, and therefore the scene, are:

  • iPhone 8: (667.0, 375.0)
  • iPad: (1366.0, 1024.0)

Note: To get the size of the scene, you can add print("scene.size: \(scene.size)") to viewDidLoad() after initializing the scene.

In GameViewController.swift, comment out the line where you set up the scene, and add this one in its place:

let scene = GameScene(size:CGSize(width: 1336,
                                  height: 1024))

Now, the scene size is set to match the design.

Build and run, on both the iPad Pro and iPhone simulators, and notice everything looks as it should on both devices.

center-max

In the next lesson, you’ll learn more about designing for multiple resolutions. This was just a quick introduction with very little explanation because you’ve one more thing to do before you wrap-up this lesson.

Add the Foreground

You’ve seen how to add an Image Set and get an SKSpriteNode initialized, positioned, and added to the scene. You did this with the background. It’s now time to apply that same knowledge and get the foreground added.

Add the Foreground Images

Before you can add a sprite node with a corresponding image file, you first need to add the images to the project as you did with the background.

In the Project Navigator, select Assets.xcassets.

Then, launch a Finder window, and navigate to the resources folder included with the materials for this lesson. Once there, select the three foreground images:

  • foreground_1.png
  • foreground_1@2x.png
  • foreground_1@3x.png

And drag them into Assets.xcassets.

Add the Foreground Node

Your next step is to add the code to initialize the sprite node.

Open GameScene.swift. In didMove(to:), and the following code after you set up the background:

// Set up foreground
let foreground = SKSpriteNode(imageNamed: "foreground_1")
foreground.anchorPoint = CGPoint(x: 0, y: 0)
addChild(foreground)

Build and run, and you now have a foreground on which your player can stand.

center-500

Next Steps

You made it to the end, and you’re well on your way to building out the rest of the game. In the next lesson, you’ll learn more about designing games that work across all devices.

If you get a chance, take a look at the references down below for an in-depth look at some of the key things presented in this lesson.

References

Series Navigation


<< SpriteKit MasterclassSpriteKit: Animations & Movement >>