An Introduction to Building a SpriteKit-UIKit Hybrid App

Alan Chung By Alan Chung
Every now and then, the need arises to include features like lists, text fields or maps in your sprite based iOS app or game. Or you might want to include sprite animations to decorate an app based primarily on UIKit. This guide aims to help you get started on making an app that seamlessly combines the visual punch of SpriteKit with the practicality of UIKit.

Back in my day...

In days of yore (by which I mean any time before 2013), combining elements from a 2D game engine such as Cocos2d with pieces of native UI like UIKit and MapKit was a pain. It was hacky, messy and a lot of work if you didn't get the hybrid structure in place immediately after starting a new project.

Since the introduction of SpriteKit back in 2013, iOS developers have had access to a native 2D game engine, which means that adding UIKit elements to your game has never been easier. So easy in fact that I was debating with myself whether it was worth making this into a blog post at all. After all, the default "Game" template is just a SpriteKit scene within a UIKit view controller so if you know what you're doing you can just go from there.

End of tutorial.

Still here?

I suppose I can go into more detail then.

In a nutshell, SpriteKit consists of SKScenes and SKSprites. SKSprites live inside SKScenes and aren't visible outside the bounds of the SKScene. That's more or less all we need to know for this tutorial. (Obviously this is a very simplified explanation of how SpriteKit actually works!)

I've created an app called Stitch Simulator 2016 which will appear on the App Store very soon. This is what we're going to be recreating in the next steps. If you haven't already, go ahead and download the sample project below to see what we're aiming for. It's a small 'game' where you press the button and Stitch, the Eden office dog, walks across the screen. (Thanks to Shaun for the making animation!) The 'aim' of the 'game' is to mash the button and watch loads of Stitches all walk across the screen at once. I say 'aim' and 'game' because there isn't really an aim and it isn't really a game.

I have made a sample project available to download.

In the app, the red background is the SKScene and the animated Stitches are SKSprites. UIKit views are placed on top.

Stitch Simulator 2016

I started this project with the 'Single View Application' template from the new project menu in Xcode. You can either do the same or pick the 'Game' template if you like.

It started with a Stitch

Let's start with the StitchScene. This is a subclass of SKScene so we'll need to add the SpriteKit framework to our target if it isn't linked already. In our init() method we set the background colour and more importantly, we get the individual frames of the Stitch animation from our texture atlas and store them in a property called stitchFrames. The StitchScene will access this property every time a new Stitch is spawned.

var frames: [SKTexture] = []
let stitchAtlas = SKTextureAtlas(named: "Stitch")

for index in 0...15 {
	let textureName = String(format: "stitch_001%02d", index)
	let texture = stitchAtlas.textureNamed(textureName)

self.stitchFrames = frames

There's only one method in the StitchScene other than the initialisers, and that's the simulateStitch() method. This will be called from the MainViewController when the 'Simulate Stitch' button is pressed. In this method we create an SKSprite for Stitch and run an SKAction to animate through each of the frames we stored in our property stitchFrames. We then run a sequence of SKActions to move him across the screen and remove him once he's across. See below for a code snippet that achieves this.

// Assign the first frame to the sprite
let texture = self.stitchFrames![0]
let stitch = SKSpriteNode(texture: texture)

// Set the size and position of Stitch then add to the scene
stitch.size = CGSize(width: 160, height: 160)
stitch.position = CGPoint(x: self.frame.size.width + stitch.size.width * 0.5, y: self.frame.size.height * 0.5)

// Animate through all the stitchFrames
stitch.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(self.stitchFrames!, timePerFrame: 0.05, resize: false, restore: true)))

// The remaining code manages everything to do with movement of the sprite
var xMovement = -(self.frame.size.width + stitch.size.width)

// Time = displacement / velocity
// Use a constant speed of 130 points per second so it takes longer to traverse larger screens.
let time = NSTimeInterval(abs(xMovement) / 130)	
let moveAction = SKAction.moveByX(xMovement, y: 0, duration: time)

let doneAction = SKAction.runBlock {
	self.numberOfStitchesOnScreen -= 1

let moveActionAndDone = SKAction.sequence([moveAction, doneAction])

In the full source code there's also some logic to randomise the y-position of the Stitch sprite and the direction in which he moves. Feel free to check out the sample project if you're interested in how it was done.

Let there be sprite!

Let's move on to the UIKit parts. If you've downloaded the sample project, you might notice that the entire view was done in Main.storyboard with the relevant parts linked to the Swift source file via @IBOutlets and @IBActions. I've also added a scene property to the beginning of the class as we'll need to reference the StitchScene later so we can call simulateStitch(). You might notice that the outlet for the view has been changed from the default UIView to an SKView. This is so that we can call presentScene() in the next step.

@IBOutlet weak var sceneView: SKView!	// Not a UIView!

The next thing we do is instantiate a new StitchScene and add it to the view that was placed in the storyboard. This is done in viewDidAppear() because the we know that by this time, Auto Layout will have adjusted the view to be the correct size. The presentScene() method allows us to drop a scene straight into the view.

The SKView now acts as a UIKit container for our SpriteKit stuff, so we can then manipulate the SKView just like any ordinary UIView. The SKView can be made as big or small as you like—it doesn't have to take up the full screen like in the sample project. There's a reason we can manipulate it so easily. The SKView class has a dirty little secret: it's actually a subclass of UIView. Okay, it isn't really dirty or a secret, in fact it's quite the opposite. You can read more in the official Apple docs for SKView.

override func viewDidAppear(animated: Bool) {
	self.scene = StitchScene(size: CGSize(width: self.sceneView.frame.size.width, height: self.sceneView.frame.size.height))

The next method in the MainViewController is the buttonDidTouchUpInside() method. (If you're new to iOS, yes, that really is a naming convention.) The @IBAction is connected to the 'Simulate Stitch' UIButton in the storyboard. In this method we simply call simulateStitch() on our scene. This is everything we need to get SpriteKit responding to our user interactions with UIKit.

@IBAction func buttonDidTouchUpInside(sender: UIButton) {
	if let scene = self.scene {

And that's pretty much it. Of course you don't need to keep it as simple as just a UIButton calling methods on an SKScene; the entire UIKit and SpriteKit frameworks are at your disposal. Plus you don't even need to limit yourself to these two frameworks!

If you fancy, take a look at the full sample project to see the rest of the code that didn't make it into this blog post, including the stats view controller and score keeping.

Stay tuned for more on Stitch Simulator in future blog posts!
comments powered by Disqus

Introducing PowerUp

By sophie

Introducing PowerUp -- our new virtual reality solution for events.

Read more

We’re a top UK digital agency - wahoo!

By Sophie Hardbattle

We're Eden Agency - one of the UK's top digital agencies.

Read more

How to build a material design prototype using Sketch and Pixate - Part Three

By Mike Scamell

Part three of a three-part tutorial on building a material design prototype. This section focuses on adding more detail to the prototype in Pixate.

Read more

We're Hiring - Web Developer Role

By Craig Gilchrist

We are currently seeking a full time full-stack web developer to join the team at our Knaresborough office.

Read more

How to build a material design prototype using Sketch and Pixate - Part Two

By Mike Scamell

Part two of a three-part tutorial on building a material design prototype. This section focuses on creating a interactive login screen in Pixate.

Read more