Chapter 1. Laying Out a Game

Games are software, and the best software has had some thought put into it regarding how it’s going to work. When you’re writing a game, you need to keep in mind how you’re going to handle the individual tasks that the game needs to perform, such as rendering graphics, updating artificial intelligence (AI), handling input, and the hundreds of other small tasks that your game will need to deal with.

In this chapter, you’ll learn about ways you can lay out the structure of your game that will make development easier. You’ll also learn how to organize the contents of your game so that adding more content and gameplay elements is easier, and find out how to make your game do multiple things at once.

Laying Out Your Engine

Problem

You want to determine the best way to lay out the architecture of your game.

Solution

The biggest thing to consider when you’re thinking about how to best lay out your game is how the game will be updated. There are three main things that can cause the state of the game to change:

Input from the user
The game may change state when the user provides some input, such as tapping a button or typing some text. Turn-based games are often driven by user input (e.g., in a game of chess, the game state might only be updated when the user finishes moving a piece).
Timers
The game state may change every time a timer goes off. The delay between timer updates might be very long (some web-based strategy games have turns that update only once a day), or very short (such as going off every time the screen finishes drawing). Most real-time games, like shooters or real-time strategy games, use very short-duration timers.
Input from outside

The game state may change when information from outside the game arrives. The most common example of this is some information arriving from the network, but it can also include data arriving from built-in sensors, such as the accelerometer.

Sometimes, this kind of updating is actually a specific type of timer-based update, because some networks or sensors need to be periodically checked to see if new information has arrived.

Discussion

None of these methods are mutually exclusive. You can, for example, run your game on a timer to animate content, and await user input to move from one state to the next.

Updating every frame is the least efficient option, but it lets you change state often, which makes the game look smooth.

Creating an Inheritance-Based Game Layout

Problem

You want to use an inheritance-based (i.e., a hierarchy-based) architecture for your game, which is simpler to implement.

Solution

First, define a class called GameObject:

class GameObject: NSObject {
    func update(deltaTime : Float) {

        // 'deltaTime' is the number of seconds since
        // this was last called.

        // This method is overriden by subclasses to update
        // the object's state - position, direction, and so on.
    }
}

When you want to create a new kind of game object, you create a subclass of the GameObject class, which inherits all of the behavior of its parent class and can be customized:

class Monster: GameObject {

    var hitPoints : Int = 10 // how much health we have
    var target : GameObject? // the game object we're attacking

    override func update(deltaTime: Float) {

        super.update(deltaTime)

        // Do some monster-specific updating

    }

}

Discussion

In an inheritance-based layout, as shown in Figure 1-1, you define a single base class for your game object (often called GameObject), which knows about general tasks like being updated, and then create subclasses for each specific type of game object. This hierarchy of subclasses can be multiple levels deep (e.g., you might subclass the GameObject class to make the Monster subclass, and then subclass that to create the Goblin and Dragon classes, each of which has its own different kinds of monster-like behavior).

An inheritance-based layout.
Figure 1-1. An inheritance-based layout

The advantage of a hierarchy-based layout is that each object is able to stand alone: if you have a Dragon object, you know that all of its behavior is contained inside that single object, and it doesn’t rely on other objects to work. The downside is that you can often end up with a very deep hierarchy of different game object types, which can be tricky to keep in your head as you program.

Creating a Component-Based Game Layout

Problem

You want to use a component-based architecture for your game, which allows for greater flexibility.

Solution

First, define a Component class. This class represents components that are attached to game objects—it is a very simple class that, at least initially, only has a single method and a single property:

@class GameObject;
@interface Component : NSObject

- (void) update:(float)deltaTime;

@property (weak) GameObject* gameObject;
@end

Next, define a GameObject class. This class represents game objects:

class Component: NSObject {

    // The game object this component is attached to
    var gameObject : GameObject?

    func update(deltaTime : Float) {
        // Update this component
    }

}

The implementation for this class looks like this:

class GameObject: NSObject {

    // The collection of Component objects attached to us
    var components : [Component] = []

    // Add a component to this gameobject
    func addComponent(component : Component) {
        components.append(component)
        component.gameObject = self
    }

    // Remove a component from this game object, if we have it
    func removeComponent(component : Component) {
        if let index = find(components, component) {
            component.gameObject = nil
            components.removeAtIndex(index)
        }
    }

    // Update this object by updating all components
    func update(deltaTime : Float) {

        for component in self.components {
            component.update(deltaTime)
        }

    }

    // Returns the first component of type T attached to this
    // game object
    func findComponent<T: Component>() -> T?{

        for component in self.components {
            if let theComponent = component as? T {
                return theComponent
            }
        }

        return nil;
    }

    // Returns an array of all components of type T
    // (this returned array might be empty)
    func findComponents<T: Component>() -> [T?] {
        // NOTE: this returns an array of T? (that is,
        // optionals), even though it doesn't strictly need
        // to. This is because Xcode 6.1.1's Swift compiler
        // was crashing when this function returned an array of T
        // (that is, non-optionals). Your mileage may vary.

        var foundComponents : [T] = []

        for component in self.components {
            if let theComponent = component as? T {
                foundComponents.append(theComponent)
            }
        }

        return foundComponents
    }

}

Using these objects looks like this:

// Define a type of component
class DamageTaking : Component {
    var hitpoints : Int = 10

    func takeDamage(amount : Int) {
        hitpoints -= amount
    }
}

// Make an object - no need to subclass GameObject,
// because its behavior is determined by which
// components it has
let monster = GameObject()

// Add a new DamageTaking component
monster.addComponent(DamageTaking())

// Get a reference to the first DamageTaking component
let damage : DamageTaking? = monster.findComponent()
damage?.takeDamage(5)

// When the game needs to update, send all game
// objects the "update" message.
// This makes all components run their update logic.
monster.update(0.33)

Discussion

In a component-based architecture, as shown in Figure 1-2, each game object is made up of multiple components. Compare this to an inheritance-based architecture, where each game object is a subclass of some more general class (see Creating an Inheritance-Based Game Layout).

A component-based layout means you can be more flexible with your design and not worry about inheritance issues. For example, if you’ve got a bunch of monsters, and you want one specific monster to have some new behavior (such as, say, exploding every five seconds), you just write a new component and add it to that monster. If you later decide that you want other monsters to also have that behavior, you can add that behavior to them, too.

In a component-based architecture, each game object has a list of components. When something happens to an object—for example, the game updates, or the object is added to or removed from the game—the object goes through all of its components and notifies them. This gives them the opportunity to respond in their own way.

A component-based layout.
Figure 1-2. A component-based layout

The main problem with component-based architectures is that it’s more laborious to create multiple copies of an object, because you have to create and add the same set of components every time you want a new copy.

Note

The findComponent and findComponents methods are worth a little explanation. These functions are designed to let you get a reference to a component, or an array of components, attached to the game object. The functions use generics to make them return an array of the type of component you expect. This means that you don’t need to do any type casting in your code—you’re guaranteed to receive objects that are the right type.

Calculating Delta Times

Problem

You want to know how many seconds have elapsed since the last time the game updated.

Solution

First, decide which object should be used to keep track of time. This may be a view controller, an SKScene, a GLKViewController, or something entirely custom.

Create an instance variable inside that object:

class TimeKeeper: NSObject {

    var lastFrameTime : Double = 0.0

}

Then, each time your game is updated, get the current time in milliseconds, and subtract lastFrameTime from that. This gives you the amount of time that has elapsed since the last update.

When you want to make something happen at a certain rate—for example, moving at 3 meters per second—multiply the rate by the delta time:

func update(currentTime : Double) {

    // Calculate the time since this method was last called
    let deltaTime = currentTime - lastFrameTime

    // Move at 3 units per second
    let movementSpeed = 3.0

    // Multiply by deltaTime to work out how far
    // an object needs to move this frame
    someMovingObject.move(distance: movementSpeed * deltaTime)

    // Set last frame time to current time, so that
    // we can calculate the delta time when we're next
    // called
    lastFrameTime = currentTime
}

Discussion

“Delta time” means “change in time.” Delta times are useful for keeping track of how much time has elapsed from one point in time to another—in games, this means the time from one frame to the next. Because the game content changes frame by frame, the amount of time between frames becomes important.

Additionally, the amount of time between frames might change a little. You should always be aiming for a constant frame rate of 60 frames per second (i.e., a delta time of 16 milliseconds: 1÷60 = 0.0166); however, this may not always be achievable, depending on how much work needs to be done in each frame. This means that delta time might vary slightly, so calculating the delta time between each frame becomes necessary if you want rates of change to appear constant.

Some engines give you the delta time directly. For example, CADisplayLink gives you a duration property (see Updating Based on When the Screen Updates), and GLKViewController gives you timeSinceLastUpdate (see Rotating a Cube).

Some engines give you just the current time, from which you can calculate the delta time. For example, the SKScene class passes the currentTime parameter to the update: method (discussed further in Adding Thrusters to Objects).

In other cases (e.g., if you’re doing the main loop yourself), you won’t have easy access to either. In these cases, you need to get the current time yourself:

let currentTime = NSDate.timeIntervalSinceReferenceDate() as Double

Detecting When the User Enters and Exits Your Game

Problem

You want to detect when the user leaves your game, so that you can pause the game. You also want to know when the user comes back.

Solution

To get notified when the user enters and exits your game, you register to receive notifications from an NSNotificationCenter. The specific notifications that you want to receive are UIApplicationDidBecomeActiveNotification, UIApplicationWillEnterForegroundNotification, UIApplicationWillResignActiveNotification, and UIApplicationDidEnterBackgroundNotification:

override func viewDidLoad() {
    super.viewDidLoad()

    let center = NSNotificationCenter.defaultCenter()

    center.addObserver(self,
        selector: "applicationDidBecomeActive:",
        name: UIApplicationDidBecomeActiveNotification,
        object: nil)

    center.addObserver(self,
        selector: "applicationWillEnterForeground:",
        name: UIApplicationWillEnterForegroundNotification,
        object: nil)

    center.addObserver(self,
        selector: "applicationWillResignActive:",
        name: UIApplicationWillResignActiveNotification,
        object: nil)

    center.addObserver(self,
        selector: "applicationDidEnterBackground:",
        name: UIApplicationDidEnterBackgroundNotification,
        object: nil)

}

func applicationDidBecomeActive(notification : NSNotification) {
    NSLog("Application became active")
}

func applicationDidEnterBackground(notification : NSNotification) {
    NSLog("Application entered background - unload textures!")
}

func applicationWillEnterForeground(notification : NSNotification) {
    NSLog("Application will enter foreground - reload " +
        "any textures that were unloaded")
}

func applicationWillResignActive(notification : NSNotification) {
    NSLog("Application will resign active - pause the game now!")
}

deinit {
    // Remove this object from the notification center
    NSNotificationCenter.defaultCenter()
        .removeObserver(self)
}

Discussion

On iOS, only one app can be the “active” application (i.e., the app that is taking up the screen and that the user is interacting with). This means that apps need to know when they become the active one, and when they stop being active.

When your game is no longer the active application, the player can’t interact with it. This means that the game should pause (see Pausing a Game). When the game resumes being the active application, the player should see a pause screen.

Note

Pausing, of course, only makes sense in real-time games, such as shooters, driving games, arcade games, and so on. In a turn-based game, like a strategy or puzzle game, you don’t really need to worry about the game being paused.

In addition to being the active application, an application can be in the foreground or the background. When an application is in the foreground, it’s being shown on the screen. When it’s in the background, it isn’t visible at all. Apps that are in the background become suspended after a short period of time to save battery power. Apps that enter the background should reduce their memory consumption as much as possible; if your app consumes a large amount of memory while it is in the background, it is more likely to be terminated by iOS.

Updating Based on a Timer

Problem

You want to update your game after a fixed amount of time.

Solution

Use an NSTimer to receive a message after a certain amount of time, or to receive an update on a fixed schedule.

First, add an instance variable to your view controller:

var timer : NSTimer?

Next, add a method that takes an NSTimer parameter:

func updateWithTimer(timer: NSTimer) {
    // Timer went off; update the game
    NSLog("Timer went off!")
}

Finally, when you want to start the timer:

// Start a timer
self.timer = NSTimer.scheduledTimerWithTimeInterval(0.5,
    target: self, selector: "updateWithTimer",
    userInfo: nil, repeats: true)

To stop the timer:

// Stop a timer
self.timer?.invalidate()
self.timer = nil

Discussion

An NSTimer waits for a specified number of seconds, and then calls a method on an object that you specify. You can change the number of seconds by changing the timeInterval parameter.

You can also make a timer either fire only once or repeat forever, by changing the repeats parameter to false or true, respectively.

Problem

You want to update your game every time the screen redraws.

Solution

Use a CADisplayLink, which sends a message every time the screen is redrawn.

First, import the QuartzCore framework:

import QuartzCore

Next, add an instance variable to your view controller:

var displayLink : CADisplayLink?

Next, add a method that takes a single parameter (a CADisplayLink):

func screenUpdated(displayLink : CADisplayLink) {
    // Update the game.
}

Finally, add this code when you want to begin receiving updates:

// Create and schedule the display link
displayLink = CADisplayLink(target: self, selector: "screenUpdated:")
displayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)

When you want to pause receiving updates, set the paused property of the CADisplayLink to YES:

// Pause the display link
displayLink?.paused = true

When you want to stop receiving updates, call invalidate on the CADisplayLink:

// Remove the display link; once done, you need to
// remove it from memory
displayLink?.invalidate()
displayLink = nil

Discussion

When we talk about “real-time” games, what comes to mind is objects like the player, vehicles, and other things moving around the screen, looking like they’re in continuous motion. This isn’t actually what happens, however—what’s really going on is that the screen is redrawing itself every 1/60 of a second, and every time it does this, the locations of some or all of the objects on the screen change slightly. If this is done fast enough, the human eye is fooled into thinking that everything’s moving continuously.

Note

In fact, you don’t technically need to update as quickly as every 1/60 of a second—anything moving faster than 25 frames per second (in other words, one update every 1/25 of a second) will look like motion. However, faster updates yield smoother-looking movement, and you should always aim for 60 frames per second.

You’ll get the best results if you update your game at the same rate as the screen. You can achieve this with a CADisplayLink, which uses the Core Animation system to figure out when the screen has updated. Every time this happens, the CADisplayLink sends its target a message, which you specify.

It’s worth mentioning that you can have as many CADisplayLink objects as you like, though they’ll all update at the same time.

Pausing a Game

Problem

You want to be able to pause parts of your game, but still have other parts continue to run.

Solution

Keep track of the game’s “paused” state in a Bool variable. Then, divide your game objects into two categories—ones that run while paused, and ones that don’t run while paused:

for gameObject in self.gameObjects {

    // Update it if we're not paused, or if this game object
    // ignores the paused state
    if self.paused == false || gameObject.canPause == false {
        gameObject.update(deltaTime)
    }

}

Discussion

The simplest possible way to pause the game is to keep track of a pause state; every time the game updates, you check to see if the pause state is set to true, and if it is, you don’t update any game objects.

However, you often don’t want every single thing in the game to freeze. For example:

  • The user interface may need to continue to animate.
  • The network may need to keep communicating with other computers, rather than stopping entirely.

In these cases, having special objects that never get paused makes more sense.

Calculating Time Elapsed Since the Game Start

Problem

You want to find out how much time has elapsed since the game started.

Solution

When the game starts, create an NSDate object and store it:

// Store the time when the game started as a property
var gameStartDate : NSDate?
// When the game actually begins, store the current date
self.gameStartDate = NSDate()

When you want to find out how much time has elapsed since the game started, create a second NSDate and use the timeIntervalSinceDate method to calculate the time:

let now = NSDate()
let timeSinceGameStart = now
    .timeIntervalSinceDate(self.gameStartDate!)
NSLog("The game started \(timeSinceGameStart) seconds ago")

Discussion

NSDate objects represent moments in time. They’re the go-to object for representing any instant of time that you want to be able to refer to again later, such as when your game starts. NSDate objects can refer to practically any date in the past or future and are very precise.

When you create an NSDate with the [NSDate date] method, you get back an NSDate object that refers to the current time (i.e., the instant when the NSDate object was created).

To determine the interval between two dates, you use timeIntervalSinceDate:. This method returns an NSTimeInterval, which is actually another term for a floating-point number. These values are represented in seconds, so it’s up to your code to do things like determine the number of hours and minutes:

let hours = timeSinceGameStart / 3600.0 // 3600 seconds in an hour
let minutes = timeSinceGameStart % 3600.0 / 60.0 // 60 seconds in a minute
let seconds = timeSinceGameStart % 60.0 // remaining seconds

NSLog("Time elapsed: \(hours):\(minutes):\(seconds)")

Working with Closures

Problem

You want to store some code in a variable for later execution.

Solution

Closures are ideal for this:

class GameObject {
    // define a type of closure that takes a single GameObject
    // as a parameter and returns nothing
    var onCollision : (GameObject -> Void)?
}

// Create two objects for this example
let car = GameObject()
let brickWall = GameObject()

// Provide code to run when the car hits any another object
car.onCollision = { (objectWeHit) in
    NSLog("Car collided with \(objectWeHit)")
}

// later, when a character collides:
car.onCollision?(brickWall) // note the ? - this means that
                            // the code will only run if onCollision
                            // is not nil

Discussion

Closures are a language feature in Swift that allow you to store chunks of code in variables, which can then be worked with like any other variable.

Here’s an example of a simple closure:

var multiplyNumber : Int -> Int  1

multiplyNumber = { (number) -> Int in  2

    return number * 2

}

multiplyNumber(2)  3
1

This is how you define a closure. In this case, the closure returns an Int, is named multiplyNumber, and accepts a single Int parameter.

2

Just like any other variable, once a closure is defined, it needs to be given a value. In this case, we’re providing a closure that takes an Int and returns an Int, just like the variable’s definition.

3

Calling a closure works just like calling any other function.

How closures work

So far, this just seems like a very roundabout way to call a function. However, the real power of closures comes from two facts:

  • Closures capture the state of any other variables their code references.
  • Closures are objects, just like everything else. They stay around until you need them. If you store a closure, you can call it however often you like.

This is extremely powerful, because it means that your game doesn’t need to carefully store values for later use; if a closure needs a value, it automatically keeps it.

You define a closure by describing the parameters it receives and the type of information it returns. To help protect against mistakes, you can also create a type alias for closures, which defines a specific type of closure. This allows you to declare variables with more easily understandable semantics:

typealias ErrorHandler = NSError -> Void

var myErrorHandler : ErrorHandler

myErrorHandler = { (theError) in
    // do work with theError
    NSLog("i SPILL my DRINK! \(theError)")
}

Closures and other objects

When a closure is created, the compiler looks at all of the variables that the closure is referencing. If a variable is a simple value, like an int or a float, that value is simply copied. However, if the variable is a Swift object, it can’t be copied because it could potentially be very large. Instead, the object is retained by the closure. When a closure is freed, any objects retained by the closure are released.

This means that if you have a closure that references another object, that closure will keep the other object around. This is usually what you want, because it would be annoying to have to remember to keep the variables referenced by closures in memory. However, sometimes that’s not what you want.

One example is when you want a closure to run in two seconds’ time that causes an enemy object to run an attack animation. However, between the time you schedule the closure and the time the closure runs, the enemy is removed from the game. If the closure has a strong reference to the enemy, the enemy isn’t actually removed from memory until the closure is scheduled to run, which could have unintended side effects.

To get around this problem, you use weak references. A weak reference is a reference that does not keep an object in memory; additionally, if the object that is being referred to is removed (because all owning references to it have gone away), the weak reference will automatically be set to nil. For more information on weak references, see The Swift Programming Language’s chapter on Automatic Reference Counting.

Writing a Method That Calls a Closure

Problem

You want to write a method that, after performing its work, calls a closure to indicate that the work is complete.

For example, you want to tell a character to start moving to a destination, and then run a closure when the character finishes moving.

Solution

To create a method that takes a closure as a parameter, you just do this:

func moveToPosition(position : CGPoint, completion: (Void->Void)?) {

    // Do the actual work of moving to the location, which
    // might take place over several frames

    // Call the completion handler, if it exists
    completion?()
}

let destination = CGPoint(x: 5, y: 3)

// Call the function and provide the closure as a parameter
moveToPosition(destination) {
    NSLog("Arrived!")
}

Discussion

Methods that take a closure as a parameter are useful for when you’re writing code that starts off a long-running process, and you want to run some code at the conclusion of that process but want to keep that conclusion code close to the original call itself.

Before closures were added to the Swift language, the usual technique was to write two methods: one where you started the long-running process, and one that would be called when the process completed. This separates the various parts of the code, which decreases the readability of your code; additionally, passing around variables between these two methods is more complicated (because you need to manually store them in a temporary variable at the start, and retrieve them at the end; with closures, you just use the variables without any additional work).

Note

If the last parameter that you pass to a function or method is a closure, you can place the closure outside the function call’s parentheses. It can look a little cleaner.

Working with Operation Queues

Problem

You want to put chunks of work in a queue, so that they’re run when the operating system has a moment to do them.

Solution

Use an NSOperationQueue to schedule closures to be run in the background without interfering with more time-critical tasks like rendering or accepting user input:

// Create a work queue to put tasks on
let concurrentQueue = NSOperationQueue()

// This queue can run 10 operations at the same time, at most
concurrentQueue.maxConcurrentOperationCount = 10

// Add some tasks
concurrentQueue.addOperationWithBlock {
    UploadHighScores()
}

concurrentQueue.addOperationWithBlock {
    SaveGame()
}

concurrentQueue.addOperationWithBlock {
    DownloadMaps()
}

Discussion

An operation queue is a tool for running chunks of work. Every application has an operation queue called the main queue. The main queue is the queue that normal application tasks (e.g., handling touches, redrawing the screen, etc.) are run on.

Note

Many tasks can only be run on the main queue, including updating anything run by UIKit. It’s also a good idea to only have a single operation queue that’s in charge of sending OpenGL instructions.

The main queue is a specific NSOperationQueue, which you can access using the mainQueue method:

let mainQueue = NSOperationQueue.mainQueue()

mainQueue.addOperationWithBlock { () -> Void in
    ProcessPlayerInput()
}

It’s often the case that you want to do something in the background (i.e., on another operation queue), and then alert the user when it’s finished. However, as we’ve already mentioned, you can only do UIKit or OpenGL tasks (e.g., displaying an alert box) on the main queue.

To address this, you can put tasks on the main queue from inside a background queue:

let backgroundQueue = NSOperationQueue()

backgroundQueue.addOperationWithBlock { () -> Void in

    // Do work in the background

    NSOperationQueue.mainQueue().addOperationWithBlock {

        // Once that's done, do work on the main queue

    }
}

An operation queue runs as many operations as it can simultaneously. The number of concurrent operations that can be run depends on several conditions, including the number of processor cores available and the different priorities that other operations may have.

By default, an operation queue determines the number of operations that it can run at the same time on its own. However, you can specify a maximum number of concurrent operations by using the maxConcurrentOperationCount property.

Performing a Task in the Future

Problem

You want to run some code, but you want it to happen a couple of seconds from now.

Solution

Use dispatch_after to schedule a closure of code to run in the future:

// Place a bomb, but make it explode in 10 seconds
PlaceBomb()

let delayTime : Float = 10.0

let dispatchTime = dispatch_time(DISPATCH_TIME_NOW,
    Int64(delayTime * Float(NSEC_PER_SEC)))

let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

dispatch_after(dispatchTime, queue) { () -> Void in
    // Time's up. Kaboom.
    ExplodeBomb()
}

Discussion

NSOperationQueue is actually a higher-level wrapper around the lower-level features provided by the C-based Grand Central Dispatch API. Grand Central Dispatch, or GCD, works mostly with objects called “dispatch queues,” which are basically NSOperationQueues. You do work with GCD by putting closures onto a queue, which runs the closures. Just as with NSOperationQueue, there can be many queues operating at the same time, and they can be serial or concurrent queues.

GCD provides a function called dispatch_after that runs a closure on an operation queue at a given time. To use the function, you first need to figure out the time when the closure should be run. GCD doesn’t actually work in seconds, or even in nanoseconds, but rather with time units called dispatch_time_t, which Apple’s documentation describes as “a somewhat abstract representation of time.”

To work with dispatch_time_t, you use the function dispatch_time, which takes two parameters: a base time and an amount of time to be added on top, measured in nanoseconds.

Once you specify a time for the closure to run, you need to get a reference to a GCD dispatch_queue. You can get background queues using dispatch_get_global_queue, but you can also get the main queue using dispatch_get_main_queue.

Finally, you instruct GCD to run the closure.

Making Operations Depend on Each Other

Problem

You want to run some operations, but they need to run only after certain other operations are done.

Solution

To make an operation wait for another operation to complete, store each individual operation in a variable, and then use the addDependency: method to indicate which operations need to complete before a given operation begins:

let firstOperation = NSBlockOperation { () -> Void in
    NSLog("First operation")
}

let secondOperation = NSBlockOperation { () -> Void in
    NSLog("Second operation")
}

let thirdOperation = NSBlockOperation { () -> Void in
    NSLog("Third operation")
}

// secondOperation will not run until firstOperation and
// thirdOperation have finished
secondOperation.addDependency(firstOperation)
secondOperation.addDependency(thirdOperation)

NSOperationQueue.mainQueue().addOperations([firstOperation,
    secondOperation, thirdOperation], waitUntilFinished: true)

Discussion

You can add an operation to another operation as a dependency. This is useful for cases where you want one closure to run only after one or more operations have completed.

To add a dependency to an operation, you use the addDependency: method. Doing this doesn’t run the operation, but just links the two together.

Once the operation dependencies have been set up, you can add the operations to the queue in any order that you like; operations will not run until all of their dependencies have finished running.

Filtering an Array with Closures

Problem

You have an array, and you want to filter it with your own custom logic.

Solution

Use the filtered method to create an array that only contains objects that meet certain conditions:

let array = ["One", "Two", "Three", "Four", "Five"]

NSLog("Original array: \(array)")

let filteredArray = filter(array) { (element) -> Bool in
    if element.rangeOfString("e") != nil {
        return true
    } else {
        return false
    }
}

NSLog("Filtered array: \(filteredArray)")

Discussion

The closure that you provide to the filtered method is called multiple times. Each time it’s called, it takes an item in the array as its single parameter, and returns true if that item should appear in the filtered array.

Loading New Assets During Gameplay

Problem

You want to load new resources without impacting the performance of the game.

Solution

For each resource that needs loading, run an operation that does the loading into memory, and do it in the background. Then run a subsequent operation when all of the loads have completed.

You can do this by scheduling load operations on a background queue, and also running an operation on the main queue that depends on all of the load operations. This means that all of your images will load in the background, and you’ll run code on the main queue when it’s complete:

let imagesToLoad = ["Image 1.jpg", "Image 2.jpg", "Image 3.jpg"]

let imageLoadingQueue = NSOperationQueue()

// We want the main queue to run at close to regular speed, so mark this
// background queue as running in the background

// (Note: this is actually the default value, but it's good to know about
// the qualityOfService property.)
imageLoadingQueue.qualityOfService = NSQualityOfService.Background

// Allow loading multiple images at once
imageLoadingQueue.maxConcurrentOperationCount = 10

// Create an operation that will run when all images are loaded - you may want
// to tweak this
let loadingComplete = NSBlockOperation { () -> Void in
    NSLog("Loading complete!")
}

// Create an array for storing our loading operations
var loadingOperations : [NSOperation] = []

// Add a load operation for each image

for imageName in imagesToLoad {
    let loadOperation = NSBlockOperation { () -> Void in

        NSLog("Loading \(imageName)")

    }

    loadingOperations.append(loadOperation)

    // Don't run the loading complete operation until
    // this load (and all other loads) are done
    loadingComplete.addDependency(loadOperation)
}

imageLoadingQueue.addOperations(loadingOperations, waitUntilFinished: false)
imageLoadingQueue.addOperation(loadingComplete)

Discussion

When you create an NSOperationQueue, you can control its quality of service. By default, operation queues you create have the background quality of service, which indicates to the operating system that it’s OK for higher-priority operations to take precedence. This is generally what you want for your asset loading routines, because it’s important that you keep your application responsive to user input.

Depending on how much memory the rest of your game takes, you can also use this technique to load assets while the user is busy doing something else. For example, once the user reaches the main menu, you could start loading the resources needed for actual gameplay while you wait for the user to tap the New Game button.

Adding Unit Tests to Your Game

Problem

You want to test different parts of your game’s code in isolation, so that you can ensure that each part is working.

Solution

You can write code that tests different parts of your app in isolation using unit tests. By default, all newly created projects come with an empty set of unit tests, in which you can add isolated testing functions.

Note

If you’re working with an existing project, you can create a new set of unit tests by choosing File→New→Target and creating a Cocoa Touch Unit Testing Bundle.

You’ll find your unit test files in a group whose name ends with Tests. For example, if your Xcode project is called MyAwesomeGame, your testing files will be in a group named MyAwesomeGameTests, and it will by default come with a file called MyAwesomeGameTests.swift.

When you want to add a test, open your test file (the .swift file) and add a method whose name begins with test:

func testDoingSomethingCool() {

        let object = SomeAwesomeObject()

        let succeeded = object.doSomethingCool()

        if succeeded == false {
                XCTFail("Failed to do something cool");
        }
}

When you want to run the tests, choose Product→Test or press Command-U. All of the methods in your testing classes that begin with test will be run, one after the other.

You can also add additional collections of tests, by creating a new test suite. You do this by choosing File→New→File and creating a new Swift test case class. When you create this new class, don’t forget to make it belong to your testing target instead of your game target, or you’ll get compile errors.

Discussion

Unit testing is the practice of writing small tests that test specific features of your code. In normal use, your code is used in a variety of ways, and if there’s a bug, it can be difficult to track down exactly why your code isn’t behaving the way you want it to. By using unit tests, you can run multiple tests of your code and check each time to see if the results are what you expect. If a test fails, the parts of your game that use your code in that particular way will also fail.

Each test is actually a method in a test case. Test cases are subclasses of XCTestCase whose names begin with test. The XCTestCase objects in a testing bundle make up a test suite, which is what’s run when you tell Xcode to test your application.

When tests run, Xcode performs the following tasks for each test method, in each test case, in each test suite:

  • Call the test case’s setUp method.
  • Call the test method itself, and note if the test succeeds or fails.
  • Call the test case’s tearDown method.
  • Show a report showing which tests failed.

As you can see, the test case’s setUp and tearDown methods are called for each test method. The idea behind this is that you use setUp to create whatever conditions you want to run your test under (e.g., if you’re testing the behavior of an AI, you could use setUp to load the level in which the AI needs to operate). Conversely, the tearDown method is used to dismantle whatever resources are set up in setUp. This means that each time a test method is run, it’s operating under the same conditions.

The contents of each test method are entirely up to you. Typically, you create objects that you want to test, run methods, and then check to see if the outcomes were what you expected. The actual way that you check the outcomes is through a collection of dedicated assertion methods, which flag the test as failing if the condition you pass in evaluates to false. The assertion methods also take a string parameter, which is shown to the user if the test fails.

For example:

// Fails if X is not nil
XCTAssertNil(X, "X should be nil")

// Fails if X IS nil
XCTAssertNotNil(X, "X should not be nil")

// Fails if X is not true
XCTAssertTrue(1 == 1, "1 really should be equal to 1")

// Fails if X is not false
XCTAssertFalse(2 != 3, "In this universe, 2 equals 3 apparently")

// Fails if X and Y are not equal (tested by calling X.equals(Y)])
XCTAssertEqualObjects((2), (1+1), "Objects should be equal")

// Fails if X and Y ARE equal (tested by calling X.equals(Y))
XCTAssertNotEqualObjects("One", "1", "Objects should not be equal")

// Fails, regardless of circumstances
XCTFail("Everything is broken")

There are several other assertion methods available for you to use that won’t fit in this book; for a comprehensive list, see the file XCTestAssertions.h (press Command-Shift-O, type XCTestAssertions, and then press Enter).

2D Grids

Problem

You want to store objects in a two-dimensional grid, as shown in Figure 1-3.

The grid. A digital frontier.
Figure 1-3. The grid: a digital frontier

Solution

Use a Grid class, which lets you store and look up objects.

Create an NSObject subclass called Grid, and put the following code in Grid.swift:

// A GridPoint is a structure that represents a location in the grid.
// This is Hashable, because it will be stored in a dictionary.
struct GridPoint : Hashable {
    var x: Int;
    var y: Int;

    // Returns a unique number that represents this location.
    var hashValue: Int {
        get {
            return x ^ (y << 32)
        }
    }


}

// If an object is Hashable, it's also Equatable. To conform
// to the requirements of the Equatable protocol, you need
// to implement the == operation (which returns true if two objects
// are the same, and false if they aren't)
func ==(first : GridPoint, second : GridPoint) -> Bool {
    return first.x == second.x && first.y == second.y
}

// Next: the grid itself
class Grid: NSObject {

    // The information is stored as a dictionary mapping
    // GridPoints to arrays of NSObjects
    var contents: [GridPoint: [NSObject]] = [:]

    // Returns the list of objects that occupy the given position
    func objectsAtPosition(position: GridPoint) -> [AnyObject] {

        // If we have a collection of objects at this position, return it
        if let objects = self.contents[position] {
            return objects
        } else {
            // Otherwise, create an empty collection
            self.contents[position] = []
            // And return it
            return []
        }

    }

    // Returns a GridPoint describing the position of an object, if it exists
    func positionForObject(objectToFind: NSObject) -> GridPoint? {

        for (position, objects) in contents {

            if find(objects, objectToFind) != nil {
                return position
            }

        }

        return nil

    }

    // Adds or moves the object to a location on the board
    func addObject(object: NSObject, atPosition position: GridPoint) {

        if self.contents[position] == nil {
            self.contents[position] = []
        }

        self.contents[position]?.append(object)

    }

    // Removes a given object from the board
    func removeObjectFromGrid(objectToRemove : NSObject) {

        var newContents = self.contents

        for (position, objects) in contents {
            newContents[position] = newContents[position]?.filter
            { (item) -> Bool in
                return item != objectToRemove
            }
        }
        self.contents = newContents
    }

    // Removes all objects at a given point from the board
    func removeAllObjectsAtPosition(position: GridPoint) {
        self.contents[position] = []
    }

    // Removes all objects from the board.
    func removeAllObjects() {
        self.contents = [:]
    }

}

Discussion

When working with 2D grids, you usually have two main tasks that you want to perform with it:

  • You have a game object on the board, and want to work out where on the board it is.
  • You have a location on the board, and you want to work out what object (or objects) are at that point on the board.

This Grid class doesn’t require that you limit the board to a predefined size.

This class implements grids by using a dictionary to map locations to arrays of objects. When you add a piece to the board, the class works out which array should contain the object (and creates one if necessary) and inserts it. Later, when you want to get the objects at a given location, it simply looks up the location in the dictionary.

Note

For small boards (for example, those with a size of about 14-by-14), you can get away with a simple implementation. However, this implementation will slow down when you start having larger boards (especially with many objects on the board). In those cases, you’d be better off creating multiple dictionaries for different areas of the board (for example, one for the upper-left corner, one for the top-right, and so on). This improves the lookup speed of getting objects at a location, though it complicates your implementation.

Get iOS Swift Game Development Cookbook, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.