Home Game Development iOS 9 Game Development Essentials

iOS 9 Game Development Essentials

By Chuck Gaffney
books-svg-icon Book
eBook $29.99 $20.98
Print $38.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $29.99 $20.98
Print $38.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    The Swift Programming Language
About this book
Publication date:
November 2015
Publisher
Packt
Pages
224
ISBN
9781784391430

 

Chapter 1. The Swift Programming Language

At the core of game development is your game's code. It is the brain of your project and outside of the art, sound, and various asset developments. It is where you will spend most of your time creating and testing your game. Up until Apple's Worldwide Developers Conference WWDC14 in June of 2014, the code of choice for iOS game and app development was Objective-C. At WWDC14, a new and faster programming language, Swift, was announced and is now the recommended language for all current and future iOS games and general app creation.

As of the time of writing, you can still use Objective-C to design your games, but programmers, both, new and seasoned, will see why writing in Swift is not only easier for expressing your game's logic, but even more preformat. Keeping your game running at that critical 60 fps is dependent on fast code and logic. Engineers at Apple developed the Swift programming language from the ground up with performance and readability in mind, so this language can execute certain code iterations faster than Objective-C while also keeping code ambiguity to a minimum. Swift also uses many of the methodologies and syntaxes found in more modern languages, such as Scala, JavaScript, Ruby, and Python.

So, let's dive into the Swift language.

Note

It is recommended that some basic knowledge of object-oriented programming (OOP) be known previously, but we will try to keep the build-up and explanation of code simple and easy to follow as we move on to the more advanced topics related to game development.

 

Hello World!


It's somewhat traditional when learning programming languages to begin with a Hello World example. A Hello World program is simply using your code to display or log the text Hello World. It's always been the general starting point because sometimes just getting your code environment set up and having your code executing correctly is half the battle. At least, this was more the case in older programming languages.

Swift makes this easier than ever, and without going into the structure of a Swift file (which we shall do later on and is also much easier than Objective-C and past languages), here's how you create a Hello World program:

print("Hello, World!")

That's it! That is all you need to have the text Hello World appear in Xcode's debug area output.

 

No more semicolons


Those of us who have been programming for some time might note that the usually all-important semicolon (;) is missing. This isn't a mistake; in Swift, we don't have to use a semicolon to mark the end of an expression. We can if we'd like, and some of us might still do it as a force of habit, but Swift has omitted that common concern.

Note

The use of the semicolon to mark the end of an expression stems from the earliest days of programming when code was written in simple word processors and needed a special character to represent when the code's expression ends and the next begins.

 

Variables, constants, and primitive data types


While programming any application, either if new to programming or trying to learn a different language, first we should get an understanding of how a language handles variables, constants, and various data types, such as Booleans, integers, floats, strings, and arrays. You can think of the data in your program as boxes or containers of information. Those containers can be of different flavors or types. Throughout the life of your game, the data can change (variables, objects, and so on) or they can stay the same.

For example, the number of lives a player has would be stored as a variable, as that is expected to change during the course of the game. That variable would then be of the primitive data type integer, which is basically whole numbers. Data that stores, say, the name of a certain weapon or power-up in your game, would be stored in what's known as a constant, as the name of that item is never going to change. In a game where the player can have interchangeable weapons or power-ups, the best way to represent the currently equipped item would be to use a variable. A variable is a piece of data that is bound to change. That weapon or power-up will also most likely have a bit more information to it than just a name or number; the primitive types we mentioned prior. The currently equipped item would be made up of properties, such as its name, power, effects, index number, and the sprite or 3D model that visually represents it. Thus, the currently equipped item wouldn't just be a variable of a primitive data type, but be what is known as a type of object. Objects in programming can hold a number of properties and functionalities that can be thought of as a black box of both function and information. The currently equipped item in our case would be a sort of placeholder that can hold an item of that type and interchange it when needed, fulfilling its purpose as a replaceable item.

Note

Swift is what's known as a type-safe language, so we should keep track of the exact type of data and even it's future usage (that is, if the data is or will be NULL), as it's very important when working with Swift compared with other languages. Apple made Swift behave this way to help keep runtime errors and bugs in your applications to a minimum, so we can find them much earlier in the development process.

Variables

Let's look at how variables are declared in Swift.

var lives = 3      //variable of representing the player's lives
lives = 1          //changes that variable to a value of 1

Those of us who have been developing in JavaScript will feel right at home here. Like JavaScript, we use the keyword var to represent a variable, and we named the variable lives.

The compiler implicitly knows that the type of this variable is a whole number, the primitive data type Int.

The type can be explicitly declared as such:

var lives: Int = 3    //variable of type Int

We can also represent lives as the floating point data types double or float, as follows:

// lives are represented here as 3.0 instead of 3
var lives: Double = 3           //of type Double
var lives: Float = 3            //of type Float

Using a colon after the variable's name declaration allows us to explicitly typecast the variable.

Constants

During your game, there will be points of data that don't change throughout the life of the game or the game's current level/scene. These can be various data, such as gravity, a text label in the Heads-Up Display (HUD), the center point of character's 2D animation, an event declaration, or the time before your game checks for new touches/swipes.

Declaring constants is almost the same as declaring variables.

Using a colon after the variable's name declaration allows us to explicitly typecast the variable.

let gravityImplicit  = -9.8         //implicit declaration
let gravityExplicit: Float  =  -9.8 //explicit declaration

As we can see, we use the keyword let to declare constants.

Here's another example using a string that could represent a message displayed on the screen at the start or end of a stage:

let stageMessage  = "Start!"
stageMessage      = "You Lose!"   //error

Since the string stageMessage is a constant, we cannot change it once it has been declared. Something like this would be better as a variable using var instead of let.

Tip

"Why don't we declare everything as a variable?"

This is a question sometimes asked by new developers and is understandable why it's asked, especially since game apps tend to have a large number of variables and more interchangeable states than an average application. When the compiler is building its internal list of your game's objects and data, more goes on behind the scenes with variables than with constants.

Without getting too much into topics, such as the program's stack and other details, in short, having objects, events, and data declared as constants with the let keyword is more efficient than var. In a small app on the newest devices today, though not recommended, we could possibly get away with this without seeing a great deal of loss in app performance. When it comes to video games, however, performance is critical. Buying back as much performance as possible can allow a better player experience. Apple recommends that when in doubt, always use let at the time of declaration and have the compiler say when to change to var.

More about constants…

As of Swift version 1.2, constants can have a conditionally controlled initial value.

Prior to this update, we had to initialize a constant with a single starting value or be forced to make the property a variable. In Xcode 6.3 and newer, we can perform the following logic:

let x : SomeThing

if condition
{
  x = foo()
}
else
{
  x = bar()
}
use(x)

An example of this in a game could be as follows:

let stageBoss : Boss

if (stageDifficulty == gameDifficulty.hard)
{
  stageBoss = Boss.toughBoss()
}
else
{
  stageBoss = Boss.normalBoss()
}
loadBoss(stageBoss)

With this functionality, a constant's initialization can have a layer of variance while still keeping it unchangeable, or immutable through its use. Here, the constant stageBoss can be one of two types based on the game's difficulty: Boss.toughBoss() or Boss.normalBoss(). The boss won't change for the course of this stage, so it makes sense to keep it as a constant. More on if and else statements is covered later in the chapter.

 

Arrays, matrices, sets, and dictionaries


Variables and constants can represent a collection of various properties and objects. The most common collection types are arrays, matrices, sets, and dictionaries. An array is an ordered list of distinct objects; a matrix is, in short, an array of arrays; a set is an unordered list of distinct objects; and a dictionary is an unordered list that utilizes a key : value association with the data.

Arrays

Here's an example of an array in Swift:

let stageNames : [String] = ["Downtown Tokyo","Heaven Valley","Nether"]

The object stageNames is a collection of strings representing the names of a game's stages. Arrays are ordered by subscripts from 0 to array length -1. So, stageNames[0] would be Downtown Tokyo; stageNames[2] would be Nether; and stageNames[4] would give an error since that's beyond the limits of the array and doesn't exist. We use [] brackets around the class type of stageNames, [String], to tell the compiler that we are dealing with an array of strings. Brackets are also used around the individual members of this array.

2D arrays / matrices

A common collection type used in physics calculations, graphics, and game design, particularly grid-based puzzle games, is two-dimensional arrays / matrices. 2D arrays are simply arrays that have arrays as their members. These arrays can be expressed in a rectangular fashion in rows and columns.

For example, the 4x4 (4 rows, 4 columns) tile board in the 15-puzzle game can be represented as follows:

var tileBoard = [[1,2,3,4],
                 [5,6,7,8],
                 [9,10,11,12],
                 [13,14,15,""]]

In the 15 puzzle game, your goal is to shift the tiles using the one empty spot (represented with the blank string ""), to all end up in the 1-15 order as we saw. The game would start with the numbers arranged in a random and solvable order, and the player would then have to swap the numbers and the blank space.

Tip

To better perform various actions on and/or store information about each tile in the 15 game (and other games), it'd be better to create a tile object as opposed to using raw values seen here. For the sake of understanding what a matrix or 2D array is, simply make a note of how the array is surrounded by doubly encapsulated brackets [[]]. We will later use one of our example games, SwiftSweeper, to better understand how puzzle games use 2D arrays of objects to create a full game.

Here are ways to declare blank 2D arrays with strict types:

var twoDTileArray : [[Tiles]] = []     //blank 2D array of type,Tiles
var anotherArray = Array<Array<Tile>>()  //same array, using Generics

The variable twoDTileArray uses the double brackets [[Tiles]] to declare it as a blank 2D array/matrix for the made-up type, tiles. The variable anotherArray is a rather oddly declared array that uses angle bracket characters <> for enclosures. It utilizes what's known as Generics. Generics is a rather advanced topic that we will touch more on later. They allow very flexible functionality among a wide array of data types and classes. For the moment, we can think of them as a catch-all way of working with objects.

To fill in the data for either version of this array, we would then use for-loops. More on loops and iterations will be explained later in the chapter.

Sets

This is how we would make a set of various game items in Swift:

var keyItems = Set([Dungeon_Prize, Holy_Armor, Boss_Key,"A"])

This set keyItems has various objects and a character A. Unlike an array, a set is not ordered and contains unique items. So, unlike stageNames, attempting to get keyItems[1] would return an error and items[1] might not necessarily be the Holy_Armor object, as the placement of objects is internally random in a set. The advantage sets have over arrays is that sets are great at checking for duplicated objects and specific content searching in the collection overall. Sets make use of hashing to pinpoint the item in the collections, so checking for items in a set's content can be much faster than in an array. In game development, a game's key items, which the player may only get once and should never have duplicates of, could work great as a set. Using the function keyItems.contains(Boss_Key) returns the Boolean value of true in this case.

Note

Sets were added in Swift 1.2 and Xcode 6.3. Their class is represented by the generic type Set<T>, where T is the class type of the collection. In other words, the set, Set([45, 66, 1233, 234]). would be of the type Set<Int>, and our example here would be a Set<NSObject> instance due to it having a collection of various data types.

We will discuss more on Generics and class hierarchy later in this chapter.

Dictionaries

A dictionary can be represented this way in Swift:

var playerInventory: [Int : String]  =  [1 : "Buster Sword",  43 : "Potion", 22: "StrengthBooster"]

Dictionaries use a key : value association, so playerInventory[22] returns the value StrengthBooster based on the key 22. Both the key and value could be initialized to almost any class type*. In addition to the inventory example given, we can have the following code:

var stageReward: [Int : GameItem] = [:] //blank initialization
//use of the Dictionary at the end of a current stage
stageReward = [currentStage.score : currentStage.rewardItem]

Note

*The values of a dictionary, though rather flexible in Swift, do have limitations. The key must conform to what's known as the hashable protocol. Basic data types, such as Int and String, already have this functionality. So, if you are to make your own classes / data structures that are to be used in dictionaries, say mapping a player actions with player input, this protocol must be utilized first. We will discuss more about protocols later in this chapter.

Dictionaries are like sets in that they are unordered but with the additional layer of having a key and a value associated with their content instead of just the hash key. Like sets, dictionaries are great for quick insertion and retrieval of specific data. In iOS apps and in web applications, dictionaries are used to parse and select items from JavaScript Object Notation (JSON) data.

In the realm of game development, dictionaries using JSON or via Apple's internal data class, NSUserDefaults, can be used to save and load game data, set up game configurations, or access specific members of a game's API.

For example, here's one way to save a player's high score in an iOS game using Swift:

let newBestScore : Void = NSUserDefaults.standardUserDefaults().setInteger(bestScore, forKey: "bestScore")

This code comes directly from a published Swift-developed game named PikiPop, which we will use from time to time to show code used in actual game applications.

Again, note that dictionaries are unordered, but Swift has ways to iterate or search through an entire dictionary. We will go more in depth in the next section and later on when we move on to loops and control flow.

 

Mutable/immutable collections


One rather important discussion that we've left out is how to subtract, edit, or add to arrays, sets, and dictionaries. However, before we do this, you should understand the concept of mutable and immutable data/collections.

A mutable collection is simple data that can be changed, added to, or subtracted from, whereas an immutable collection cannot be changed, added to, or subtracted from.

To work with mutable and immutable collections efficiently in Objective-C, we had to explicitly state the mutability of the collection beforehand. For example, an array of the type NSArray in Objective-C is always immutable. There are methods we can call on NSArray that would edit the collection, but behind the scenes, this would be creating brand new NSArray objects, thus would be rather inefficient to do this often in the life of our game. Objective-C has solved this issue with the class type, NSMutableArray.

Thanks to the flexibility of Swift's type inference, we already know how to make a collection mutable or immutable! The concept of constants and variables has us covered when it comes to data mutability in Swift. Using the keyword let when creating a collection will make that collection immutable, while using var will initialize it as a mutable collection.

//mutable Array
var unlockedLevels : [Int] =  [1, 2, 5, 8]

//immutable Dictionary
let playersForThisRound : [PlayerNumber:PlayerUserName] = [453:"userName3344xx5", 233:"princeTrunks", 6567: "noScopeMan98", 211: "egoDino"]

The array of integers, unlockedLevels, can be edited simply because it's a variable. The immutable dictionary playersForThisRound can't be changed since it's already been declared as a constant. There is no additional layer of ambiguity concerning additional class types.

Editing/accessing collection data

As long as a collection type is a variable, using the var keyword, we can do various edits to the data. Let's go back to our unlockedLevels array. Many games have the functionality of unlocking levels as the player progresses. Let's say that the player has reached the high score needed to unlock the previously locked level 3 (as 3 isn't a member of the array). We can add 3 to the array using the append function:

unlockedLevels.append(3)

Another neat attribute of Swift is that we can add data to an array using the += assignment operator:

unlockedLevels += [3]

Doing it this way however will simply add 3 to the end of the array. So, our previous array [1, 2, 5, 8] is now [1, 2, 5, 8, 3]. This probably isn't a desirable order, so to insert the number 3 in the third spot, unlockedLevels[2], we can use the following method:

unlockedLevels.insert(3, atIndex: 2)

Now, our array of unlocked levels is ordered to [1, 2, 3, 5, 8].

This is assuming though that we know a member of the array prior to 3 is sorted already. There are various sorting functionalities provided by Swift that could help keeping an array sorted. We will leave the details of sorting to our discussions of loops and control flow later in this chapter.

Removing items from an array is just simple. Let's again use our unlockedLevels array. Imagine that our game has an overworld for the player to travel to and from and the player has just unlocked a secret that triggered an event that blocked off access to level 1. Level 1 would now have to be removed from the unlocked levels. We can do it like this:

unlockedLevels.removeAtIndex(0) // array is now  [2, 3, 5, 8]

Alternately, imagine that the player has lost all of their lives and got a Game Over message. A penalty for this could be to lock the furthest level. Though probably a rather infuriating method and us knowing that level 8 is the furthest level in our array, we can remove it using the .removeLast() function of array types.

unlockedLevels.removeLast() // array is now [2,3,5]

Note

This is assuming that we know the exact order of the collection. Sets or dictionaries might be better at controlling certain aspects of your game.

Here are some ways to edit a set or a dictionary as a quick guide.

Set

inventory.insert("Power Ring")    //.insert() adds items to a set
inventory.remove("Magic Potion")  //.remove() removes a specific item
inventory.count                   //counts # of items in the Set
inventory.union(EnemyLoot)        //combines two Sets
inventory.removeAll()             //removes everything from the Set
inventory.isEmpty                 //returns true

Dictionary

var inventory = [Float : String]() //creates a mutable dictionary

/*
one way to set an equipped weapon in a game; where 1.0 could represent the first "item slot" that would be placeholder for the player's "current weapon"  
*/
inventory.updateValue("Broadsword", forKey: 1.0)


//removes an item from a Dictionary based on the key value
inventory.removeValueForKey("StatusBooster")

inventory.count                   //counts items in the Dictionary
inventory.removeAll(keepCapacity: false) //deletes the Dictionary
inventory.isEmpty                 //returns false

//creates an array of the Dictionary's values
let inventoryNames = [String](inventory.values)

//creates an array of the Dictionary's keys
let inventoryKeys = [String](inventory.keys)

Iterating through collection types

We can't discuss collection types without mentioning how to iterate through them en masse.

Here's some way we'd iterate though an array, a set, or a dictionary in Swift:

//(a) outputs every item through the entire collection
  //works for Arrays, Sets and Dictionaries but output will vary
for item in inventory {
    print(item)
}

//(b) outputs sorted item list using Swift's sorted() function
  //works for Sets
for item in sorted(inventory) {
    print("\(item)")
}

//(c) outputs every item as well as its current index
  //works for Arrays, Sets and Dictionaries
for (index, value) in enumerate(inventory) {
    print("Item \(index + 1): \(value)")
}

//(d)
//Iterate through and through the keys of a Dictionary
for itemCode in inventory.keys {
    print("Item code: \(itemCode)")
}

//(e)
//Iterate through and through the values of a Dictionary
for itemName in inventory.values {
    print("Item name: \(itemName)")
}

As stated previously, this is done with what's known as a for-loop; with these examples, we show how Swift utilizes the for-in variation using the in keyword. The code will repeat until it reaches the end of the collection in all of these examples. In example (c), we also see the use of the Swift function, enumerate(). This function returns a compound value, (index,value), for each item. This compound value is known as a tuple, and Swift's use of tuples makes for a wide variety of functionalities for functions, loops, as well as code blocks.

We will delve more into tuples, loops, and blocks later on.

 

Objective-C and Swift comparison


Here's a quick review of our Swift code with a comparison to the Objective-C equivalent.

Objective-C

Here's a sample code in Objective-C:

const int MAX_ENEMIES = 10;  //constant
float playerPower = 1.3;     //variable

//Array of NSStrings
NSArray * stageNames = @[@"Downtown Tokyo", @"Heaven Valley", @" Nether"];

//Set of various NSObjects
NSSet *items = [NSSet setWithObjects: Weapons, Armor,
 HealingItems,"A", nil];

//Dictionary with an Int:String key:value
NSDictionary *inventory = [NSDictionary dictionaryWithObjectsAndKeys:
             [NSNumber numberWithInt:1], @"Buster Sword",
             [NSNumber numberWithInt:43], @"Potion",
             [NSNumber numberWithInt:22], @"Strength",
nil];

Swift

Here's the equivalent code in Swift:

let MAX_ENEMIES = 10          //constant
var playerPower = 1.3         //variable

//Array of Strings
let stageNames : [String] = ["Downtown Tokyo","Heaven Valley","Nether"]    

//Set of various NSObjects
var items = Set([Weapons, Armor, HealingItems,"A"])
          
//Dictionary with an Int:String key:value
var playerInventory: [Int : String]  =  [1 : "Buster Sword",  43 : "Potion", 22: "StrengthBooster"]

In the preceding code, we used some examples of variables, constants, arrays, sets, and dictionaries. First, we see their Objective-C syntax and then the equivalent declarations using Swift's syntax. From this example, we can see how compact Swift is compared with Objective-C.

 

Characters and strings


For some time in this chapter, we've been mentioning strings. Strings are also a collection of data types, but a specially dealt collection of characters, of the class type, string. Swift is Unicode-compliant, so we can have strings like the following:

let gameOverText =  "Game Over!"

We can have strings with emoji characters like the following:

let cardSuits =  "♠ ♥ ♣ ♦"

What we did in the preceding code was create what's known as a string literal. A string literal is when we explicitly define a string around two quotes "".

We can create empty string variables for later use in our games such as:

var emptyString = ""               // empty string literal
var anotherEmptyString = String()  // using type initializer

Both are valid ways to create an empty string "".

String Interpolation

We can also create a string from a mixture of other data types, known as String Interpolation. String Interpolation is rather common in game development, debugging, and string use in general.

The most notable of examples are displaying the player's score and lives. This is how one of our example games, PikiPop, uses String Interpolation to display the current player stats:

//displays the player's current lives
var livesLabel = "x \(currentScene.player!.lives)"

//displays the player's current score
var scoreText = "Score: \(score)"

Take note of the \(variable_name) formatting. We've actually seen this before in our past code snippets. In the various print() outputs, we used this to display the variable, collection, and so on we wanted to get information on. In Swift, the way to output the value of a data type in a string is by using this formatting.

For those of us who came from Objective-C, it's the same as the following:

NSString *livesLabel = @"Lives: ";
int lives = 3;
NSString *livesText = [NSString stringWithFormat:@" %@ (%d days ago)", livesLabel, lives];

Note how Swift makes String Interpolation much cleaner and easier to read than its Objective-C predecessor.

Mutating strings

There are various ways to change strings, such as adding characters to a string as we did to collection objects. Here are some basic examples:

var gameText = "The player enters the stage"
gameText += " and quickly lost due to not leveling up"
/* gameText now says
"The player enters the stage and lost due to not leveling up" */

Since strings are essentially arrays of characters, like arrays, we can use the += assignment operator to add to the previous string.

Also, akin to arrays, we can use the append() function to add a character to the end of a string.

 let exclamationMark: Character = "!"
gameText.append(exclamationMark)
//gameText now says "The player enters the stage and lost due to not leveling up!"

Here's how we iterate through the characters in a string, in Swift:

for character in "Start!" {
    print(character)
}
//outputs:
//S
//t
//a
//r
//t
//!

Note how again we use the for-in loop and even have the flexibility of using a string literal if we'd so like to be what's iterated through by the loop.

String indices

Another similarity between arrays and strings is the fact that a string's individual characters can be located via indices. Unlike arrays, however, since a character can be a varying size of data, broken in 21-bit numbers known as Unicode scalars, they can not be located in Swift with Int type index values.

Instead, we can use the .startIndex and .endIndex properties of a string and move one place ahead or one place behind the index with the .successor() and .predecessor() functions, respectively, to retrieve the needed character or characters of a string.

Here are some examples that use these properties and functions using our previous gameText string:

gameText[gameText.startIndex]              // = T
gameText[gameText.endIndex]                // = !
gameText[gameText.startIndex.successor()]  // = h
gameText[gameText.endIndex.predecessor()]  // = p

Note

There are many ways to manipulate, mix, remove, and retrieve various aspects of strings and characters. For more information, be sure to check out the official Swift documentation on characters and strings at https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/StringsAndCharacters.html.

 

Commenting in Swift


In our code snippets thus far, one might note notations with double forward slashes // or with forward slashes and asterisks /* */. These are how we can comment or make notations in our Swift code. Anyone who's coded in C++, Java, Objective-C, JavaScript, or other languages will see that Swift works practically the same.

Single-line comments are started with the double forward slashes, //, while multiline comments or a comment block begins with /* and ends with */.

Take the following example:

//This is a single line comment
/*
This is a comment block
that won't end until it reaches the closing asterisk/forward slash characters
 */

Commenting is used to help navigate your code, understand what it might do, and comment out lines of code we might not want to execute, but at the same time want to keep for later (that is, print() log calls or alternative starting property values).

Note

From Xcode 6 Beta 4 onward, we can also utilize the following comments:

// MARK:, // TODO:, and // FIXME. //MARK is equivalent to Objective-C's #pragma mark, which allows the programmer to label a section of your code that is accessible in Xcode's top breadcrumb dropdown list. // TODO: and // FIXME give us the ability to section off parts of code that we wish to maybe add features to in the future or debug. Even games with well-organized class structuring can be daunting to sift through. The addition of these additional mark-up tools makes planning and searching through our games' code that much easier to do.

 

Boolean


An integral part of all programming, game, or otherwise is the use of Boolean values. Boolean values typically return either true or false values, yes or no, or 0 or 1. In Swift, this is the job of the Bool class of objects. The use of the function .isEmpty() in our past collection data type examples returns a Boolean value of true or false based on whether that collection is empty or not.

In game development, one way we could use Boolean values is to have a global variable (a variable accessible in scope throughout our game/app) that checks if the game is over.

var isGameOver = false

This variable, taken from the PikiPop game, starts the game off with a variable of type bool named isGameOver with a starting value of false. If the events of the game cause this value to change to true, then this triggers the events associated with the game over state.

Note

Unlike Boolean values in Objective-C, Swift uses only true or false values to represent Boolean variables. Swift strict type safety does not allow the use of YES and NO or 0 and 1, as we have seen in Objective-C and other programming languages.

However, reading and controlling this type of information about our game, known as the game's state, is best controlled with more than just a single Boolean value. This is because your game and the characters in your game could have various states, such as game over, paused, spawn, idle, running, falling, and more. A special object known as a state machine best manages this type of information. State machines shall be covered in more detail when we discuss the GameplayKit framework.

 

Ints, UInts, floats, and doubles


In addition to Boolean values, another basic data type we have up to this point briefly mentioned is the various numeric objects, such as integers (Ints), unsigned integers (UInts), floating point numbers / decimals (floats), and double precision floating point numbers / decimals (doubles).

Integers and unsigned integers

Integers represent negative and positive whole numbers, while unsigned integers represent positive whole numbers. Like with C and other programming languages, Swift lets us create various types of integers and unsigned integers from 8, 16, 32, and 64 bits. For example, an Int32 type is a 32-bit integer, while a UInt8 type is an 8-bit unsigned integer. The size of the bits for Ints and UInts represents how much space is being allocated to store the values. Using our UInt8 example, a number made from this type of unsigned Int can only store the values 0-255 (or 11111111 in a base-2 system). This is also known as 1 byte (8 bits). If we need to store numbers larger than 255 or negative numbers, then maybe an Int16 type would suffice as that can store numbers between –32767 and 32767. Usually, we don't have to worry too much about the size allocated by our integer variables and constants. So, using just the class name of Int will work fine in most cases.

Note

The size of Int will differ depending on the type of system we are working on. If we are compiling our code on a 32-bit system, an integer will be equal to Int32, while the same integer would be an Int64 on a 64-bit system.

Swift can let us see what our minimum and maximum values are for an Int variable with the .min or .max class variables (that is, Int16.max = 32767 and UInt.min = 0).

Floats and doubles

Floats are 32bit floating point numbers / fractions, such as pi (3.14), or the golden ratio, phi (1.61803).

In game designing, we work with floating point values and ranges rather often, be it to determine the CGPoint in x and y of a 2D sprite, using linear interpolation for smoothing a game's camera movement in 3D space, or applying various physics forces on an object or 2D/3D vector. The precision needed for each situation will determine if a float is needed or if the 64-bit floating point value, the double is needed. Doubles can be as precise as 15 decimal places, while a float is six decimal places precise.

Tip

It's actually best practice to use doubles in situations that would work for either floats or doubles.

 

Objects in Swift


The core aspect of object-oriented programming (OOP) is of course the concept of objects. C++ began this paradigm in programming, while Java, C#, Apple's Objective-C, and other languages were all essentially built from this foundation.

Swift is an OOP language with the same dynamic object model as Objective-C, but presented in a cleaner, type-safe, and compact way.

You can think of an object exactly as it sounds, an abstract thing or container. An object can be something as simple as a string, or something as complex as the player object in the latest video game. Technically speaking, an object in a program is a reference to a set of various data in an allocated chunk of memory, but it's sufficient to just understand that an object can be a variable or a reference to an instance of a class, Struct, or block of code.

An object can have various data fields/aspects associated with it, such as properties, functions, parent objects, child objects, and protocols. In languages such as C for example, an integer variable is usually represented as just raw data, but the integer type in Swift is actually an object. Thus, we can access extra information and perform functions on Int objects in our code. We previously saw this with the Int.max variable, which returns the highest number that can be represented by the Int class. Again, depending on the machine you are working on, this could be the same value as Int32.max or Int64.max.

var highestIntNumber : Int = Int.max

Access to functions and properties of an object uses dot notation, as we saw with the previous example. Int.max and Int.min are actually special properties known as class variables, which represent all instances of an Int type object.

Let's look at how Swift deals with obtaining properties and functions of an instance of an object using a made-up Player type object.

let currentPlayer = Player(name:"Fumi")       //(a)
let playerName = currentPlayer.getName()      //(b)
var playerHealth = currentPlayer.health       //(c)
currentPlayer.attackEnemy()                   //(d)

We'll get back to the second half of line (a), but just understand that it creates an instance of an object of the type Player named currentPlayer. Line (c) creates a variable named playerHealth that's set by the health property of currentPlayer; here with the dot notation. Lines (b) and (d) use the dot notation to call the functions getName() and attackEnemy(). The getName() function in this case is a function that returns a string that's assigned to the constant, playerName. Line (c) creates a variable named playerHealth that is created by referencing the health property of currentPlayer, also using dot notation. Line (d) is a direct call to the Player class' attackEnemy() function, which you can imagine for now just performs what would make currentPlayer do her attack. This function doesn't return a value and thus is what's known as a void type function.

As for line (a), one might note that it doesn't use the dot notation. This is how Swift does what's known as a class initializer; designated by the parenthesis () after the class name and with the parameter called name: that sends a string, Fumi, to the object's class initializer.

We will be diving deeper in to the use of objects momentarily as we move on to functions and classes.

Type safety and type inference

Objects and, as we'll see, functions on these objects in Swift are type-safe. What this means is that if we perform a function on a string object when the code was expecting an integer, then the compiler will warn us early on in the process. In the vein of game design, if we were to have the player perform an action only an enemy supposed to do, then Swift will know through its inherently type-safe nature.

Swift's type inference is something we've mentioned before. Unlike other languages where you have to declare the object's type every time it's initialized, Swift will infer what type you mean. For example, we have the following:

var playerHealth = 100
//Swift automatically infers that playerHealth is an Int object
 

Optionals


As we stated before, Swift is a type-safe language. Apple also created Swift with the intention of keeping as many potential errors and bugs in the compilation state of development as opposed to runtime. Though Xcode has some great debugging tools, from the use of breaks, logging, and the LLDB debugger, runtime errors, particularly in games can be tough to spot, thus bringing the development process to a halt. To keep everything type-safe and as bug-free as possible during compilation, Swift deals with the concept of optionals.

Optionals, in short, are objects that potentially can be or start as nil. Nil, of course, is an object that has no reference.

In Objective-C, we could declare the following string variable for a game:

NSString *playerStatus = @"Poisoned";
playerStatus = nil;

In Swift, we would write this in the same way, but we'd find out very quickly that Xcode would give us a compiler error in doing so:

var playerStatus = "Poisoned"
playerStatus = nil      //error!

Even more confusing for anyone new to Swift, we'd also get an error if we did something as simple as this:

var playerStatus : String   //error

Creating empty/undeclared objects in our games makes sense and is something we'd often want to do at the start of our classes. We want that flexibility to assign a value later on based on the events of our game. Swift seems to be making such a basic concept impossible to do! No worries; Xcode will inform you in most cases to suffix a question mark, ?, at the end of these nil objects. This is how you declare an object as an optional.

So, if we want to plan our game's properties and objects in Swift, we can do the following:

var playerStatus : String?  //optional String
var stageBoss : Boss?       //optional Boss object

Unwrapping optionals

Let's imagine that we want to display what caused a player to lose in the game.

var causedGameOver:String? = whatKilledPlayer(enemy.recentAttack)
let text = "Player Lost Because: "
let gameOverMessage = text + causedGameOver  //error

Because the string causedGameOver is optional, Xcode will give us a compile error because we didn't unwrap the optional. To unwrap the value in an optional, we suffix an exclamation point ! at the end of the optional.

Here's our Game Over message code, now fixed using the unwrapped optional:

var causedGameOver:String? = whatKilledPlayer(enemy.recentAttack)
let text = "Player Lost Because: "
let gameOverMessage = text + causedGameOver!  //code now compiles!

We can also force unwrap optionals early at declaration to allow any potential errors to be taken care of at runtime instead of when compiling. This happens often with @IBOutlets and @IBActions (objects and functions linked to various storyboards and other tools that are based on menu/view tools).

@IBOutlet var titleLabel: UILabel!      //label from a Storyboard
var someUnwrappedOptional : GameObject! //our own unwrapped optional

Note

If possible, though it's recommended to use the basic wrapped optional ? as much as possible to allow the compiler to find any potential errors. Using what's known as optional binding and chaining, we can do some great early logic checks on optionals that in prior languages would have involved various if statements / control flow statements to simply check for nil objects.

Keeping code clean, safe, and easy to read is what Swift aims to do and why Swift goes out of its way sometimes to force many of these rules with optionals.

Optional binding and chaining

Optional binding is checking whether an optional has a value or not. This is done using the very handy if-let or if-var statements. Let's look back at our earlier code:

var causedGameOver:String? = whatKilledPlayer(enemy.recentAttack)
let text = "Player Lost Because: "
if let gotCauseOfDeath = causedGameOver {
    let gameOverMessage = text + gotCauseOfDeath
}

The code block, if let gotCauseOfDeath = causedGameOver{…}, does two things. First, using the key words, if let, it automatically creates a constant named gotCauseOfDeath and then binds it to the optional causedGameOver. This simultaneously checks whether causedGameOver is nil or has a value. If it's not nil, then the if statement's code block will run; in this case, creating the constant gameOverMessage that combines the text constant with gotCauseOfDeath.

We can use if-var to simplify this even further:

let text = "Player Lost Because: "
if var causedGameOver = whatKilledPlayer(enemy.recentAttack) {
    let message = text + causedGameOver
}

The if-var statement creates a temporary variable using our previously used optional causedGameOver and does a Boolean logic check based on the result of whatKilledPlayer(enemy.recentAttack). The statement is true if there's a non-nil value returned. Note how we don't have to use either wrapped (?) or forced unwrapping (!) of the optional in such a case.

Optional chaining is when we query down into the properties of an object using the dot operator while also doing a nil/value check as we did with optional binding. For example, let's say that we have a game where certain Enemy types can cause a player to lose instantly via an Enemy instance named currentEnemy. In this example, currentEnemy.type would be a string that returns the name of the kind of enemy that hit the player. Optional chaining uses the custom dot modifier ?. while accessing a potentially nil check on a property. Here's the code to get a better idea of how this works:

if let enemyType = currentEnemy?.type {
    if enemyType == "OneHitKill"
    {
      player.loseLife()  //run the player's lost l
    }
}

Chances are that we'd probably not make an enemy without a designated type, but for the sake of understanding optional chaining, observe how this checks for the possible nil object that'd be returned by currentEnemy.type using currentEnemy?.type. Like how the dot operator functions where you can drill down the properties and properties of properties, the same can be done with the recurring ?.per property that is drilled down. In this code, we do a Boolean comparison with == to see if enemyType is the string OneHitKill.

Don't worry if the syntax of the if statement syntax is a bit of a mystery; next, we discuss how Swift uses if statements, loops, and other ways we can control various object data and their functions.

Control flow in Swift

Control flow in any program is simply the order of instructions and logic in your code. Swift, like any other programming language, uses various statements and blocks of code to loop, change, and/or iterate through your objects and data. This includes blocks of code such as if statements, for-loops, do-while loops and Switch statements. These are contained within functions, which make up larger structures like classes.

If statements

Before we move on to how Swift handles one of the main topics of OOP, functions and classes, let's quickly run through if-else statements. An if statement checks whether a Boolean statement is true or false. We have the example as follows:

if player.health <= 0{
   gameOver()
}

This checks whether or not the player's health is less than or equal to 0, designated by the <= operator. Note that Swift is OK with there not being parenthesis, but we can use this if we wish or if the statement gets more complicated, as in this example:

if (player.health <=0) && (player.lives <=0){ //&& = "and"
   gameOver()
}

Here, we check not just whether the player has lost all of their health, but also if all of their lives are gone with the and (&&) operator. In Swift, like in other languages, we separate out the individual Boolean checks with parentheses, and like other languages, we do a logic-or check with two bar keys (||).

Here are some more ways to write if statements in Swift with the added key words, else-if and else, as well as how Swift can check if-not a certain statement:

//(a)
if !didPlayerWin { stageLost() }

//(b)
if didPlayerWin
{            
   stageWon()
}
else
{
  stageLost()
}

//(c)
if (enemy == Enemy.angelType){enemy.aura = angelEffects}
else if(enemy == Enemy.demonType){enemy.aura = demonEffects}
else{ enemy.aura = normalEffects }

//(d)
if let onlinePlayerID = onlineConnection()?.packetID?.playerID
{
  print("Connected PlayerID: /(onlinePlayerID)"
}

//(e)
if let attack = player.attackType, power = player.power where power != 0 {
    hitEnemy(attack, power)
}

//(f)
let playerPower = basePower + (isPoweredUp ? 250 : 50)

Let's look at what we put in the code:

  • (a): This checks the not / reverse of a statement with the exclamation point, !, via !statement.

  • (b): This checks whether the player has won or not. Otherwise, the stageLost() function is called, using the key word else.

  • (c): This checks if an enemy is an angel and sets its aura effect accordingly. If this is not, then it will check if it's a demon using else-if, and if that's not the case, then we catch all other instances with the else statement. We could have a number of else-if statements one after another, but if we start to stack too many, then using for-loops and Switch statements would be a better approach.

  • (d): Using optional chaining, we create an onlineID constant based on if; we are able to get a non-nil playerID property using if-let.

  • (e): This uses if-let, where optional binding became a feature in Swift 1.2. Instead of having nested if-lets and other logic checks, akin to how SQL queries are done in backend web development, we can create very compact, powerful early logic checking. In the case of example (e), we have an enemy receive an attack based on what type of attack it is and the power of the player.

  • (f): This is an example of combining the creation of a constant with the keyword let and doing a shorthand version of an if statement. We shorthen an if statement in Swift with the question mark ? and colon :. Here is the format for short handing an if statement: bool ? trueResult : falseResult. If isPoweredUp is true, then playerPower will equal basepower + 250; if false, then it's basepower + 50.

For loops

We touched on for-in loops before dealing with collections. Here again is a for-in loop in Swift that will iterate through a collection object:

for itemName in inventory.values {
    print("Item name: \(itemName)")
}

For some of us programmers who are used to the older way of using for-loops, don't worry, Swift lets us write for-loops in the C-style, which many of us are probably used to:

for var index = 0; index < 3; ++index {
    print("index is \(index)")  
}

Here's another way of using a for-loop without using an index variable, noted with the underscore character _ but of course using a Range<Int> object type to determine how many times the for-loop iterates:

let limit = 10
var someNumber = 1
for _ in 1...limit {
    someNumber *= 2
}

Note the between the 1 and limit. This means that this for-in loop will iterate from 1-10. If we wanted it to iterate from 0 to limit-1 (similar to iterating between the bounds of an array's index), we could have instead typed 0..<limit where limit is equal to the array's .count property.

Do-while loops

Another very common iteration loop in programming is the do-while loop. Many times we can just utilize the while portion of this logic, so let's look into how and why we might use a while loop:

let score = player.score
var scoreCountNum = 0
while scoreCountNum < score {
    HUD.scoreText = String(scoreCountNum)
    scoreCountNum = scoreCountNum * 2
}

In game development, one use of the while loop (though executed differently in a game app, this accommodates iterating once per frame) is for displaying the counting up of a player's score from 0 to the score the player reached—a common esthetic of many games at the end of a stage. This while loop will iterate until it reaches the player's score, displaying on HUD object showing the intermediate values up until that score.

A do-while loop is practically the same as the while-loop with the extra caveat of iterating through the code block at least once. The end-stage score count example can also illustrate why we would need such a loop. For example, let's imagine that the player did really bad and got no score when the stage ended. In the while loop given, a score of zero won't let us enter the block of code in the while loop since it doesn't fulfill the logic check of scoreCountNum < score. In the while loop, we also have code that displays the score text. Though maybe embarrassing to the player, we would want to count up to the score and more importantly, still display a score. Here's the same code done with a do-while loop:

let score = player.score
var scoreCountNum = 0
do {
    HUD.scoreText = String(scoreCountNum)
    scoreCountNum = scoreCountNum * 2
} while scoreCountNum < score

Now score text will display even if the player scored nothing.

Switch statements

Switch statements are useful when we wish to check many different conditions of an object in a fully encompassing and neat way without having a wall of else-if statements. Here's a code snippet from the game PikiPop that uses a Switch statement from the game, PikiPop, that sets the percentage a GameCenter achievement (in this case, a 6x combo) based on the number of times the combo was achieved by the player. Don't worry too much about the GameCenter code (used with the GCHelper singleton object); that's something we will go over in future chapters when we make games in SpriteKit and SceneKit.

switch (comboX6_counter) {
                
            case 2:
                GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6", percent: 25)
                break

            case 5:
                GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6", percent: 50)
                break
                
            case 10:
                GCHelper.sharedInstance.reportAchievementIdentifier("Piki_ComboX6", percent: 100)
                
            default:
                break
                
        }

The switch statement here takes the variable used to count how many times the player hit a 6X combo, comboX6_counter, and performs different tasks based on the value of comboX6_counter. For example, when the player has done a 6X Combo twice, the Piki_ComboX6 achievement gets 25% fulfilled. The player gets the achievement (when at 100%) when the counter hits 10. The purpose of the keyword break is to tell the loop to exit at that point; otherwise, the next case block will iterate. Sometimes, this might be desired by your game's logic, but keep in mind that Swift, like many other languages, will continue through the switch statement without break. The keyword default is the catch-all block and is called when the value of the item checked by the switch statement is anything but the various cases. It can be thought of as an equivalent to the else{} block, while all of the cases are similar to else if(){}. The difference though is that Swift requires all cases of the switch be handled. So, though we can suffice with an if without an else, we have to have a default case for a switch statement. Again, this is done to keep Swift code safe and clean earlier in the coding process.

Functions and classes

Up until this point, we have kept from discussing probably the most important aspects of Swift or any OOP languages for that matter—how the language handles functions on objects and how it organizes these objects, object properties, and functions and performs various object-oriented design concepts, such as polymorphism and inheritance with classes, Structs, enums, protocols, and other data structures. There is much more to discuss about how Swift utilizes these concepts, more than we can fit in this chapter but throughout the course of this book, especially as we get into how to use Apple's game-centric SpriteKit and SceneKit frameworks, we will flesh out more on these topics.

Functions

In Objective-C, functions are written the following way:

-(int) getPlayerHealth() {
    return player.health;
}

This is a simple function that returns the player's health as an integer—the Int equivalent in Objective-C.

The structure of the function/method is as follows in Objective-C:

- (return_type) method_name:( argumentType1 )argumentName1
joiningArgument2:( argumentType2 )argumentName2 ...
joiningArgumentN:( argumentTypeN )argumentNameN
{
  function body
}

Here's the same function in Swift:

func getPlayerHealth() -> Int {
    return player.health
}
//How we'd use the function
var currentHealth : Int = 0
currentHealth = getPlayerHealth()

This is how a function is structured in Swift:

func function_name(argumentName1 : argumentType1, argumentName2 : argumentType2, argumentNameN : argumentTypeN) -> return_type
{
  function body
}

Note how we use the keyword func to create a function and how the argument/parameter names are first with the types second, separated by the colon (:) and within parenthesis.

Here's what a typical void function looks like in Swift. A void-type function is a function that doesn't return a value.

//with a Player type as a parameter
func displayPlayerName (player:Player){
     print(player.name)
}

//without any parameters; using a class property
func displayPlayerName(){
     print(currentPlayer.name)
}

In a void function, there's no need to write ->returnType, but even if there are no parameters, we do have to put in the () parenthesis at the end of the function name.

 

Tuples


A rather powerful aspect of Swift is that function return types (and constants/variables) can include a combination of values into a single value. These combinations are called tuples. Here's an example of an unnamed tuple:

let http503Error = (503, "Service Unavailable")

Here's a tuple used as a return type in a function direct from Apple's Swift documentation. Observe how it uses much of what we've learned thus far:

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var currentMin = array[0]
    var currentMax = array[0]
    for value in array[1..<array.count] {
        if value < currentMin {
            currentMin = value
        } else if value > currentMax {
            currentMax = value
        }
    }
    return (currentMin, currentMax)
}
Excerpt From: Apple Inc. "IOS Developer Library". https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html#//apple_ref/doc/uid/TP40014097-CH10-ID164

Classes

In OOP, classes make up the basic frame of an object, its functionality and interactions with other classes, objects, and various data structures, such as protocols, Structs, extensions, generics, and enumerations. In the following chapters, as we begin to structure our games, we will dive deeper into all of these concepts, but for now, let's understand the basics of classes and how they differ in Swift from Objective-C and other languages.

Here's the basic structure of a class in Swift:

//(a)
Global-project wide properties/variables
//(b)
class className : parentClassName, protocolName…protocolnName
{
//(c)
  class scope properties
//(d)
initializers (init(), convenience, required, etc)

//(e)
  func function_name1(argumentName1 : argumentType1, argumentName2 :    argumentType2, argumentNameN : argumentTypeN) -> return_type
 {
   function-scope variables and body
 }
                         .
                         .
                         .
  func function_nameN(argumentName1 : argumentType1, argumentName2 :    argumentType2, argumentNameN : argumentTypeN) -> return_type
 {
   function-scope variables and body
 }
//(f)
deinit()

} // end of the class
//(g)
global-project wide properties/variables (alternative position)

The Swift class structure works somewhat similar to what we see in C# and Java, as opposed to Objective-C's two files' (.h/header, .m/.mm/ implementation) setup:

  • (a): We can have properties (like variables, constants, Structs, and enums) outside of the class declaration, which would make them global in scope, aka accessible throughout the entire project/game/app.

  • (b): This is the actual class represented by what we named our .swift file. Again, this is different from Objective-C's classname.h - classname.m/.mm dual file setup for a single class. A class can be a child class of another class. We don't have to declare a parent/base class in Swift. Classes we make can be their own base classes. We can make classes as Objective-C classes by subclassing them from NSObject. The benefit of that is getting Objective-C runtime metadata and capabilities, but we take a hit in performance from the extra baggage. Either in the same place as the parentClass or after the colon : of parentClass, we can declare which protocols this class will adhere to. We'll discuss more on protocols later in the book, but just think of them as making sure your class utilizes the same functions as the protocol dictates.

  • (c): These are where we'd place variables, constants, Structs, enums, and objects that are relevant for use in the scope of the class.

  • (d): Initializers are special functions we use to set up the properties in section (c) when other classes and data structures use instances of the class via className(initializer parameters). We will discuss more on initializers more in the next chapter as we structure our games. They don't have to be at the top of the class, but it's a good practice to do so.

  • (e): These are where your class functions will be declared and developed. We can have functions that are known as class functions. These are designated with the keywords class func. In short, class functions are part of the class as a whole as opposed to an instance of the class. It's best practice to place these above the next, more common type of function, the public functions, that can be accessed by other classes and properties via the dot operator (that is, className.function(parameters)). Using the private func keywords, as in C# and Java, we can create private functions that are only accessible to the class's own functions and properties.

  • (f): The deinit() function is a special optional function that deals with how we clean up the data allocated by our class with memory management and eliminating what's known as memory leaks. Apple's ARC (Automated Reference Counting) handles most of this, but there are key words, such as weak and unowned, that we will at times have to put before various properties to make sure that they don't hang around after use.

    This is a rather involved topic, but worth looking into to avoid memory leaks in your game. ARC does take care of most of this, but there might be objects in your game that could potentially hang around. It's highly recommended to read Apple's own documentation on this topic, as memory management in iOS is always in the evolving stage. You can view the full documentation on ARC and memory management in Swift at https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/AutomaticReferenceCounting.html.

  • (g): If we wish, we can have global properties also at the bottom of our .swift files, after the end of the class declaration. Apple's own game example, Adventure (https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html), places global properties in this spot.

 

Summary


There's much more about the Swift programming language than we could fit here. Throughout the course of this book, we will throw in a few extra tidbits and nuances about Swift as it becomes relevant to our upcoming gaming programming needs.

If you wish to become more versed in the Swift programming language, Apple actually provides a wonderful tool in what's known as a Playground.

Playgrounds were introduced with the Swift programming language at WWDC14 in June of 2014 and allow us to test various code outputs and syntaxes without having to create a project, build it, and run it and repeat again, when in many cases we simply needed to tweak a few variables and function loop iterations.

There are a number of resources to check out on the official Swift developer page (https://developer.apple.com/swift/resources/).

Two highly recommended Playgrounds to check out are as follows:

Sometimes, the best way to learn a programming language is to test live code, and that's exactly what Playgrounds allow us to do.

In addition to testing snippets of code in our games, iOS 9 also allows us to plan and structure our games, which is the topic of the next chapter.

About the Author
Latest Reviews (1 reviews total)
iOS 9 Game Development Essentials
Unlock this book and the full library FREE for 7 days
Start now