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.