How to Make a Waiting Game Like Farmville with SpriteKit and Swift

In this SpriteKit tutorial, you’ll learn how to make your very own waiting game — just like Farmville — with SpriteKit and Swift. By Kevin Colligan.

Leave a rating/review
Save for later
Share
Update 10/28/16: Updated for Swift 3, iOS 10, and Xcode 8 by Kevin Colligan. Original tutorial by Barbara Reichart.

Kookie Kiosk is one sweet waiting game.

Kookie Kiosk is one sweet waiting game.

In this SpriteKit tutorial, you’ll learn how to make your very own waiting game — just like Farmville — with SpriteKit and Swift.

Popular “waiting games” like Clash of Clans and Farmville are played in short, frequent bursts, punctuated by periods of waiting — plant a crop in seconds, then check back at a later time to reap what you’ve sown.

While every game is different, most are built around the following basic concepts:

  • State machines
  • Timed events
  • Local notifications

With this SpriteKit tutorial, you’ll dive right into these concepts, as you continue to build out Kookie Kiosk – a simple waiting game where players vie for riches by buying and selling tasty treats. Yum!

Note: This tutorial assumes you have working knowledge of SpriteKit and Swift. If you’re new to SpriteKit, check out our SpriteKit Swift Tutorial for Beginners or our full book, 2D Apple Games by Tutorials. For an introduction to Swift, check out this beginner Swift tutorial here.

Getting Started

Download the template project, then open the KookieKiosk-Swift.xcproject project file with Xcode.

Build and run the app in the iPad Air 2 simulator:

This is what you should see when you run the template. What a mess!

This is what you should see when you run the template. What a mess!

Don’t worry — you’ll soon clean shop.

Take a quick look at the files in this project:

  • GameScene.swift: Contains the core logic for the game. It maintains a list of all items in the kiosk and how much money you have. At startup, all on-screen elements are added to GameScene. This class also loads and saves a .plist file containing important data about the items available in the kiosk. Finally, but most importantly, it responds to changes in the game state.
  • StockItem.swift: Represents a single item in the kiosk. It stores important properties of the item like type, flavor and amount. There’s also a few constants like the maximum amount the player can have of an item, the position on the screen, prices for restocking, selling the item and even the speed at which the item is stocked and sold. The class contains two helper methods which draw the price label and the timer while the item is stocking.
  • Customer.swift: Draws a customer on-screen and stores the item the customer wants to buy.
  • GameDelegate.swift: Defines methods that StockItem.swift will call to perform game logic.
  • Constants.swift: The enum ZPosition ensures game layers are drawn in the correct order. TimeScale controls game speed.
  • AppDelegate.swift: The only change to the default AppDelegate is a preload of two sound files.
  • GameViewController.swift: Loads the initial scene.

Implementing the State Machine

Kookie Kiosk players earn money by selling cookies and shakes. But they can’t sell something they don’t own (out-of-cookies exception), nor restock a loaded platter (cookie-overflow exception). Keep things running smoothly with a state machine to define states and transitions between those states. Kookie Kiosk’s state machine can be represented by the following diagram:

States of an item in the Kiosk and transitions between states

States of an item in the Kiosk and transitions between states

Each item can be in one of four states:

  1. Empty: This item is out-of-stock. Players can buy more by tapping the item.
  2. Stocking: Once the player buys more, the item will begin stocking.
  3. Stocked: Ready to sell.
  4. Selling: Once stocked, the player taps an item to start selling. When an item is sold out, it returns to Empty.

Here are images that correspond to each state:

Visualization of each state

Enough background — it’s time to code.

Add the following to the bottom of Constants.swift:

enum State: Int {
  case empty
  case stocking
  case stocked
  case selling
}

This defines an enum with a value for each of the four states.

Next, add the following property at the end of the list of properties in StockItem.swift:

var state: State

And add the following lines to init(stockItemData:stockItemConfiguration:gameDelegate:) just before super.init():

let stateAsObject: AnyObject? = stockItemData["state"]
let stateAsInt = stateAsObject as! Int
state = State(rawValue: stateAsInt)!

In the code above you retrieve the state from the dictionary stockItemData, which contains all information about the stock item loaded from gamedata.plist shown below:

StockItemData Plist

In the code above, you retrieve the value from stockItemData stored under the key “state” and then cast it to an Int. Then, you map the value of the Int to the corresponding value of the enum State and assign the result to the state.

Now that you can load the state of the item, make sure the state can be saved.

Add the following line to data() in StockItem.swift, right before the return statement:

data["state"] = state.rawValue

This line sets the value for the key “state” to the raw Int value of the state for the stock item.

That takes care of loading and storing the states. Next, you’ll add code for displaying the state changes.

Cleaning up the Interface

Add the following method to StockItem.swift:

func switchTo(state: State) {
  self.state = state
  switch state {
  case .empty:
    stockingTimer.isHidden = true
    sellButton.isHidden = true
    priceTag.isHidden = false
  case .stocking:
    stockingTimer.isHidden = false
    sellButton.isHidden = true
    priceTag.isHidden = true
  case .stocked:
    stockingTimer.isHidden = true
    sellButton.isHidden = false
    priceTag.isHidden = true
    progressBar.setProgress(percentage: 1)
  case .selling:
    stockingTimer.isHidden = true
    sellButton.isHidden = true
    priceTag.isHidden = true
  }
}

This method contains a switch statement that distinguishes between the four states of your stock item. For each state, it sets isHidden appropriately for the stocking timer, sell button and price tag.

For example, when the price tag is visible in the empty state; you hide the stocking timer and the sell button. The other states follows the same logic.

Add the following line to the end of init(stockItemData:stockItemConfiguration:gameDelegate:):

switchTo(state: state)

This will initialize the stock item to the state loaded from gamedata.plist.

Build and run your project. All stock items should now start off in the empty state. They should also now display their price tag, ready and waiting for the player to act:

Bringing order to the chaos is really satisfying!

Bringing order to the chaos is really satisfying!
Kevin Colligan

Contributors

Kevin Colligan

Author

Kyle Gorlick

Tech Editor

Chris Language

Final Pass Editor

Tammy Coron

Team Lead

Over 300 content creators. Join our team.