Sprite Kit for Kids with Swift
Learn how to make a simple iPhone game using Sprite Kit – by a 13-year old game developer! By Ajay Venkat.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Game Over!
In this section you will display a game over Screen to the player when your player either collides with an enemy or falls out of the screen. You will also create a start screen where the user is instructed to Touch the screen to begin! :]
Start by adding all these variables to the top of GameScene
, right after the line let player = SKSpriteNode(imageNamed:"spacemonkey_fly02")
:
// 1
var gameOver = false
// 2
let endLabel = SKLabelNode(text: "Game Over")
let endLabel2 = SKLabelNode(text: "Tap to restart!")
let touchToBeginLabel = SKLabelNode(text: "Touch to begin!")
let points = SKLabelNode(text: "0")
// 3
var numPoints = 0
// 4
let explosionSound = SKAction.playSoundFileNamed("explosion.mp3", waitForCompletion: true)
let coinSound = SKAction.playSoundFileNamed("coin.wav", waitForCompletion: false)
Let’s review this section by section:
- First you create a
bool
calledgameOver
to keep track whether the game is over or not. - Next you create a few label nodes, which is how you display text to the screen in Sprite Kit.
- Next you create an
integer
to store the amount of points you have. Note you mark this withvar
, notlet
, because you want to be able to change the value after creating it. - Last you create some actions you will use later to play some sound effects.
Next create a new method called setupLabels()
:
func setupLabels() {
// 1
touchToBeginLabel.position = CGPoint(x: frame.size.width/2, y: frame.size.height/2)
touchToBeginLabel.fontColor = UIColor.whiteColor()
touchToBeginLabel.fontSize = 50
addChild(touchToBeginLabel)
// 2
points.position = CGPoint(x: frame.size.width/2, y: frame.size.height * 0.1)
points.fontColor = UIColor.whiteColor()
points.fontSize = 100
addChild(points)
}
Let’s review this section by section:
- You position the “touch to begin” label to the center of the screen, with a white color, and 50pt font size.
- You set the position label toward the bottom of the screen, with a white color and a font size of 100.
Now call the setupLabels()
in didMoveToView(_:)
:
setupLabels()
Now delete touchesBegan(_:withEvent:)
and replace it with this :
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// 1
if (!gameOver) {
if player.physicsBody?.dynamic == false {
player.physicsBody?.dynamic = true
touchToBeginLabel.hidden = true
backgroundColor = SKColor.blackColor()
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runBlock(spawnEnemy),
SKAction.waitForDuration(1.0)])))
}
// 2
jumpPlayer()
}
// 3
else if (gameOver) {
let newScene = GameScene(size: size)
newScene.scaleMode = scaleMode
let reveal = SKTransition.flipHorizontalWithDuration(0.5)
view?.presentScene(newScene, transition: reveal)
}
}
Let’s review this section by section:
- If the game isn’t over, and the player isn’t dynamic (i.e. moved by the physics engine) yet, then that means the game hasn’t started yet. So you set dynamic to true, hide the label, and begin spawning enemies.
- You call the
jumpPlayer
anyway because it will only work ifdynamic
is set to true. - If the game is over, you start the game over by creating a new instance of your
GameScene
and presenting that new scene..
Next, add this new method to your class:
override func update(currentTime: CFTimeInterval) {
//1
if !gameOver {
//2
if player.position.y <= 0 {
endGame()
}
//3
enumerateChildNodesWithName("enemy") {
enemy, _ in
//4
if enemy.position.x <= 0 {
//5
self.updateEnemy(enemy)
}
}
}
}
Let's review this section by section:
- You check if
gameOver
is false and if it is then you check if the player is out of the screen, if the player is out of the screen it callsendGame
which you will add later. - Your tell
enumerateChildNodesWithName
to find every single child in the scene with the name of "enemy". For each enemy, you check if any of the enemies position is out of the screen and if it is, it callsupdateEnemy()
which you will also add later.
Now you will add the method called updateEnemy()
. This which will be called before every frame is rendered so if any enemy leave the screen you can give a point to the user:
func updateEnemy(enemy: SKNode) {
//1
if enemy.position.x < 0 {
//2
enemy.removeFromParent()
//3
runAction(coinSound)
//4
numPoints++
//5
points.text = "\(numPoints)"
}
}
Let's review this line by line:
- Checks if the enemy position is out of the screen in x axis.
- If it is, it removes the enemy from the parent (removes the enemy from the game).
- Adds a point to the
numPoints
which holds the amount of points you have. - Converts points into a string and inserts that string into the points label.
Now you have to change didBeginContact(_:)
a little bit. Add this line of code after you remove the first node from parent:
endGame()
Now for the part you have all been waiting for - the endGame
method:
func endGame() {
// 1
gameOver = true
// 2
removeAllActions()
// 3
runAction(explosionSound)
// 4
endLabel.position = CGPoint(x: frame.size.width/2, y: frame.size.height/2)
endLabel.fontColor = UIColor.whiteColor()
endLabel.fontSize = 50
endLabel2.position = CGPoint(x: frame.size.width/2, y: frame.size.height/2 + endLabel.fontSize)
endLabel2.fontColor = UIColor.whiteColor()
endLabel2.fontSize = 20
points.fontColor = UIColor.whiteColor()
addChild(endLabel)
addChild(endLabel2)
}
Let's review this section by section:
- You set
gameOver
to true. - You remove all actions in the scene, to stop any further animation.
- Runs the explosion sound.
- Position and adds the
endLabel
s to the scene.
Now go to didMoveToView(_:)
and remove this block of code :
backgroundColor = SKColor.blackColor()
runAction(SKAction.repeatActionForever(
SKAction.sequence([
SKAction.runBlock(spawnEnemy),
SKAction.waitForDuration(1.0)])))
Finally add this line in its place:
player.physicsBody?.dynamic = false
This sets the player so he doesn't move at the start of the game until you tap.
Build and run, and you have a completely playable game!
OMG - that's your game done, good job! :D
Gratuitous Background Music
But wait, there's one more thing!
Open ViewController.swift and add this new property:
var backgroundMusicPlayer: AVAudioPlayer!
Also add this new method:
func playBackgroundMusic(filename: String) {
let url = NSBundle.mainBundle().URLForResource(
filename, withExtension: nil)
if (url == nil) {
println("Could not find file: \(filename)")
return
}
var error: NSError? = nil
backgroundMusicPlayer =
AVAudioPlayer(contentsOfURL: url, error: &error)
if backgroundMusicPlayer == nil {
println("Could not create audio player: \(error!)")
return
}
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
This is a handy helper method to play some background music - you don't need ot know how it works for this tutorial.
Using it is simple. Add this line the viewWillLayoutSubviews()
, right after the line skView.presentScene(scene)
:
playBackgroundMusic("BackgroundMusic.mp3")
Build and run, and enjoy your awesome music made by yours truly... aww yeah!