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.

Leave a rating/review
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

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:

  1. First you create a bool called gameOver to keep track whether the game is over or not.
  2. Next you create a few label nodes, which is how you display text to the screen in Sprite Kit.
  3. Next you create an integer to store the amount of points you have. Note you mark this with var, not let, because you want to be able to change the value after creating it.
  4. 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:

  1. You position the “touch to begin” label to the center of the screen, with a white color, and 50pt font size.
  2. 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:

  1. 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.
  2. You call the jumpPlayer anyway because it will only work if dynamic is set to true.
  3. 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:

  1. 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 calls endGame which you will add later.
  2. 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 calls updateEnemy() 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:

  1. Checks if the enemy position is out of the screen in x axis.
  2. If it is, it removes the enemy from the parent (removes the enemy from the game).
  3. Adds a point to the numPoints which holds the amount of points you have.
  4. 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:

  1. You set gameOver to true.
  2. You remove all actions in the scene, to stop any further animation.
  3. Runs the explosion sound.
  4. Position and adds the endLabels 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!

Ajay Venkat

Contributors

Ajay Venkat

Author

Over 300 content creators. Join our team.