1

Create a SpriteKit Game Project

11:21FreeDone
2

Lay Out the Game UI

8:54FreeDone

Define the Game Piece Model

13:16FreeDone
4

Create the Level Model

5:47FreeDone
5

Draw the Rune Sprites

6:02FreeDone
6

Detecting Taps on Runes

5:27ProsDone
7

Determine Swipe Direction

6:18ProsDone
8

Add Physics to Shatter Runes

14:00ProsDone
9

Build Out the UI Text

12:24ProsDone
10

Keeping Score

8:41ProsDone
11

Displaying Score Feedback

8:18ProsDone

Define the Game Piece Model

Published by Chris Slowik

Episode Notes

Extra tips from the author

Make Some Custom Types

Before we get into building our Rune game piece class, it sure would be nice to have some custom types to support some properties of the rune - the color and rune type specifically. Lets build those first! Make a new swift file called Rune, and start by adding an enum that will hold the rune type attribute - call it RuneType. We'll make it a string value and make it conform to the CustomStringConvertible protocol so we can get nice printable descriptions - simply implement a var description with the raw value. We also include a random function that will enforce our game rules when we select a random rune, by setting even odds for left/right, and a 1/6 chance of a "force" rune.

enum RuneType: String, CustomStringConvertible {
    case force = "force"
    case left = "left"
    case right = "right"

    var description: String {
        return self.rawValue
    }

    static func random() -> RuneType {
        let swipeLeft = Int(arc4random_uniform(2)) == 1
        let forceChip = Int(arc4random_uniform(6)) == 1

        if swipeLeft { return .left }
        else if forceChip { return .force }
        else { return .right }
    }
}

Now the RuneColor enum. This one will be an Int type and don't forget the CustomStringConvertible protocol! First we'll want to list all our color choices. This matches the images supplied with the game. If you make your own graphics, make sure to match. Then, make a colorName variable that just selects a string value from an array based on the color index. The description will return that color name as well. Finally, there are a few random functions to create, for some flexibility when it comes to picking runes. The first one is a simple random function. Then, one to select from a certain number of colors, and the last one which picks a color from a supplied palette of RuneColor.

enum RuneColor: Int, CustomStringConvertible {
    case red    = 0
    case yellow = 1
    case green  = 2
    case teal   = 3
    case blue   = 4
    case purple = 5

    var colorName: String {
        let strings = ["red", "yellow", "green", "teal", "blue", "purple"]
        return strings[self.rawValue]
    }

    var description: String {
        return colorName
    }

    static func random() -> RuneColor {
        return RuneColor(rawValue: Int(arc4random_uniform(6)))!
    }

    static func random(_ numColors: Int) -> RuneColor {
        return RuneColor(rawValue: Int(arc4random_uniform(UInt32((numColors < 7 && numColors > 0) ? numColors : 6))))!
    }

    static func randomFromPalette(_ pal: [RuneColor]) -> RuneColor {
        let randomIndex = Int(arc4random_uniform(UInt32(pal.count)))
        return pal[randomIndex]
    }
}

The Rune Class Itself

With that groundwork out of the way we can now build the actual Rune class. There are four properties of the game piece - the slot it's currently in, the color and type, and the sprite that represents those attributes. We of course need to include a description variable for the CustomStringConvertible protocol, and here we can really see the value of doing this. The rune color and type can easily be inserted into strings - and now we'll be able to do that with runes also. Finish off the class with an init function that takes a slot, color, and type, and simply sets those values on self.

class Rune: CustomStringConvertible {
    // MARK: - Properties
    var slot: Int
    let runeColor: RuneColor
    let runeType: RuneType
    var sprite: SKSpriteNode?

    var description: String {
        return "[\(slot)] Color: \(runeColor), Type: \(runeType)"
    }

    // MARK: - Lifecycle
    init(slot: Int, runeColor: RuneColor, runeType: RuneType) {
        self.slot = slot
        self.runeType = runeType
        self.runeColor = runeColor
    }
}

That's all we need to do to prepare our game piece data model.

Episode Topics: