How To Make a Letter / Word Game with UIKit and Swift: Part 1/3
This 3-part tutorial series will guide you through the process of building a board game for the iPad in Swift, where you create words with letters. You’ll also learn about best practices for creating solid, modular iOS apps. And as a bonus, you’ll get a crash course in audio-visual effects with UIKit! By Caroline Begbie.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How To Make a Letter / Word Game with UIKit and Swift: Part 1/3
35 mins
- Getting Started: Introducing Anagrams
- The Starter Project
- 1) Load the Level Config File
- 2) Create a Game Controller Class
- 3) Create an Onscreen View
- 4) Create a Tile View
- 5) Dealing the Tiles on the Screen
- 6) Add the Letters
- 7) Slightly Rotate the Letters Randomly
- 8) Add the Targets
- Where to Go from Here?
2) Create a Game Controller Class
People who are not experienced with the model-view-controller (MVC) paradigm before jumping into iOS development often confuse a controller and a UIViewController
.
- A controller is simply a class that focuses on some part of your app’s logic, separate from your app’s data and the classes used to display that data.
- A class that subclasses
UIViewController
is a controller managing the presentation of a particularUIView
. (AndUIView
s are used to display something on the screen.) You can read up more on the MVC pattern here.
For this tutorial, you are going to create a controller class to manage your game’s logic. Let’s try this out.
Create a new Swift file in the Anagrams/Classes/Controllers folder. Call the new file GameController
.
Open GameController.swift and add the following:
import UIKit
class GameController {
var gameView: UIView!
var level: Level!
init() {
}
func dealRandomAnagram() {
}
}
I bet you’ve already spotted the building blocks of your current goal:
-
gameView
: The view you’ll use to display game elements on the screen. -
level
: TheLevel
object that stores the anagrams and other settings for the current game level. -
dealRandomAnagram()
: The method you’ll call to display the current anagram on the screen.
The variables are declared as implicitly unwrapped optionals, as they should never be nil, but you will not be creating the instances in the GameController’s initializer.
The code so far is pretty simple. Change dealRandomAnagram()
to have this placeholder implementation:
func dealRandomAnagram () {
//1
assert(level.anagrams.count > 0, "no level loaded")
//2
let randomIndex = randomNumber(minX:0, maxX:UInt32(level.anagrams.count-1))
let anagramPair = level.anagrams[randomIndex]
//3
let anagram1 = anagramPair[0] as! String
let anagram2 = anagramPair[1] as! String
//4
let anagram1length = count(anagram1)
let anagram2length = count(anagram2)
//5
println("phrase1[\(anagram1length)]: \(anagram1)")
println("phrase2[\(anagram2length)]: \(anagram2)")
}
This method will fetch a random anagram, deal the letter tiles, and create the targets. Here’s what happening in the code, section by section:
- You check to make sure this method is only called after the
level
property is set and that itsLevel
object contains anagrams. - You generate a random index into the anagram list, then grab the anagram at this index. This
randomNumber()
function is defined in Config.swift. - You store the two phrases into
anagram1
andanagram2
. - Then you store the number of characters in each phrase into
anagram1length
andanagram2length
. Even though the letters are the same between anagram1 and anagram2, there can be a different number of spaces so the overall number of characters can be different. - Finally, you print the phrases to the console. This will suffice for testing.
Your app is already set up to load the storyboard Main.storyboard at start up. This storyboard creates a single screen using the ViewController
class.
Since your game will only have one screen, you will add all initialization inside the ViewController
initializer. For games that include more than one view controller, you may want to do your initialization someplace else, such as the AppDelegate
class.
Open up ViewController.swift and add this property inside the ViewController class:
private let controller:GameController
Finally, add a new initializer to the class:
required init(coder aDecoder: NSCoder) {
controller = GameController()
super.init(coder: aDecoder)
}
The app will use the init(coder:)
initializer automatically when it instantiates a ViewController
from the storyboard.
There it is! You’ve created a GameController
class and you have an instance of it in your ViewController
class, ready to go off and spill some letter tiles on the screen at any moment. :]
3) Create an Onscreen View
The next step is also quite easy: you need to create a view on the screen and connect your GameController
to it.
Open up Config.swift and look at the first two constants inside the file: ScreenWidth
and ScreenHeight
. You are going to use these constants to create your game view.
Switch back to ViewController.swift and add the following code at the end of viewDidLoad()
:
//add one layer for all game elements
let gameView = UIView(frame: CGRectMake(0, 0, ScreenWidth, ScreenHeight))
self.view.addSubview(gameView)
controller.gameView = gameView
Here, you create a new view with the dimensions of the screen and add it to the ViewController
‘s view. Then you assign it to the gameView
property of your GameController
instance. This way the GameController
will use this view for all game elements. You’ll create a separate view for the heads-up display (HUD) later.
Having now created your model and controller classes, you’ve come to the point where you need your first custom view class for the Anagrams game to display the tiles.
4) Create a Tile View
In this section, you are going to build a view to show tiles like these:
For now, you’ll focus on just creating the tile squares with the background image. Later, you’ll add the letters on top.
Inside the file group Anagrams/Classes/Views, create a new Swift file called TileView
. Add the following to TileView.swift:
import UIKit
//1
class TileView:UIImageView {
//2
var letter: Character
//3
var isMatched: Bool = false
//4 this should never be called
required init(coder aDecoder:NSCoder) {
fatalError("use init(letter:, sideLength:")
}
//5 create a new tile for a given letter
init(letter:Character, sideLength:CGFloat) {
self.letter = letter
//the tile background
let image = UIImage(named: "tile")!
//superclass initializer
//references to superview's "self" must take place after super.init
super.init(image:image)
//6 resize the tile
let scale = sideLength / image.size.width
self.frame = CGRect(x: 0, y: 0, width: image.size.width * scale, height: image.size.height * scale)
//more initialization here
}
}
There are a few different sections in the code:
- Make the class a subclass of
UIImageView
. TheUIImageView
class provides you with the means to show an image, so you’ll only need to add a label on top of the image later on. -
letter
: A property that will hold the letter assigned to the tile. -
isMatched
: A property, initially set to false, that will hold a Boolean indicating whether this tile has already been successfully matched. - This is
UIImageView
‘s required initializer, which must be overridden even though you’ll never use it. -
init(letter:sideLength:)
: a custom initializer to set up an instance of the class with a given letter and tile size. It saves the letter to the tile’s variable and loads the tile.png image. - You then calculate by how much you need to scale the default tile so that you get a size that will fit your board for the given word or phrase. To do that, you just adjust the
frame
of theTileView
.UIImageView
resizes its image automatically to match its frame size.
Why do you need to set the size of the tile, you might ask?
Look at the these two setups:
The top example shows a short word that requires large tiles to fill the screen. The bottom example shows a phrase that requires smaller tiles because it has almost double the tile count. The tile view needs to be resizeable so that you can show different size tile depending on how many tiles there are on the screen at a time.
Your controller will calculate the phrase length, divide the screen width by the number of characters and decide on a tile size. You’ll implement that soon, but this code is already enough to show tiles containing just the empty tile.png image.