Putting a SpriteKit Scene on a View Controller
by
Lou Franco
In a typical iOS app, you build your screens either with UIKit's UIViewController
, UIView
and possibly storyboards or you might try SwiftUI and build out a View
based on an ObservableObject
.
Those kinds of apps often have scrollable lists of data, forms, tabs, or hierarchical navigation suitable for a to do list or an email client.
But games are something very different.
To develop 2D games on iOS, Apple has provided SpriteKit. SpriteKit builds up its user interfaces from nodes that are in a "physics world" scene.
To get an idea of what that means, let's build a very minimal scene.
Scenes are hosted in view controllers
If you start with a blank app in Xcode (not the game template), you get an empty view controller to start. If you put this code in it, it will host an empty SpriteKit scene.
First, we need to import SpriteKit
Then, use this code in your view controller.
class GameViewController: UIViewController {
var scene: GameScene?
override func loadView() {
super.loadView()
self.view = SKView()
self.view.bounds = UIScreen.main.bounds
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
setupScene()
}
func setupScene() {
if let view = self.view as? SKView, scene == nil {
let scene = GameScene(size: view.bounds.size)
view.presentScene(scene)
self.scene = scene
}
}
override var prefersStatusBarHidden: Bool {
return true
}
}
And make a new file called GameScene.swift with this code:
import SpriteKit
import GameplayKit
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMove(to view: SKView) {
self.backgroundColor = .cyan
}
}
If you do that correctly, you will see a blank Cyan colored full screen. That screen is a SpriteKit scene. The function didMove(to view:)
is called when scene is presented by the view controller and can be used to set up the game.
The Coordinate System
In SpriteKit, the coordinate system is a little different than UIKit. The origin is at the bottom-left of the screen. As you move to the right, X increases, and as you move up, Y increases. This might actually be more intuitive to you as it matches the coordinate system used in most graphs, but if you are used to UIKit, then you have to get used to Y being flipped.
Also, when you place objects, you are placing their center-point. In UIKit, the position of a view is its top-left point, but if you imagine setting the center
property instead, it will match what SpriteKit does when you set a node's position.
A Falling Ball
In SpriteKit, a game is a physics simulation. There is gravity, and objects have friction, mass, and bounce off each other.
Let's put a ball in the air and let it fall to the ground.
In UIKIt, we have different UIViews like labels and buttons. In SpriteKit, we have different node types. For this code, we'll use the SKShapeNode
which can render as different simple shapes like a circle or rectangle.
The basic idea is to create nodes, set up their physical behavior, attributes, and starting position, and then add them to the scene.
func setupGame() {
guard let view = self.view else { return }
// Create a ball that looks like a circle and acts like a circle to the physics engine
let ball = SKShapeNode(circleOfRadius: 10)
ball.physicsBody = SKPhysicsBody(circleOfRadius: 10)
// Put it in the center of the screen and make it white
ball.position = CGPoint(x: view.frame.midX, y: view.frame.midY)
ball.fillColor = .white
addChild(ball)
// Create the ground which looks and acts like a rectangle at the bottom of the screen
let groundHeight: CGFloat = 40
let size = CGSize(width: view.frame.size.width, height: groundHeight)
let ground = SKShapeNode(rectOf: size)
ground.physicsBody = SKPhysicsBody(rectangleOf: size)
// Put the ground on the bottom of the screen and make it brown
ground.position = CGPoint(x: view.frame.midX, y: groundHeight / 2)
ground.fillColor = .brown
// The ground is not affected by gravity and doesn't move
ground.physicsBody?.isDynamic = false
addChild(ground)
}
Make sure to put a call to setupGame()
in the didMove(to view:)
function.
When you run it, it looks like this:
What's next
In the next few articles, we'll make some useful extensions and then look at how to make Pong.
Make sure to sign up to my newsletter to get notified when a new article is published.
Contact me if you are working on a Game and need help.
Next Article: Some useful SKPhysicsBody Extensions for SpriteKit nodes