Day 71 - 100 Days of Swift

4 minute read

Project 20 (part 2)

Day 71 is the second part of the twentieth project. Today you make the game playable by giving the user the ability to explode fireworks when they shake the device. He also gives you three challenges to make the game a little better. He challenges you to add a label to display the current score. He challenges you to end the game after a certain number of launches. And he challenges you to clean up after the emitter nodes, so there isn’t an ever-increasing number of nodes on screen.

First, you add a function to explode a single firework:

1
2
3
4
5
6
7
8
func explode(firework: SKNode) {
    if let emitter = SKEmitterNode(fileNamed: "explode") {
        emitter.position = firework.position
        addChild(emitter)
    }

    firework.removeFromParent()
}

Then you add a function that loops through and checks for all of the fireworks that should be exploded, and updates the score:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
func explodeFireworks() {
    var numExploded = 0

    for (index, fireworkContainer) in fireworks.enumerated()
                                               .reversed() {
        guard let firework =
            fireworkContainer.children.first as? SKSpriteNode else {
                continue
            }

        if firework.name == "selected" {
            explode(firework: fireworkContainer)
            fireworks.remove(at: index)
            numExploded += 1
        }
    }

    score += numExploded * numExploded * 200
}

I changed the way the score was calculated because his version is like fifteen lines long and does pretty much the same thing: it gives you more points the more fireworks you blow up at once.

Then you add the code to detect when the device has been shaken and call explodeFireworks from there. It is in the GameViewController.swift file:

1
2
3
4
5
6
override func motionBegan(_ motion: UIEvent.EventSubtype,
                          with event: UIEvent?) {
    guard let skView = view as? SKView else { return }
    guard let gameScene = skView.scene as? GameScene else { return }
    gameScene.explodeFireworks()
}

At this point the game is playable, but I went ahead and implemented the three challenges real quick as well. First, I added a scoreLabel, set it up in didMove(to:) and updated it from the didSet observer on score:

1
2
3
4
5
6
7
8
9
10
11
private var scoreLabel: SKLabelNode!
private var score = 0 {
    didSet { scoreLabel.text = "Score: \(score)" }
}

// in didMove(to:)
scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
scoreLabel.position = CGPoint(x: 120, y: 16)
scoreLabel.horizontalAlignmentMode = .center
addChild(scoreLabel)
score = 0

Then I added a property to keep track of how many launches we’ve had so far and watched it to see when the game should end:

1
2
3
4
5
6
7
8
9
10
private var numberOfLaunches = 0 {
    didSet {
      if numberOfLaunches >= 10 {
        gameTimer?.invalidate()
      }
    }
}

// At the end of launchFireworks
numberOfLaunches += 1

Finally, I added this sequence to run on the SKEmitterNode for the explosion:

1
2
3
4
5
// in explode(firework:)
let wait = SKAction.wait(forDuration: 1)
let remove = SKAction.removeFromParent()
let sequence = SKAction.sequence([wait, remove])
emitter.run(sequence)

And that completes the game and all the challenges he gives you. It looks like this:

You can find my version of this project at the end of day 71 on Github here.

Reflections

I did not enjoy this game as much as I’ve enjoyed some of the others. It doesn’t seem as challenging and having to shake the iPad to blow up the fireworks is a weird mechanism. To his credit, he agrees and was just looking for an excuse to demonstrate how you would detect the device being shaken, so if I were to take this farther I would look for some other mechanism to blow up the fireworks. Maybe just once the first one crossed the threshold to go off screen? Or add a button to blow them up? Maybe a multiple finger tap? Almost anything would be better than shaking it. Some other ideas would be to add a nicer game over condition, a way to restart the game and maybe some way to add levels of increasing complexity/difficulty.