Quantcast
Channel: Kodeco | High quality programming tutorials: iOS, Android, Swift, Kotlin, Unity, and more
Viewing all 4373 articles
Browse latest View live

Custom Subscripting in Swift Tutorial

$
0
0
Create a Checkers game that takes advantage of subscripting.

Create a Checkers game that takes advantage of subscripting.

Subscripting first came to Objective-C in Xcode 4.4, way back in the middle of 2012. At this time, Swift was already two years into development. As with many other powerful features in Objective C, such as ARC, subscripting also became part of Swift.

Subscripts don’t actually add functionality to a class, instead they’re shortcuts to access members of a collection. It sounds like a trivial application, but subscripts significantly enhance the convenience factor and readability of your code.

For example, it used to be that you would write myArray.objectAtIndex(2) to access the third element of the array myArray. As of Xcode 4.4, you can access the third element with the much simpler myArray[2].

Moreover, dictionary access is simpler as well; instead of value = [myDictionary objectForKey:@"VotingAge"], you can now write value = myDictionary[@"VotingAge"]

Check out iOS 6 by Tutorials (Second edition) for the details on this and all the other advances in modern Objective-C.

Moreover, Objective-C supports adding subscripts to custom classes, but it requires some effort. In contrast, Swift makes adding subscripts to your own classes easier to implement than ever. Yes, that’s right, your life is about to get easier, compliments of Apple.

Note: This Swift tutorial assumes you already know the basics of Swift development. If you are new to Swift, we recommend you check out some of our other Swift tutorials first.

Getting Started

In this Swift tutorial, you’re going to explore subscripts by building a basic checkers game in a playground. You’ll see how easy moving pieces around is, illustrating the power of subscripting right on your game board.

When you’re done, you’ll also have a new game to keep your fingers occupied during all of your spare time.

Download the starter project. Look over the two types that already present in the playground:

  • enum PlayerColor: Represents the color of a piece on the board. Note that a piece with PlayerColor type .None represents a blank space on the board.
  • class GameBoard: This is the main class you’ll work with. It has a 2-dimensional array of PlayerColors that holds the board’s data.

GameBoard controls all the gameplay and keeps track of the piece locations, and to make it functional you’ll add subscripting to GameBoard.

Open the Assistant Editor by going to View\Assistant Editor\Show Assistant Editor to view the console.

Enter the following lines at the bottom of the playground, after the closing brackets of the GameBoard class:

let board = GameBoard()
board.displayBoard()

After initializing the instance GameBoard of the GameBoard class, the call to board.displayBoard() prints the board to the console.

The board currently looks like this:

-r-r-r-r
r-r-r-r-
-r-r-r-r
--------
--------
b-b-b-b-
-b-b-b-b
b-b-b-b-

The board array comprises eight elements, each of which is an array of eight elements. In effect, this makes board a two-dimensional array. For example, board[2][5] refers to the sixth element of the third subarray — remember that the first element of an array is at index 0).

Note how the board’s subscripts are y-before-x. No, you’re not looking through at in in one of those goofy mirrors at a carnival.

Though it seems backwards, it’s actually not on this project, because you have to access it in this way because of how board is set up.

The following image should help clarify this concept. From the user’s perspective, the square at (7,0) is at the top-right corner. However, in the image, the square (7,0) appears in the first array of board. The seventh element of this subarray is the piece at square (7,0).

Therefore, to locate the piece at square (7,0), you would need to access board[0][7].

CheckerboardCoords

Implementing a Simple Moving Method

An effective way to create subscripts is to write the code in functions first, then reuse it when you build the subscripts.

With that in mind, you’re going to implement a simple function that moves a piece from one location to another. The coordinates of the locations consist of a tuple of two Int’s: (Int,Int).

Add this function to the end of the GameBoard class:

func movePieceFrom(from: (Int,Int), to: (Int,Int)) {
  let pieceToMove = board[from.1][from.0]
  board[from.1][from.0] = empty()
  board[to.1][to.0] = pieceToMove
}

This is a very basic implementation for now – you’ll add more game logic here later in the tutorial.

First, you store the piece you want to move in a variable. The next line replaces that piece in the GameBoard with a blank space. Then, you move the piece where you want it to go.

Try this out. At the bottom of the file, add the following two lines:

board.movePieceFrom((2,5), to: (3,4))
board.displayBoard()

Here, you tell your GameBoard to move the piece at (2,5), which happens to be a black piece, diagonally to the right.

Look in the console, the board shows that the piece from (2,5) moved to its new position at (3,4):

-r-r-r-r
r-r-r-r-
-r-r-r-r
--------
---b----
b---b-b-
-b-b-b-b
b-b-b-b-

Finding Who is Where

Looking at the console, it’s pretty easy for you to know what piece occupies a given location, but your program doesn’t have the same powers. It can’t know which player is at a specified position without directly accessing GameBoard properties.

Add the following function at the end of GameBoard:

func playerAtLocation(coordinates: (Int, Int)) -> PlayerColor {
  return board[coordinates.1][coordinates.0]
}

This function simply returns the color of the piece located at the given coordinates.

Often, when a function gets a value from the class, there’s also one to set a value. In this case, setting the PlayerColor at a location can be very helpful.

If you need to set up the board, allow someone else to take over a piece, or need to remove a jumped piece, you need a method like this. Add the following function at the end of GameBoard.

func setPlayer(player: PlayerColor, atLocation coordinates: (Int, Int)) {
  board[coordinates.1][coordinates.0] = player
}

This method replaces the color of the piece at a specific location on the board with a piece of the given color.

Declaring Subscripts

Subscripts and computed properties have similar declarations. For a little comparison, pretend you’re making a computed property, like this:

var computedProperty: Type {
  get {
    //return someValue
  }
  set {
    //setSomeValue()
  }
}

Here’s how that looks as a subscript:

subscript(parameters) -> ReturnType {
  get {
    //return someValue
  }
  set (newValue) {
    //setSomeValue()
  }
}

In the setter, there is a default parameter newValue with a type that equals the subscript’s return value type. You use this parameter to change the underlying value within the class. You don’t have to declare the newValue parameter.

Just like computed properties, subscripts can be read-only or read-write.

A read-only subscript doesn’t explicitly state get or set; the entire function body is a getter:

subscript(parameters) -> ReturnType {
  return someValue
}

disguise

A common approach to subscripting is to have a normal method that works the same as the subscript, allowing it to act as a shortcut to the method.

For example, consider that NSMutableArray has objectAtIndex() and replaceObjectAtIndex(withObject:). Using subscripts on an NSMutableArray instance would call these two methods, depending on the use.

Similarly, custom indexed subscripts on your class in Objective-C serve as shortcuts for calls to objectAtIndexedSubscript: and setObject:atIndexedSubscript:, both of which you must implement appropriately for your class.

In Swift, Apple seems to have moved away from this paradigm, because using subscripts is the only way to access elements of arrays and dictionaries. However, this paradigm is still useful.

Creating a Subscript on GameBoard

Remember playerAtLocation(_:) and setPlayer(_:atLocation:)? A single subscript can replace both of these.

Add this empty subscript declaration into the bottom of GameBoard:

subscript(coordinates: (Int,Int)) -> PlayerColor {
  get {
 
  }
  set {
 
  }
}

Ignore the errors for now, they’ll disappear when you combine playerAtLocation() and setPlayer(atLocation:) into a single read-write subscript.

Based on the pattern explained earlier, there is no need to copy the code from before into the subscript. Instead, the subscript calls these methods directly.

Add the following code to the subscript’s getter:

get {
  return playerAtLocation(coordinates)
}

At the bottom of the playground, add the following lines to see this subscript in action:

let player = board[(3,4)]
println(player.description)

Since there is a black piece at the location (3,4), the console prints Black.

Likewise, implement the setter using setPlayer(atLocation:) to make your code look like this:

set {
  setPlayer(newValue, atLocation: coordinates)
}

Now go to the bottom of the playground and enter the following lines:

board[(3,4)] = .Red
board.displayBoard()

Voila! The black piece located at (3,4) becomes a red piece!

-r-r-r-r
r-r-r-r-
-r-r-r-r
--------
---r----
b---b-b-
-b-b-b-b
b-b-b-b-

Adding a Second Subscript

One subscript down, one more to go! This time, you’re adding a subscript for movePieceFrom(_:to:). After this, instead of writing this old, verbose line:

board.movePieceFrom((2,5), to: (3,4))

You’ll be able to write the more succinct:

board[(4,5)] = (2,3)

At the bottom of GameBoard, create another read-write subscript like the first one, but with a return type of (Int,Int) instead of PlayerColor.

subscript (coordinates: (Int,Int)) -> (Int,Int) {
  get {
 
  }
  set {
 
  }
}

Add movePieceFrom(to:) to the setter for this subscript.

set {
  movePieceFrom(coordinates, to: newValue)
}

Note the above code uses the default newValue, but doesn’t declare it.

In contrast, the getter for this subscript is not so straightforward. In fact, you don’t want to return a value for this subscript; it’s effectively write-only.

Instead of returning a dummy value, you’ll employ the useful assert function, which throws an error during development to alert the developer that something’s wrong, but doesn’t throw an error in production code.

Replace the getter with the following:

get {
  assert(false, "Using the getter of this subscript is not supported.")
}

Now, any attempt to access this subscript throws an exception.

Uh-oh, there seems to be a problem! Did you notice that the playground shows an error on the line?
let player = GameBoard[(3,4)].
Screenshot 2014-08-22 22.48.55

Why is this happening? More importantly, how can you fix it?

Ambiguous Subscripts

The problem is a lack of information. GameBoard[(3,3)] can return either (Int,Int) or PlayerColor. As a result, the compiler has no clue know which one to call.

In order to specify which one you really want to use, explicitly set the type of player to a PlayerColor. The compiler will then be able to infer the appropriate subscript method to use.

To do this, replace the line:

let player = board[(3,4)]

With this:

let player: PlayerColor = board[(3,4)]

This lets the compiler know which subscript you really want to call: the one that returns a PlayerColor.

Gratuitous Gameplay

Note: Congratulations, you’ve learned how to add subscripting to your own classes in Swift! The rest of this Swift tutorial just extends this game a bit further with some gameplay logic, so is optional.

Right now, when you use the subscript to set the new position of a piece, the piece just goes wherever you say, even if it’s an illegal or invalid move. Talk about a power trip.

You’ll have a hard time finding anybody to play with you given your supreme impunity to the rules, so you need to add some simple move validations.

Before jumping to the code, think through the ways you can ensure a move is valid.

thinkingcap

  1. Is the new coordinate in the game board? If either of the coordinates are outside the range of 0-7, the move is invalid.
  2. Is the moving piece either red or black? If the piece represents a blank space on the board, there’s no sense in moving it.
  3. Is there a red or black piece at the new location? In checkers, you cannot land on another piece.
  4. Is the piece moving in the right direction? red pieces move down the board, while black pieces move up the board.
  5. Is the new position off by one in both the X-coordinate and the Y-coordinate? Pieces move diagonally by one when they don’t jump over the opponent’s piece.
  6. Does the piece jump over an opponent?. If this is the case, then a blank space must replace the jumped piece on the board.

That of course doesn’t cover every variable, but you have the basics covered.

To be fully functional, you also need to check for multiple jumps, declare a king, allow the king to move backwards, and check for moves that are not jumps when a jump is possible (The official rules of checkers requires a player to make a jumping move if one is possible.)

You’d also need to check that the player moving is not moving out of turn!

Now that you know what to validate, you need to add these new rules to the program. Instead of making changes directly to the subscript, you’ll make the changes in movePieceFrom(_:to:).

Delete the code inside movePieceFrom(_:to:). One by one, you’ll add the rules from your list.

After detecting an invalid move, the code prints an error message. Within the function, add this new function that prints the error message:

func error(errorType:String) {
  println("Invalid Move: \(errorType)")
}

The first check is to make sure both locations are actually on the board, not in the hinterlands. To do this, check if the coordinates fall within the proper range of 0-7:

if !(0...7 ~= from.0 && 0...7 ~= from.1 && 0...7 ~= to.0 && 0...7 ~= to.1) {
  error("Range error")
  return
}

The ~= operator (tilde and equals characters) tests to see if the range on the left contains the value on the right. Here, you make sure that each location’s coordinate is in the range of 0-7. If not, you call the error message and return.

Next up is a simple check to ensure the color of the moved piece is a not a blank, and in this situation, you’ll use subscripting to find the player.

if playerAtLocation(from) == .None {
  error("No Piece to Move")
  return
}

Similar to the previous validation, you check if there is actually a piece (of either color) at the starting position.

Now, add this to the bottom of movePieceFrom(_:to:):

if playerAtLocation(to) != .None {
  error("Move onto occupied square")
  return
}

In this case, you do want the new location to be empty. Notice the != compared to the == in the previous code.

Onto the next validation step, which is making sure the piece is moving in the right direction. Remember that each color can only go one way — and that’s what this next block does:

let yDifference = to.1 - from.1
if (playerAtLocation(from) == .Red) ? yDifference != abs(yDifference) : yDifference == abs(yDifference) {
  error("Move in wrong direction")
  return
}

yDifference finds the difference between the y-coordinates of to and from.

If the piece being moved is red, then it can only move down the board; when a piece moves down the board, it moves by a positive value. Since a positive value always equals its absolute value, you can use this basic math to determine if the piece is moving in the right direction.

On the other hand, black moves up the board and has a negative y-coordinate. Negative numbers don’t equal their absolute value so they’re disallowed from moving down the board — you check this at the end of the ternary operator.

Now for the next validation, and that is determining if the piece is moving diagonally by one. This is the only type of move you can make when you’re not moving a king and there isn’t a jump to make.

Diagonal movement requires that both the x- and y-coordinate change by an absolute value of 1. The following checks for this condition:

if abs(to.0 - from.0) != 1 || abs(to.1 - from.1) != 1 {
  error("Not a diagonal move")
  return
}

movePieceFrom(_:to:) is almost functional at this point, but there is an issue to address.

Since the last segment throws an error whenever a piece moves more than one space, there is no way to check for legal jumps that move a piece by 2 spaces.

In order to change this, replace the code:

if abs(to.0 - from.0) != 1 || abs(to.1 - from.1) != 1 {
  error("Not a diagonal move")
  return
}

with:

if abs(to.0 - from.0) != 1 || abs(to.1 - from.1) != 1 {
  if abs(to.0 - from.0) != 2 || abs(to.1 - from.1) != 2 {
    error("Not a diagonal move")
    return
  }  
  let coordsOfJumpedPiece = ((to.0 + from.0) / 2 as Int, (to.1 + from.1) / 2 as Int)
  let pieceToBeJumped: PlayerColor = self[coordsOfJumpedPiece]
  if contains([.None, playerAtLocation(from)], pieceToBeJumped) {
    error("Illegal jump")
    return
  }
  setPlayer(.None, atLocation: coordsOfJumpedPiece)    
}

The first if-statement is the same as the original code, but inside there’s another similar if-statement that checks to see if the piece moves by 2 instead of by 1. Also, if the piece doesn’t move diagonally by 1 or 2, the code prints an error message to the console.

In the instance that the piece moves two spaces in either direction, there needs to be a piece in the middle to jump over, otherwise the move is illegal. The location of this piece must be the midpoint between from and to, and you calculate that location by averaging the x and y values of both coordinates.

Also, the jumped piece needs to be the opposite color as the piece that is doing the jumping. Once the code confirms that, the jumped piece is set to .None.

Nice job, although you’ll no longer enjoy supreme command over the board, you now have checks in place that allow for basic play and the piece moves to its new location:

let pieceToMove = board[from.1][from.0]
    board[from.1][from.0] = empty()
    board[to.1][to.0] = pieceToMove

Finally, test out this new functionality by entering these two lines at the bottom of the playground:

board[(4,5)] = (2,3)
board.displayBoard()

This changes the board from

-r-r-r-r
r-r-r-r-
-r-r-r-r
--------
---r----
b---b-b-
-b-b-b-b
b-b-b-b-

to

-r-r-r-r
r-r-r-r-
-r-r-r-r
--b-----
--------
b-----b-
-b-b-b-b
b-b-b-b-

The black piece now jumps over the red piece, as you’d expect in a normal game of checkers.

Now test the error checking by trying other moves. Remember that each legal move you make changes the board!

Enter the moves below, one by one, in the order indicated to see the effect:

board[(1,6)] = (2,5) //legal move
board.displayBoard()
 
board[(1,6)] = (1,5) //No piece to move since
board.displayBoard() //you just moved the piece at (1,6)
 
board[(7,2)] = (6,1) //(6,1) is already occupied
board.displayBoard()
 
board[(7,2)] = (5,4) //Illegal jump - no piece to jump
board.displayBoard()
 
board[(7,2)] = (8,1) //Range Error
board.displayBoard()
 
board[(0,7)] = (1,6) //legal move
board.displayBoard()

Where To Go From Here?

If you’d like to see the project in its fully functional form, feel free to download the completed project from this Swift tutorial.

Now that you have added subscripts to your tool kit, look for opportunities in your own code to use them. While they don’t add extra functionality, they sure make your code more readable and more intuitive if used properly.

That said, you don’t always want to revert to subscripts. One or two subscripts on a class can be helpful, but if the subscript feels unnatural or forced, or if you have more than a few on a single class, then you should start asking yourself if you really need it.

Of course, this is just a bare bones start for a checkers game. You can still improve the game, for one, there’s still several basic validations you could add. Then you could implement a “King Me!” mechanism, multiple jumps, or track of which player’s turn it is.

If you want to learn more about Swift development, check out our book Swift by Tutorials.

If you have an questions, comments or other idea for how to use subscripts, please leave your comments below!

Custom Subscripting in Swift Tutorial is a post from: Ray Wenderlich

The post Custom Subscripting in Swift Tutorial appeared first on Ray Wenderlich.


Swift by Tutorials Updated for Xcode 6.1

$
0
0
Swift by Tutorials Updated for Xcode 6.1!

Swift by Tutorials Updated for Xcode 6.1!

Good news – Colin Eberhardt and Matt Galloway have updated Swift by Tutorials for Xcode 6.1!

Xcode 6.1 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

In addition to updating the book for Xcode 6.1, Matt and Colin also fixed some errata pointed out by readers – thanks all!

Here’s how you can get the update:

  • If you’re a Swift by Tutorials customer, you can download the update for free on your My Loot page (version 1.2).
  • If you haven’t picked up a copy of the iOS Apprentice yet, grab your copy now.

We’re hard at work updating the rest of our Swift books for Xcode 6.1 – stay tuned.

Colin, Matt and I hope you enjoy this update!

Swift by Tutorials Updated for Xcode 6.1 is a post from: Ray Wenderlich

The post Swift by Tutorials Updated for Xcode 6.1 appeared first on Ray Wenderlich.

Realm with JP Simard – Podcast S02 E03

$
0
0
A deep dive into Core Data with Saul Mora!

A deep dive into Core Data with Saul Mora!

Welcome back to season 2 of the raywenderlich.com podcast!

Remember that among the many changes in this season, we are now moving to a weekly (and shorter) format – so we’re cracking along with episodes (3 already)!

In this episode, we talk with JP Simard, iOS Developer at Realm, a new mobile database replacement for SQLite and Core Data.

We discuss what Realm is, what advantages it has over Core Data, and when you might want (or not want) to use it.

[Subscribe in iTunes] [RSS Feed]

Links and References

Contact Us

Where To Go From Here?

We hope you enjoyed this podcast, and the changes we made for season 2.

Remember – we’re now on a weekly format, so stay tuned for a new episode next week! :]

Be sure to subscribe in iTunes to get access as soon as it comes out!

We’d love to hear what you think about the podcast, and any suggestions on what you’d like to hear in future episodes. Feel free to drop a comment here, or email us anytime at podcast@raywenderlich.com!

Realm with JP Simard – Podcast S02 E03 is a post from: Ray Wenderlich

The post Realm with JP Simard – Podcast S02 E03 appeared first on Ray Wenderlich.

Why RWDevCon is Different

$
0
0

As you may know, we are teaming up with the folks from 360iDev to run an iOS conference next year: RWDevCon.

But what you might not know is why RWDevCon is different than other iOS conferences. Check out this video to learn why!


Don’t miss your chance to save $100 off the ticket price – the early bird discount ends this Friday. Get your ticket today!

If you’re not the type to watch a video, keep reading – the full transcript is below!

Video Transcript

Screen Shot 2014-10-26 at 5.36.52 PM

I have been to a lot of iOS conferences over the years, and here’s how the experience typically goes for me.

I look over the schedule and I see a bunch of random topics by random people on random subjects.

I choose one that seems interesting, I walk into the room, and there’s somebody up front, going over a bunch of slides and showing a demo or two. Sometimes, the talk is good, and sometime’s it’s bad – it’s really just luck of the draw.

If the talk is good, I eagerly take notes, sure that this is going to come in handy later, and that I’m really learning something. But then I get home and try to use this stuff in an actual app, and I realize I haven’t actually learned anything – and I have to learn it from scratch.

A Better Way

We believe there’s a better way to run a conference than this.

Screen Shot 2014-10-26 at 5.37.57 PM

  • Imagine a conference where the schedule and talks are coordinated by a team, rather than a random hodge-podge of topics.
  • Imagine a conference where instead of just listening to some boring slides, you get hands-on experience, try out things for yourself, and actually learn.
  • Imagine a conference where each session is high quality, rather than luck of the draw.
  • Imagine a conference where you leave inspired, having made some new friendships along the way.

It this is the kind of conference you’d like to attend – we have something you’re going to really enjoy – RWDevCon.

About RWDevCon

RWDevCon is the first ever conference focused on high quality hands-on tutorials. We’re going to have two tracks of tutorials: one for beginner to intermediate iOS developers, and one for advanced iOS developers.

Screen Shot 2014-10-26 at 5.39.55 PM

In a typical tutorial, you’ll come in and the instructor will give a brief overview of the topic, and then you’ll get right into a live demo. But instead of just watching the instructor, you’ll follow along with the instructor so you can see things working for yourself.

After the demo, you’ll break out into a hands-on lab, where you’ll be challenged to try things out on your own – and the instructor will be right with you if you have any questions.

We really think this hands-on experience is the best way to learn, and this way you won’t just leave with notes and references – you’ll leave with actual new skills.

Where To Go From Here?

Hands-on experience, team coordination, inspiration, and friendship – that’s what RWDevCon is all about. This is why RWDevCon is different than other iOS conferences out there, and why I think we have something really special.

The team and I hope to see you at the conference – don’t forget that this is the last week for the early bird discount, so be sure to sign up now. See you in DC!

Music credits: Kevin MacLeod.

Why RWDevCon is Different is a post from: Ray Wenderlich

The post Why RWDevCon is Different appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 13: Interactive Transitions

Introduction to Google Maps iOS SDK in Swift

$
0
0

GoogleMaps_Main

Up to iOS 5, Google Maps was an integral part of iOS and was the mapping engine used by all iOS devices. With the release of iOS 6 in 2012, Apple made a dramatic change and replaced Google Maps with an in-house mapping engine.

Just a few months later, Google released its own standalone Google Maps app for iOS, along with the Google Maps iOS SDK for developers.

There are benefits and drawbacks to both MapKit and the Google Maps iOS SDK, but this tutorial will walk you through implementing Google Maps into your apps to see for yourself how well it can work in your geolocating apps.

In this tutorial, you’ll build an app called Feed Me, which gets the user’s current location and searches for nearby places to eat, drink, or even go grocery shopping. The results will be presented in-app using the Google Maps SDK.

This tutorial assumes some familiarity with Swift and iOS programming. If you’re new to Swift, or to iOS programming altogether, you might want to check out some other tutorials previously published on this site.

This tutorial uses Xcode 6.1 with iOS 8 and requires knowledge of Auto Layout, Size Classes, and of course, Swift.

Getting Started

Download the Feed Me Starter and open it in Xcode 6.

Here are the most important elements in the project:

  • Main.storyboard: This is the UI storyboard for the project, with some very basic UI ready for your modifications. Notice that this storyboard uses Auto Layout and Size Classes.
  • MapViewController.swift: This is the main view controller of this project; there’s not much in it right now, other than a types array and navigation methods that present a type selection controller. You’ll be working with just MapViewController in this tutorial; don’t worry, by the time you’re done it will look a lot more finished!
  • TypesTableViewController.swift: This is a table view controller that lets you search for types of places to present them on a map.
  • GoogleDataProvider.swift: This is a wrapper class for making Google API calls. You’ll review the methods contained within later in the tutorial.
  • GooglePlace.swift: This is a model for place results returned from Google.
  • MarkerInfoView.swift: This is a subclass of UIView that displays details of places. It comes with a matching xib file.
  • UIViewExtension.swift: This is a UIView class extension — similar to a category in Objective-C — with several methods you’ll use as you make your way through the tutorial.

Before you start coding it’s a good idea to see how the app works. Build and run your app; you’ll see the following screen appear:

GoogleMaps_GettingStarted_01

Right now all you’ll see is a blank screen with a pin in the middle. Press the action button on the right side of the navigation bar to see the TypesTableViewController screen like so:

GoogleMaps_GettingStarted_02

That’s all there is to see in the app at the moment — it’s up to you to add some magic!

Creating API Keys

The first thing you’ll need are some API keys for the Google Maps SDK and the Google APIs you’ll be using. If you don’t already have a Google account, create one (they’re free!) and log in to the Google Developers Console.

Click on Create Project, name your project Feed Me, accept the terms of service and click Create:

GoogleMaps_APIKeys_01
Select APIs & auth and then APIs from the left pane menu. You’ll see a long list of available APIs on the main pane. Disable the currently selected APIs, and enable the following three APIs:

  • Google Maps SDK for iOS
  • Places API
  • Directions API

Your screen should now look like the following:

GoogleMaps_APIKeys_02

Select Credentials under APIs & auth in the left pane menu. Click Create new key, and then click iOS key to create the Maps SDK key:

GoogleMaps_APIKeys_03

Enter the starter project’s bundle identifier (tutorial.feedme.com) and click Create:

GoogleMaps_APIKeys_04

Create another key, only this time choose Server key to create the Places and Directions APIs key. Leave the text box empty and click Create. You should now have two boxes with browser and iOS keys, like this:

GoogleMaps_APIKeys_05

Go back to Xcode and open GoogleDataProvider.swift. Locate the apiKey property declaration below:

let apiKey = "YOUR_API_KEY"

and replace it with the server key you created above. You’ll use the iOS key in a moment, but you need the actual Google Maps SDK key first.

Adding the Maps

Download the Google Maps SDK from the Google Maps SDK for iOS page. This tutorial uses version 1.8.1 of the SDK, so if the API has advanced by the time you read this tutorial find the version closest to 1.8.1 and use that.

Return to Xcode and drag the GoogleMaps.framwork file you downloaded into the Frameworks folder. When prompted, check Copy items if needed, make sure the Feed Me target is checked and click Finish:

GoogleMaps_AddingMaps_01

Right-click on GoogleMaps.framework in the Project Navigator and select Show In Finder. Expand the framework and go into the Resources folder. Drag the GoogleMaps.bundle from the Resources folder to your Frameworks folder in Xcode. Once again, make sure Copy items if needed and the Feed Me target are checked, then click Finish.

Next, select the Feed Me project at the top of the Project Navigator, and choose the Feed Me target. Select the Build Phases tab, and within Link Binary with Libraries add the following frameworks by clicking the + sign:

  • AVFoundation.framework
  • CoreData.framework
  • CoreLocation.framework
  • CoreText.framework
  • GLKit.framework
  • ImageIO.framework
  • libc++.dylib
  • libicucore.dylib
  • libz.dylib
  • OpenGLES.framework
  • QuartzCore.framework
  • SystemConfiguration.framework

When finished, the Frameworks folder in the Project Navigator should look like this:

GoogleMaps_AddingMaps_02

Once again, select the Feed Me project at the top of the Project Navigator, only this time, choose the Feed Me Project rather than the target. Select the Build Settings tab, and in Other Linker Flags add -ObjC as shown below:

GoogleMaps_AddingMaps_03

That last step is required because the Google Maps SDK is currently written in Objective-C; even though you won’t be writing Objective-C code, you’ll still need to link in Objective-C libraries. To use Google’s Obj-C SDK code in your Swift application, you’ll need an Objective-C Bridging Header file.

This easiest way to create a bridging header file is to add an arbitrary Objective-C file to your project and let Xcode create the bridging header for you.

Go to File \ New \ File… and select the iOS \ Source \ Objective-C file template. Name the file whatever you like — you’ll delete this file in a moment — then save it. When save the file, Xcode offers to create an Objective-C bridging header file for you like so:
GoogleMaps_AddingMaps_04

Click Yes and Xcode will create the bridging header file and add it to your project. Delete the original Objective-C file as you no longer need it.

Open the newly created Feed Me-Bridging-Header.h and add the following line of code to the bottom of the file:

#import <GoogleMaps/GoogleMaps.h>

The Google Maps SDK is now available in your Swift app — it’s finally time to write some code! :]

Open AppDelegate.swift and replace its content with the following:

import UIKit
 
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
 
  var window: UIWindow?
  // 1
  let googleMapsApiKey = "YOUR_GOOGLE_IOS_API_KEY"
 
  func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
    // 2
    GMSServices.provideAPIKey(googleMapsApiKey)
    return true
  }
}

There are two new elements here:

  1. There is new a constant to hold your Google iOS API key. Replace YOUR_GOOGLE_IOS_API_KEY with the Google iOS API key you created earlier.
  2. Your app will instantiate Google Maps services with the API Key using the GMSServices class method provideAPIKEY.

Next, open Main.storyboard to bring up Interface Builder. Bring up the Object Library by selecting the third tab in the view toolbar — Utilities — and then select the third tab in the library toolbar (Object library), as shown in the screenshot below:

GoogleMaps_AddingMaps_05

Locate the MapViewController scene and drag a simple UIView from the Object library to the approximate center of the MapViewController’s view. Next, open the Document Outline using Editor \ Show Document Outline and re-order the view hierarchy so that the object tree looks like this:

GoogleMaps_AddingMaps_06

To turn this simple UIView into a GMSMapView, select the view you just added and open the Identity Inspector by selecting the third tab from the left in the Utilities toolbar. Change the view’s class name from UIView to GMSMapView, as shown in the screenshot below:

GoogleMaps_AddingMaps_07

Open the Attributes Inspector by selecting the fourth tab from the left in the Utilities toolbar, and change the MapView’s background color to a light grey color. This will not affect the view during runtime, but will make the MapView more visible as you edit it in Interface Builder.

Your MapViewController scene should now look like this:

GoogleMaps_AddingMaps_08

Next, you’ll need to add some constraints to make the map fill the entire screen. Select the second button in the bottom left of the Interface Builder window — the Pin button — and add 0 (zero) space constraints from the top, left, bottom and right of the superview.

For the top margin constraint, make sure you set it from its superview and not from the top layout margin, as you want the map to go behind the navigation bar. Your Pin editor should look like this:

GoogleMaps_AddingMaps_09

Ensure that Constrain to layout margins is unchecked — this ensures that the map will fill all the available space. on the screen.

Click on Add 4 constraints to add the constraints to the map view. To update the frame, select the button on the right of the Pin button — the Resolve button — and select Update Frames.

Note: Need an Auto Layout refresher? Check out the Beginning Auto Layout tutorial on this site.

Your MapViewController scene should look like the following, where the grey area represents the GMSMapView:

GoogleMaps_AddingMaps_11

Before you build and run the project, add an IBOutlet for the MapView. To do that, bring up the Assistant Editor by selecting the second tab in the Editor toolbar:

GoogleMaps_AddingMaps_12

Select the MapView in Interface Builder, hold down the Ctrl key and drag a line from the MapView to MapViewController.swift, just above the mapCenterPinImage property. A popup will appear; set the connection type to Outlet and the name to mapView. Keep the Type as GMSMapView, and click Connect:

GoogleMaps_AddingMaps_13

This will create a GMSMapView property in MapViewController.swift and automatically hook it up to Interface Builder. The class and properties declarations in MapViewController.swift should look like the following:

class MapViewController: UIViewController, TypesTableViewControllerDelegate {
  @IBOutlet weak var mapView: GMSMapView!
  @IBOutlet weak var mapCenterPinImage: UIImageView!
  @IBOutlet weak var pinImageVerticalConstraint: NSLayoutConstraint!
  var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]

Build and run your project; you should see a Google Map showing half the world like so:

GoogleMaps_AddingMaps_14

In its default mode, the MapView displays as a Normal map, but you can give the user the option to choose Satellite or Hybrid views.
Open Main.storyboard, go to the Object Library and drag a UISegmentedControl onto the MapViewController’s Navigation Bar. Ensure the segmented control is selected, go to the Attributes Inspector — the third tab — and increase the number of segments to 3.

Double click on each of the segments to change their names to Normal, Satellite, and Hybrid respectively. Your MapViewController scene should now look like this:

GoogleMaps_AddingMaps_15

Add the following method to MapViewController.swift:

@IBAction func mapTypeSegmentPressed(sender: AnyObject) {
  let segmentedControl = sender as UISegmentedControl
  switch segmentedControl.selectedSegmentIndex {
  case 0:
      mapView.mapType = kGMSTypeNormal
    case 1:
      mapView.mapType = kGMSTypeSatellite
    case 2:
      mapView.mapType = kGMSTypeHybrid
    default:
      mapView.mapType = mapView.mapType
  }
}

In the code above you check the selected segment index and use a switch block to set the new mapType accordingly.

Head back to Main.storyboard, select the Assistant Editor and Ctrl+drag from the Segmented Control to the newly added method to hook it up.

Build and run your app again; toggle between the different map types and see what the different results look like:
GoogleMaps_AddingMaps_16

You’re now using the Google Maps iOS SDK in your app — but you can do more than show a basic map, right? :]

Getting the Location

Feed Me is all about finding places near the user, and you can’t do that without getting the user’s location.

To request the user’s location, open MapViewController.swift and at the top of the file, make the following changes:

// 1
class MapViewController: UIViewController, TypesTableViewControllerDelegate, CLLocationManagerDelegate {
  @IBOutlet weak var mapView: GMSMapView!
  @IBOutlet weak var mapCenterPinImage: UIImageView!
  @IBOutlet weak var pinImageVerticalConstraint: NSLayoutConstraint!
  var searchedTypes = ["bakery", "bar", "cafe", "grocery_or_supermarket", "restaurant"]
  //2
  let locationManager = CLLocationManager()
 
  override func viewDidLoad() {
    super.viewDidLoad()
    //3
    locationManager.delegate = self
    locationManager.requestWhenInUseAuthorization()
  }

Here’s what’s the code above does:

  1. Declares that MapViewController conforms to the CLLocationManagerDelegate protocol.
  2. Adds a constant property named locationManager and instantiates it with a CLLocationManager object.
  3. Makes the MapViewController the delegate of locationManager and requests access to the user’s location.

Next, open the Feed Me project at the top of the Project Navigator, go to the Info tab, select the first line and click the + icon to add a new row.

Enter NSLocationWhenInUseUsageDescription as the key, choose String for the type, and enter the following text as the value:
By accessing your location, this app can find you a good place to eat.

When done, it should look like this:

Screen Shot 2014-10-08 at 11.37.02 AM

Note: If you used CLLocationManager in previous iOS versions, the above will probably look new to you. Don’t worry, you haven’t been doing anything wrong. In iOS 8, Apple changed the way you request a user for their location. You now have to specifically request the permission, giving one of two options: requestWhenInUseAuthorization to get location updates while the app is in the foreground, and requestAlwaysAuthorization to get location updates while the app is in the background.

In addition, you need to explain why you need these permissions by adding the NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription keys to your info.plist. The value for these keys is displayed to the user when they are prompted for location permissions.

For more information, check out the CLLocationManager class documentation.

Build and run your app; once it loads you’ll be prompted with an alert, asking for location permissions. Tap on Allow:

Allow Locations

Now that you’ve seen how to request location permissions in iOS 8, you can use these granted permissions in your app.

Add the following two CLLocationManagerDelegate methods to MapViewController.swift:

  // 1
  func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
    // 2
    if status == .AuthorizedWhenInUse {
 
      // 3
      locationManager.startUpdatingLocation()
 
      //4
      mapView.myLocationEnabled = true
      mapView.settings.myLocationButton = true
    }
  }
 
  // 5
  func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
    if let location = locations.first as? CLLocation {
 
      // 6
      mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
 
      // 7
      locationManager.stopUpdatingLocation()
    }
  }

Taking each numbered comment in turn:

  1. You invoke CLLocationManagerDelegate when the user grants or revokes location permissions.
  2. Here you verify the user has granted you permission while the app is in use.
  3. Once permissions have been established, ask the location manager for updates on the user’s location.
  4. GMSMapView has two features concerning the user’s location: myLocationEnabled draws a light blue dot where the user is located, while myLocationButton adds a button to the map that centers the user’s location when tapped.
  5. CLLocationManagerDelegate executes when the location manager receives new location data.
  6. This updates the map’s camera to center around the user’s current location. The GMSCameraPosition class aggregates all camera position parameters and passes them to the map for display.
  7. Tell locationManager you’re no longer interested in updates; you don’t want to follow a user around as their initial location is enough for you to work with.

Build and run your project; you’ll see a map centering around your location. Scroll the map and tap the Locate button and the map will center back to your location like so:

GoogleMaps_Location_04

Implementing Geocoding

Now that you have the user’s location, it would be nice if you could show the street address of that location. Google has an object that does exactly that: GMSGeocoder. This takes a simple coordinate and returns a readable street address.

First, you’ll need to add some UI to present the address to the user.

Open Main.storyboard and add a UILabel to the MapViewController scene. Make sure you add the label to the MapViewController view, and not the GMSMapView.

New Label

Next, open the Attributes Inspector, and give the label the following attributes:

  • Set the text alignment to center.
  • Set the number of lines to 0. Surprisingly, this lets the label take up as many lines as it needs to fit the text. Go figure! :]
  • Set the background color to white with 85% opacity. This will give your app a nice effect by making the map slightly visible behind the label.

The label’s Attributes Inspector and the scene’s Object Tree should look like this when done:

GoogleMaps_Geocoding_01

GoogleMaps_Geocoding_06

Finally, add to the label left, bottom and right constraints of 0 as shown below:

GoogleMaps_Geocoding_02

This pins the label to the bottom of the screen and stretches it over the entire width of the screen. Update the frames and continue.

Your Storyboard scene should look like the following:

Storyboard Scene

Next, create an outlet for the label. Select the Assistant Editor, and Ctrl+drag from the label in the Document Outline to MapViewController.swift. Set the connection type to Outlet, the name to addressLabel and click Connect.

This adds a property to your MapViewController that you can use in your code:

@IBOutlet weak var addressLabel: UILabel!

Add the method below to MapViewController.swift:

func reverseGeocodeCoordinate(coordinate: CLLocationCoordinate2D) {
 
  // 1
  let geocoder = GMSGeocoder()
 
  // 2
  geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
    if let address = response?.firstResult() {
 
      // 3
      let lines = address.lines as [String]
      self.addressLabel.text = join("\n", lines)
 
      // 4
      UIView.animateWithDuration(0.25) {
        self.view.layoutIfNeeded()
      }
    }
  }
}

Once again, here’s what each commented section does:

  1. Creates a GMSGeocoder object to turn a latitude and longitude coordinate into a street address.
  2. Asks the geocoder to reverse geocode the coordinate passed to the method. It then verifies there is an address in the response of type GMSAddress. This is a model class for addresses returned by the GMSGeocoder.
  3. Sets the text of the address to the address returned by the geocoder.
  4. Once the address is set, animate the changes in the label’s intrinsic content size.

You’ll want to call this method every time the user changes their position on the map. To do so you’ll use the GMSMapView‘s delegate.

Change MapViewController‘s class declaration as follows:

class MapViewController: UIViewController, TypesTableViewControllerDelegate, CLLocationManagerDelegate, GMSMapViewDelegate

In the code above you declare that MapViewController conforms to the GMSMapViewDelegate protocol.

Next, add the following line of code to viewDidLoad:

mapView.delegate = self

This makes MapViewController the map view’s delegate.

Finally, add the following method to MapViewController.swift:

func mapView(mapView: GMSMapView!, idleAtCameraPosition position: GMSCameraPosition!) {
  reverseGeocodeCoordinate(position.target)
}

You call this method each time the map stops moving and settles in a new position, where you then make a call to reverse geocode the new position and update the addressLabel‘s text.

Build and run your app; you’ll see the address of your current location — real or simulated — pop up at the bottom of the screen:

GoogleMaps_Geocoding_03

Notice anything wrong with this picture?

Solution Inside SelectShow>

Fortunately, GMSMapView provides a very simple solution for this: padding. When padding is applied to the map, all of the visual elements will be placed according to that padding.

Head back to the reverseGeocodeCoordinate(), and make these changes to the animation block:

// 1
let labelHeight = self.addressLabel.intrinsicContentSize().height
self.mapView.padding = UIEdgeInsets(top: self.topLayoutGuide.length, left: 0, bottom: labelHeight, right: 0)
 
UIView.animateWithDuration(0.25) {
  //2
  self.pinImageVerticalConstraint.constant = ((labelHeight - self.topLayoutGuide.length) * 2)
  self.view.layoutIfNeeded()
}

This does two thing:

  1. Prior to the animation block, this adds top and bottom paddings to the map. the top padding equals the navigation bar’s height, while the bottom padding equals the label’s height.
  2. Updates the location pin’s position to match the map’s padding by adjusting it’s vertical layout constraint.

Build and run your app again; this time the Google logo and locate button will move to their new position once the label becomes visible:

GoogleMaps_Geocoding_04

Move the map around; you’ll notice that the address changes every time the map settles to a new position. However, this change happens very suddenly could be unsettling to your user. You’ll add another visual effect to dampen the address changing.

Add the following method to MapViewController.swift:

func mapView(mapView: GMSMapView!, willMove gesture: Bool) {
  addressLabel.lock()
}

You call the above method each time the map starts to move. It accepts a Bool that tells you if the movement originated from a user gesture, such as scrolling the map, or if the movement originated elsewhere, such as from code. You call the lock() on the addressLabel to give it a loading animation.

When there’s a lock(), there must also be an unlock(), so add that call to the top of the reverseGeocodeCoordinate closure:

func reverseGeocodeCoordinate(coordinate: CLLocationCoordinate2D) {
    let geocoder = GMSGeocoder()
    geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
 
      //Add this line
      self.addressLabel.unlock()
      if let address = response.firstResult() {
        let lines = address.lines as [String]
        self.addressLabel.text = join("\n", lines)
 
        let labelHeight = self.addressLabel.intrinsicContentSize().height
        self.mapView.padding = UIEdgeInsets(top: self.topLayoutGuide.length, left: 0, bottom: labelHeight, right: 0)
        UIView.animateWithDuration(0.25) {
          self.pinImageVerticalConstraint.constant = ((labelHeight - self.topLayoutGuide.length) * 2)
          self.view.layoutIfNeeded()
        }
      }
    }
  }
Note: For the full implementation of the lock() and unlock(), check out UIViewExtensions.swift.

Build and run your app; as you scroll the map you should see a loading animation on the address label like so:
GoogleMaps_Geocoding_05

Finding Something to Eat

Now that the map is set up and you have the user’s location in hand, it’s time to get this user fed!

You’ll use the Google Places API to search for places to eat and drink around the user’s location.

Note: For more information on the Google Places API, check out the Using the Google Places API With MapKit tutorial on this site. The GoogleDataProvider and GooglePlace classes that come with the starter project implement this API for the use of Feed Me.

Google Maps SDK provides you with the GMSMarker class to mark locations on a map. Each marker object holds a coordinate and an icon image and renders on the map when added.

For this app you’ll need some more info on each marker, so you’ll need to create a subclass of GMSMarker.

Create a new Cocoa Touch Class, name it PlaceMarker and make it a subclass of GMSMarker. Ensure you choose Swift as the language for this file.

Replace the contents of PlaceMarker.swift with the following:

class PlaceMarker: GMSMarker {
  // 1
  let place: GooglePlace
 
  // 2
  init(place: GooglePlace) {
    self.place = place
    super.init()
 
    position = place.coordinate
    icon = UIImage(named: place.placeType+"_pin")
    groundAnchor = CGPoint(x: 0.5, y: 1)
    appearAnimation = kGMSMarkerAnimationPop
  }
}

This is a relatively straightforward bit of code:

  1. Add a property of type GooglePlace to the PlaceMarker.
  2. Declare a new designated initializer that accepts a GooglePlace as its sole parameter and fully initializes a PlaceMarker with a position, icon image, anchor for the marker’s position and an appearance animation.

Head back to MapViewController.swift and add the following computed property that calculates the visible radius of the map:

var mapRadius: Double {
  get {
    let region = mapView.projection.visibleRegion()
    let center = mapView.camera.target
 
    let north = CLLocation(latitude: region.farLeft.latitude, longitude: center.longitude)
    let south = CLLocation(latitude: region.nearLeft.latitude, longitude: center.longitude)
    let west = CLLocation(latitude: center.latitude, longitude: region.farLeft.longitude)
    let east = CLLocation(latitude: center.latitude, longitude: region.farRight.longitude)
 
    let verticalDistance = north.distanceFromLocation(south)
    let horizontalDistance = west.distanceFromLocation(east)
    return max(horizontalDistance, verticalDistance)*0.5
  }
}

Above you use use the map’s projection to find the visible region of the map. A GMSProjection defines a mapping between coordinates on earth — CLLocationCoordinate2D — and coordinates in the map’s view — CGPoint.

You next create four CLLocation objects to represent the four basic directions. Since the height and width of the map view aren’t equal, you determine the maximum of of the horizontal and vertical distances of the visible region and return that value divided by 2.

Note: Computed properties don’t actually store a value, but instead provide a getter and an optional setter to retrieve and set other properties and values indirectly. In the above case the mapRadius property only provides a getter, and returns a calculated map radius.

Now, add another property to MapViewController.swift as follows:

let dataProvider = GoogleDataProvider()

You’ll use dataProvider to make calls to the Google Places API.

Add the following method to MapViewController.swift:

func fetchNearbyPlaces(coordinate: CLLocationCoordinate2D) {
  // 1
  mapView.clear()
  // 2
  dataProvider.fetchPlacesNearCoordinate(coordinate, radius:mapRadius, types: searchedTypes) { places in
    for place: GooglePlace in places {
      // 3
      let marker = PlaceMarker(place: place)
      // 4
      marker.map = self.mapView
    }
  }
}

Let’s go over what you just added:

  1. Clear the map from all current markers.
  2. Use dataProvider to query Google for nearby places around the mapRadius, filtered to the user’s selected types.
  3. Enumerate through the results returned in the completion closure and create a PlaceMarker for each result.
  4. Set the marker’s map. This line of code is what tells the map to render the marker.

Here’s the $64,000 question — when do you want to call this method?

First, the user can reasonably expect to see places nearby when the app launches.

Locate locationManage(_:didUpdateLocations:) and add the following line of code at the end, within the if let statement:

fetchNearbyPlaces(location.coordinate)

The user has the ability to change the types of places to display on the map, so you’ll need to update the search results if the selected types change.

Locate typesController(_:didSelectTypes:) and add the following line of code to the end:

fetchNearbyPlaces(mapView.camera.target)

Finally, you’ll need to give the user the option to fetch new places when their location changes.

Open Main.storyboard and drag a UIBarButtonItem from the Object Library to the left side of the MapViewController’s navigation bar. Select the newly added bar button and go to the Attributes Inspector. Change the Identifier to refresh, as shown in the screenshot below:

GoogleMaps_Places_01

Select the Assistant Editor and Ctrl+drag from the refresh button to MapViewController.swift. Choose Action and name the method refreshPlaces. Replace the contents of the newly added method with the following:

@IBAction func refreshPlaces(sender: AnyObject) {
  fetchNearbyPlaces(mapView.camera.target)
}

Build and run your project; you’ll see location pins popping up around the map. Change the search types in the TypesTableViewController and see how the results change:

GoogleMaps_Places_02

Note: If you do not see any of the locations appear, you can debug the issue by opening GoogleDataProvider.swift and underneath the line of code that serializes the json object, print the error to console by adding the following: println(json["error_message"]!)

All these markers sure add some color to the map, but they’re not much use without additional info to give the user some details on the pinned location.

Add the following method to MapViewController.swift:

func mapView(mapView: GMSMapView!, markerInfoContents marker: GMSMarker!) -> UIView! {
  // 1
  let placeMarker = marker as PlaceMarker
 
  // 2
  if let infoView = UIView.viewFromNibName("MarkerInfoView") as? MarkerInfoView {
    // 3
    infoView.nameLabel.text = placeMarker.place.name
 
    // 4
    if let photo = placeMarker.place.photo {
      infoView.placePhoto.image = photo
    } else {
      infoView.placePhoto.image = UIImage(named: "generic")
    }
 
    return infoView
  } else {
    return nil
  }
}

You call this method each time the user taps a marker on the map. If you receive a view, then it pops up above the marker. If nil is returned, nothing happens. How does that happen?

  1. You first cast the tapped marker to a PlaceMarker
  2. Next you create a MarkerInfoView from its nib. The MarkerInfoView class is a UIView subclass that comes with the starter project for this tutorial.
  3. Then you apply the place name to the nameLabel.
  4. Check if there’s a photo for the place. If so, add that photo to the info view. If not, add a generic photo instead.

Build and run your app; choose one of the markers and you’ll see the map center around the marker, which is the default behaviour when selecting markers. A small info window pops above the marker with the place details:

GoogleMaps_Places_03

Notice that when you select a marker, the location pin hovers above it. That doesn’t look too great.

To correct this, add the following method to MapViewController.swift:

func mapView(mapView: GMSMapView!, didTapMarker marker: GMSMarker!) -> Bool {
  mapCenterPinImage.fadeOut(0.25)
  return false
}

This method simply hides the location pin when a marker is tapped. The method returns false to indicate that you don’t want to override the default behavior — to center the map around the marker — when tapping a marker.

Obviously, the pin needs to re-appear at some point. Add the following to the end of mapViewWillMove:

if (gesture) {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
}

This checks if the movement originated from a user gesture; if so, it unhides the location pin using the fadeIn method. Setting the map’s selectedMarker to nil will remove the currently presented infoView.

Next, add the following method to MapViewController.swift:

func didTapMyLocationButtonForMapView(mapView: GMSMapView!) -> Bool {
  mapCenterPinImage.fadeIn(0.25)
  mapView.selectedMarker = nil
  return false
}

This method runs when the user taps the Locate button; the map will then center on the user’s location. Like the previous method, this fades in the location pin and clears the currently selected infoView. Returning false again indicates that it does not override the default behavior when tapping the button.

Build and run your app; select a marker and you’ll see the location pin fade out. Scrolling the map closes the infoView and brings the pin back:
GoogleMaps_Places_04

Using Directions

In the previous section of the tutorial, you learned one way to draw on the map – using the GMSMarker object. In this section, you’ll learn how to draw a line on the map using the GMSPath and the GMSPolyline objects.

A GMSPath is basically an array of CLLocationCoordinate2Ds. You pass the path to a GMSPolyline, which renders the line on the map. Polylines are a great way to present routes on the map, and you’ll be doing just that using the Google Directions API.

Note: In short, the Google Directions API returns directions from point A to point B according to the parameters you pass it. For example, you can request walking, driving, bicycling or transit directions. For more information, visit the Google Directions API documentation.

Time to draw some lines! Add the following method to MapViewController.swift:

func mapView(mapView: GMSMapView!, didTapInfoWindowOfMarker marker: GMSMarker!) {
  // 1
  let googleMarker = mapView.selectedMarker as PlaceMarker
 
  // 2
  dataProvider.fetchDirectionsFrom(mapView.myLocation.coordinate, to: googleMarker.place.coordinate) {optionalRoute in
    if let encodedRoute = optionalRoute {
      // 3
      let path = GMSPath(fromEncodedPath: encodedRoute)
      let line = GMSPolyline(path: path)
 
      // 4
      line.strokeWidth = 4.0
      line.tappable = true
      line.map = self.mapView
 
       // 5
      mapView.selectedMarker = nil
    }
  }
}

You invoke this method when the user taps the marker’s info view. That’s when you want to display the route.

  1. Cast the given marker to a PlaceMarker.
  2. Call the dataProvider‘s fetchDirections(_to:). This method takes two coordinates and a completion closure that handles an optional encoded route. This special String is an encoded representation of a coordinates array that is decoded when passed to a GMSPath.
  3. Create a GMSPatch from the encoded route and then create a GMSPolyline from the path.
  4. Set the GMSPolyline‘s width, make it tappable and set the map on which it should be displayed.
  5. Clear the map’s selected marker. This removes the currently presented info view.

Build and run your app; tap a marker, then tap its info view and you’ll see a line drawn on the map with the requested route:

GoogleMaps_Directions_01

The blue line color is a bit boring; change it to something more interesting by adding a computed property to MapViewController.swift as follows:

var randomLineColor: UIColor {
  get {
    let randomRed = CGFloat(drand48())
    let randomGreen = CGFloat(drand48())
    let randomBlue = CGFloat(drand48())
    return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
  }
}

This just returns a random color each time you call the property.

Head back to mapView didTapInfoWindowOfMarker and add the following line of code just after the line where you set the line width:

line.strokeColor = self.randomLineColor

Build and run your app again; this time you’ll get a different line color every time you ask for directions:

GoogleMaps_Directions_02

Where To Go From Here?

Here’s a link to the complete project from this tutorial.

Keep in mind that before you’re able to run this finished project, you will need to insert your API keys as you did at the beginning of this tutorial.

Our purpose here is not to convince you that Google Maps SDK is better than Apple’s own MapKit; however, here’s a few pros and cons of Google Maps:

Pros

  • Unlike MapKit, which updates once a year, the Google Maps SDK updates frequently and has already seen eight major updates since its release. Bugs are being fixed all the time,and with each new release the SDK becomes richer and more stable.
  • When developing cross platform iOS and Android apps, it’s often best to use the same mapping SDK for both platforms. Imagine you have a mapping app that needs to display a walking route on the map. While MapKit has its own solution for this problem, using Google Maps SDK allows you to use the Google Directions API’s encoded route, and receive identical results for both your iOS and Android apps.
  • Google Maps are often more detailed, especially outside the United States. For example, take a look at these two screenshots of central Moscow, one taken from a MapKit map and the other from a Google Maps map:

    Compare_Apple Compare_Google

    Cons

    • MapKit is native to iOS, which means it’s always synced with iOS. For example, Swift works with MapKit out of the box, while using Google Maps requires some adjustments and still lacks full support of the language. Being native also means set up is much easier.
    • The Google Maps SDK still lacks the stability that MapKit has. The SDK crashes more than it should which could scare off users and lead to bad App Store reviews.
    • MapKit has a much better integration with CoreLocation and CoreAnimation. The “Follow user location” mode is missing in Google Maps; as well, the ability to add advanced animations to annotations (MKAnnotation is represented by a UIView, while a GMSMarker is represented by a UIImage) can give your app an appealing touch that the Google Maps SDK just can’t.

    This tutorial only showed you the basics of what the Google Maps SDK can do. There’s much more to learn; you should definitely check out the full documentation for more cool features the SDK has to offer.

    Among the other things you can do with Google Maps are indoor maps, overlays, tile layers, Street View, and advanced integration with the Google Maps app. For brownie points, try to use some of these features to enhance the Feed Me app.

    For example, you could add a Street View for places the user wants to check out. Additionally, you can further explore the Google Places and Google directions APIs and apply a tighter integration of these two features with Feed Me.

    The Google Maps SDK provides many utility methods as part of the GMSGeometryUtils module. One of these methods is the GMSGeometryDistance C function, which returns a distance between two coordinates. Unfortunately, this method is marked as FOUNDATION_EXPORT OVERLOADABLE which is not supported by Swift and generates an error when used. We expect this to be fixed in future releases of the Google Maps SDK, so we’ve used the existing CLLocation methods for the time being.

    If you have any questions, tips, or just wanna show off your cool mapping app, feel free to post about it in the discussion below!

    Introduction to Google Maps iOS SDK in Swift is a post from: Ray Wenderlich

    The post Introduction to Google Maps iOS SDK in Swift appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 14: 3D Animations

Video Tutorial: iOS Animation with Swift Part 15: Pop Basic Animations


How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 1

$
0
0
Learn how to make a game like Space Invaders!

Learn how to make a game like Space Invaders!

Update note: This tutorial was updated for iOS 8 and Swift by Riccardo D’Antoni. Original tutorial by Joel Shapiro.

Space Invaders is one of the most important video games ever developed. Created by Tomohiro Nishikado and released in 1978 by Taito Corporation, it earned billions of dollars in revenue. It became a cultural icon, inspiring legions of non-geeks to take up video games as a hobby.

Space Invaders used to be played in big game cabinets in video arcades, chewing up our allowances one quarter at a time. When the Atari 2600 home video game console went to market, Space Invaders was the “killer app” that drove sales of Atari hardware.

In this tutorial, you’ll build an iOS version of Space Invaders, using Swift and Sprite Kit, Apple’s 2D game framework.

This tutorial assumes you are familiar with the basics of Swift and Sprite Kit. If you are completely new to Sprite Kit, you should go through our Sprite Kit tutorial for beginners first.

Also, you will need Xcode 6.1 (the latest version), an iPhone or iPod Touch running iOS 8 and an Apple developer account in order to get the most out of this tutorial. That is because you will be moving the ship in this game using the accelerometer, which is not present on the iOS simulator. If you don’t have an iOS 8 device or developer account, you can still complete the tutorial — you just won’t be able to move your ship.

Without further ado, let’s get ready to blast some aliens!

An original Space Invaders arcade cabinet

An original Space Invaders arcade cabinet

Getting Started

Apple provides an template named Game which is pretty useful if you want to create your next smash hit from scratch. However, in order to get you started quickly, download the starter project for this tutorial. It’s based on the Sprite Kit Game template and already has some of the more tedious work done for you.

Once you’ve downloaded and unzipped the project, open the project in Xcode and build and run. After the splash screen intro, you should see the following screen appear on your device or your simulator:

First run - invaders are already watching you

Creepy – the invaders are watching you! However, if you see the screen above, this means you’re ready to move forward.

The Role of GameScene

You’ll spend most of this tutorial filling out GameScene with your game code. Before you start coding, take a moment to consider the GameScene and take a look at how it’s organized (comments stripped):

import SpriteKit
import CoreMotion
 
class GameScene: SKScene {
 
  var contentCreated = false
 
  override func didMoveToView(view: SKView) {
    if (!contentCreated) {
      createContent()
      contentCreated = true
    }
  }
 
  func createContent() {
 
    let invader = SKSpriteNode(imageNamed: "InvaderA_00.png")
    invader.position = CGPoint(x: size.width/2, y: size.height/2)
    addChild(invader)
 
    backgroundColor = SKColor.blackColor()
  }
 
  override func update(currentTime: CFTimeInterval) {
  }
}

As you can see here, the game is initialized inside didMoveToView() to present a single sprite to the screen.

You might think the scene’s initializer, init(size:), would be the proper place to initialize the scene, but the scene may not be fully configured or scaled at the time its initializer runs. It’s better to create a scene’s content once the scene has been presented by a view, since at that point the environment in which the scene operates is ready to go.

First, comment out the lines that create the single invader in the center of the screen – you’ll add the invaders back later!

//let invader = SKSpriteNode(imageNamed: "InvaderA_00.png")
//invader.position = CGPoint(x: size.width/2, y: size.height/2)
//addChild(invader)

Now let’s add some new constants you’ll need for the game. Navigate just below Private GameScene Properties and add the following code:

//1
enum InvaderType {
  case A
  case B
  case C
}
 
//2
let kInvaderSize = CGSize(width:24, height:16)
let kInvaderGridSpacing = CGSize(width:12, height:12)
let kInvaderRowCount = 6
let kInvaderColCount = 6
 
// 3
let kInvaderName = "invader"

The above type definition and constant definitions take care of the following tasks:

  1. Define the possible types of invader enemies. You can use this in switch statements later when you need to do things such as displaying different sprite images for each enemy type.
  2. Define the size of the invaders and that they’ll be laid out in a grid of rows and columns on the screen.
  3. Define a name you’ll use to identify invaders when searching for them in the scene.
Note: It’s good practice to define constants like this rather than using raw numbers like 6 (also known as “magic numbers”) or raw strings like "invader" (“magic strings”) that are prone to typos.

Imagine mistyping "Invader" where you meant "invader" and spending hours debugging to find that a simple typo messed everything up. Using constants like kInvaderRowCount and kInvaderName prevents frustrating bugs — and makes it clear to other programmers what these constant values mean.

All right, time to make some invaders! Add the following method to GameScene.swift directly after createContent():

func makeInvaderOfType(invaderType: InvaderType) -> (SKNode) {
 
  // 1
  var invaderColor: SKColor
 
  switch(invaderType) {
  case .A:
    invaderColor = SKColor.redColor()
  case .B:
    invaderColor = SKColor.greenColor()
  case .C:
    invaderColor = SKColor.blueColor()
  default:
    invaderColor = SKColor.blueColor()
  }
 
  // 2
  let invader = SKSpriteNode(color: invaderColor, size: kInvaderSize)
  invader.name = kInvaderName
 
  return invader
}

You take the following actions in the above code:

  1. Use the invaderType parameter to determine the color of the invader.
  2. Call the handy convenience initializer SKSpriteNode(color:size:) to allocate and initialize a sprite that renders as a rectangle of the given color invaderColor with size kInvaderSize.

Okay, so a colored block is not the most menacing enemy imaginable. It may be tempting to design invader sprite images and dream about all the cool ways you can animate them, but the best approach is to focus on the game logic first, and worry about aesthetics later.

Adding makeInvaderOfType() isn’t quite enough to display the invaders on the screen. You’ll need something to invoke this method and place the newly created sprites in the scene.

Still in GameScene.swift add the following method directly after makeInvaderOfType():

func setupInvaders() {
 
  // 1
  let baseOrigin = CGPoint(x:size.width / 3, y:180)
  for var row = 1; row <= kInvaderRowCount; row++ {
 
    // 2
    var invaderType: InvaderType
    if row % 3 == 0 {
      invaderType = .A
    } else if row % 3 == 1 {
      invaderType = .B
    } else {
      invaderType = .C
    }
 
    // 3
    let invaderPositionY = CGFloat(row) * (kInvaderSize.height * 2) + baseOrigin.y
    var invaderPosition = CGPoint(x:baseOrigin.x, y:invaderPositionY)
 
    // 4
    for var col = 1; col <= kInvaderColCount; col++ {
 
      // 5
      var invader = makeInvaderOfType(invaderType)
      invader.position = invaderPosition
      addChild(invader)
 
      // 6
      invaderPosition = CGPoint(x: invaderPosition.x + kInvaderSize.width + kInvaderGridSpacing.width, y: invaderPositionY)
    }
  }
}

The above method lays out invaders in a grid of rows and columns. Each row contains only a single type of invader. The logic looks complicated, but if you break it down, it makes perfect sense:

  1. Declare and set the baseOrigin constant and loop over the rows.
  2. Choose a single InvaderType for all invaders in this row based on the row number.
  3. Do some math to figure out where the first invader in this row should be positioned.
  4. Loop over the columns.
  5. Create an invader for the current row and column and add it to the scene.
  6. Update the invaderPosition so that it’s correct for the next invader.

Now, you just need to display the invaders on the screen. Add setupInvaders() just above the background color setup in createContent():

setupInvaders()

Build and run your app; you should see a bunch of invaders on the screen, as shown below:

00_Invaders

The rectangular alien overlords are here! :]

Create Your Valiant Ship

With those evil invaders on screen, your mighty ship can’t be far behind. Just as you did for the invaders, you first need to define a few constants.

Add the following code immediately below the kInvaderName line:

let kShipSize = CGSize(width:30, height:16)
let kShipName = "ship"

kShipSize stores the size of the ship, and kShipName stores the name you will set on the sprite node, so you can easily look it up later.

Next, add the following two methods just after setupInvaders():

func setupShip() {
  // 1
  let ship = makeShip()
 
  // 2
  ship.position = CGPoint(x:size.width / 2.0, y:kShipSize.height / 2.0)
  addChild(ship)
}
 
func makeShip() -> SKNode {
  let ship = SKSpriteNode(color: SKColor.greenColor(), size: kShipSize)
  ship.name = kShipName
  return ship
}

Here’s the interesting bits of logic in the two methods above:

  1. Create a ship using makeShip(). You can easily reuse makeShip() later if you need to create another ship (e.g. if the current ship gets destroyed by an invader and the player has “lives” left).
  2. Place the ship on the screen. In Sprite Kit, the origin is at the lower left corner of the screen. The anchorPoint is based on a unit square with (0, 0) at the lower left of the sprite’s area and (1, 1) at its top right. Since SKSpriteNode has a default anchorPoint of (0.5, 0.5), i.e., its center, the ship’s position is the position of its center. Positioning the ship at kShipSize.height / 2.0 means that half of the ship’s height will protrude below its position and half above. If you check the math, you’ll see that the ship’s bottom aligns exactly with the bottom of the scene.

To display your ship on the screen, add the following line to the end of createContent():

setupShip()

Build and run your app; and you should see your ship arrive on the scene, as below:

01_Ship

Fear not, citizens of Earth! Your trusty spaceship is here to save the day!

Adding the Heads Up Display (HUD)

It wouldn’t be much fun to play Space Invaders if you didn’t keep score, would it? You’re going to add a heads-up display (or HUD) to your game. As a star pilot defending Earth, your performance is being monitored by your commanding officers. They’re interested in both your “kills” (score) and “battle readiness” (health).

Add the following constants at the top of GameScene.swift, just below kShipName:

let kScoreHudName = "scoreHud"
let kHealthHudName = "healthHud"

Now, add your HUD by inserting the following method right after makeShip():

func setupHud() {
  // 1
  let scoreLabel = SKLabelNode(fontNamed: "Courier")
  scoreLabel.name = kScoreHudName
  scoreLabel.fontSize = 25
 
  // 2
  scoreLabel.fontColor = SKColor.greenColor()
  scoreLabel.text = NSString(format: "Score: %04u", 0)
 
  // 3
  println(size.height)
  scoreLabel.position = CGPoint(x: frame.size.width / 2, y: size.height - (40 + scoreLabel.frame.size.height/2))
  addChild(scoreLabel)
 
  // 4
  let healthLabel = SKLabelNode(fontNamed: "Courier")
  healthLabel.name = kHealthHudName
  healthLabel.fontSize = 25
 
  // 5
  healthLabel.fontColor = SKColor.redColor()
  healthLabel.text = NSString(format: "Health: %.1f%%", 100.0)
 
  // 6
  healthLabel.position = CGPoint(x: frame.size.width / 2, y: size.height - (80 + healthLabel.frame.size.height/2))
  addChild(healthLabel)
}

This is boilerplate code for creating and adding text labels to a scene. The relevant bits are as follows:

  1. Give the score label a name so you can find it later when you need to update the displayed score.
  2. Color the score label green.
  3. Position the score label.
  4. Give the health label a name so you can reference it later when you need to update the displayed health.
  5. Color the health label red; the red and green indicators are common colors for these indicators in games, and they’re easy to differentiate in the middle of furious gameplay.
  6. Position the health below the score label.

Add the following line below setupShip() in createContent() to call the setup method for your HUD:

setupHud()

Build and run your app; you should see the HUD in all of its red and green glory on your screen as shown below:

02_Hud

Invaders? Check. Ship? Check. HUD? Check. Now all you need is a little dynamic action to tie it all together!

Adding Motion to the Invaders

To render your game onto the screen, Sprite Kit uses a game loop which searches endlessly for state changes that require on-screen elements to be updated. The game loop does several things, but you’ll be interested in the mechanisms that update your scene. You do this by overriding the update() method, which you’ll find as a stub in your GameScene.swift file.

When your game is running smoothly and renders 60 frames-per-second (iOS devices are hardware-locked to a max of 60 fps), update() will be called 60 times per second. This is where you modify the state of your scene, such as altering scores, removing dead invader sprites, or moving your ship around…

You’ll use update() to make your invaders move across and down the screen. Each time Sprite Kit invokes update(), it’s asking you “Did your scene change?”, “Did your scene change?”… It’s your job to answer that question — and you’ll write some code to do just that.

Insert the following code at the top of GameScene.swift, just above the definition of the InvaderType enum:

enum InvaderMovementDirection {
  case Right
  case Left
  case DownThenRight
  case DownThenLeft
  case None
}

Invaders move in a fixed pattern: right, right, down, left, left, down, right, right, … so you’ll use the InvaderMovementDirection type to track the invaders’ progress through this pattern. For example, InvaderMovementDirection.Right means the invaders are in the right, right portion of their pattern.

Next, insert the following properties just below the existing property for contentCreated:

// 1
var invaderMovementDirection: InvaderMovementDirection = .Right
// 2
var timeOfLastMove: CFTimeInterval = 0.0
// 3
let timePerMove: CFTimeInterval = 1.0

This setup code initializes invader movement as follows:

  1. Invaders begin by moving to the right.
  2. Invaders haven’t moved yet, so set the time to zero.
  3. Invaders take 1 second for each move. Each step left, right or down takes 1 second.

Now, you’re ready to make the invaders move. Add the following code just below // Scene Update Helpers:

func moveInvadersForUpdate(currentTime: CFTimeInterval) {
 
  // 1
  if (currentTime - timeOfLastMove < timePerMove) {
    return
  }
 
  // 2
  enumerateChildNodesWithName(kInvaderName, usingBlock: {
    (node: SKNode!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in
 
    switch self.invaderMovementDirection {
    case .Right:
      node.position = CGPoint(x: node.position.x + 10, y: node.position.y)
    case .Left:
      node.position = CGPoint(x: node.position.x - 10, y: node.position.y)
    case .DownThenLeft, .DownThenRight:
      node.position = CGPoint(x: node.position.x, y: node.position.y - 10)
    case .None:
      break
    default:
      break
    }
 
    // 3
    self.timeOfLastMove = currentTime
  })
}

Here’s a breakdown of the code above, comment by comment:

  1. If it’s not yet time to move, then exit the method. moveInvadersForUpdate() is invoked 60 times per second, but you don’t want the invaders to move that often since the movement would be too fast for a normal person to see.
  2. Recall that your scene holds all of the invaders as child nodes; you added them to the scene using addChild() in setupInvaders() identifying each invader by its name property. Invoking enumerateChildNodesWithName() only loops over the invaders because they’re named kInvaderName; this makes the loop skip your ship and the HUDs. The guts of the block moves the invaders 10 pixels either right, left or down depending on the value of invaderMovementDirection.
  3. Record that you just moved the invaders, so that the next time this method is invoked (1/60th of a second from now), the invaders won’t move again till the set time period of one second has elapsed.

To make your invaders move, add the following to update():

moveInvadersForUpdate(currentTime)

Build and run your app; you should see your invaders slowly walk their way to the right:

03_Moving

Hmmm, what happened? Why did the invaders disappear? Maybe the invaders aren’t as menacing as you thought!

The invaders don’t yet know that they need to move down and change their direction once they hit the side of the playing field. Guess you’ll need to help those invaders find their way!

A Brief Note on Swift’s Closures

In moveInvadersForUpdate() you used the method enumerateChildNodesWithName to enumerate through all of the space invaders:

enumerateChildNodesWithName(kInvaderName, usingBlock: {
  (node: SKNode!, stop: UnsafeMutablePointer<ObjCBool>) -> Void in 
    ...
})

Thanks to Swift’s type inference, this statement can be simplified as follows:

enumerateChildNodesWithName(kInvaderName, usingBlock: {
  node, stop in 
    ...
})

Or even better, you can use trailing closure syntax:

enumerateChildNodesWithName(kInvaderName) {
  node, stop in 
    ...
}

Change your call to enumerateChildNoesWithName() to this shorter form. From here on out, we’ll use this syntax as it’s more concise.

Note: If you’re confused about this syntax, check Apple’s Swift Programming Book or our book Swift by Tutorials for more details.

Controlling the Invaders’ Direction

Adding the following code just after // Invader Movement Helpers:

func determineInvaderMovementDirection() {
 
  // 1
  var proposedMovementDirection: InvaderMovementDirection = invaderMovementDirection
 
  // 2
  enumerateChildNodesWithName(kInvaderName) { node, stop in
    switch self.invaderMovementDirection {
    case .Right:
      //3
      if (CGRectGetMaxX(node.frame) >= node.scene!.size.width - 1.0) {
        proposedMovementDirection = .DownThenLeft
        stop.memory = true
      }
    case .Left:
      //4
      if (CGRectGetMinX(node.frame) <= 1.0) {
        proposedMovementDirection = .DownThenRight
 
        stop.memory = true
      }
    case .DownThenLeft:
      //5
      proposedMovementDirection = .Left
      stop.memory = true
    case .DownThenRight:
      //6
      proposedMovementDirection = .Right
      stop.memory = true
    default:
      break
    }
  }
 
  //7
  if (proposedMovementDirection != invaderMovementDirection) {
    invaderMovementDirection = proposedMovementDirection
  }
}

Here’s what’s going on in the above code:

  1. Here you keep a reference to the current invaderMovementDirection so that you can modify it in //2.
  2. Loop over all the invaders in the scene and invoke the block with the invader as an argument.
  3. If the invader’s right edge is within 1 point of the right edge of the scene, it’s about to move offscreen. Set proposedMovementDirection so that the invaders move down then left. You compare the invader’s frame (the frame that contains its content in the scene’s coordinate system) with the scene width. Since the scene has an anchorPoint of (0, 0) by default, and is scaled to fill its parent view, this comparison ensures you’re testing against the view’s edges.
  4. If the invader’s left edge is within 1 point of the left edge of the scene, it’s about to move offscreen. Set proposedMovementDirection so that invaders move down then right.
  5. If invaders are moving down then left, they’ve already moved down at this point, so they should now move left. How this works will become more obvious when you integrate determineInvaderMovementDirection with moveInvadersForUpdate().
  6. If the invaders are moving down then right, they’ve already moved down at this point, so they should now move right.
  7. If the proposed invader movement direction is different than the current invader movement direction, update the current direction to the proposed direction.

Add the following code to determineInvaderMovementDirection() within moveInvadersForUpdate(), immediately after the conditional check of timeOfLastMove:

determineInvaderMovementDirection()

Why is it important that you add the invocation of determineInvaderMovementDirection() only after the check on timeOfLastMove? That’s because you want the invader movement direction to change only when the invaders are actually moving. Invaders only move when the check on timeOfLastMove passes — i.e., the conditional expression is true.

What would happen if you added the new line of code above as the very first line of code in moveInvadersForUpdate(currentTime: CFTimeInterval)? If you did that, then there would be two bugs:

  • You’d be trying to update the movement direction way too often — 60 times per second — when you know it can only change at most once per second.
  • The invaders would never move down, as the state transition from DownThenLeft to Left would occur without an invader movement in between. The next invocation of moveInvadersForUpdate() that passed the check on timeOfLastMove would be executed with Left and would keep moving the invaders left, skipping the down move. A similar bug would exist for DownThenRight and Right.

Build and run your app; you’ll see the invaders moving as expected across and down the screen:

SpaceInvaders

Note: You might have noticed that the invaders’ movement is jerky. That’s a consequence of your code only moving invaders once per second — and moving them a decent distance at that. But the movement in the original game was jerky, so keeping this feature helps your game seem more authentic.

Adding Motion to your Ship

Good news: your supervisors can see the invaders moving now and have decided that your ship needs a propulsion system! To be effective, any good propulsion system needs a good control system. In other words, how do you, the ship’s pilot, tell the ship’s propulsion system what to do?

The important thing to remember about mobile games is the following: mobile games are not desktop/arcade games and desktop/arcade controls don’t port well to mobile.

In a desktop or arcade version of Space Invaders, you’d have a physical joystick and fire button to move your ship and shoot invaders. Such is not the case on a mobile device such as an iPhone or iPad.

Some games attempt to use virtual joysticks or virtual D-pads but these rarely work well, in my opinion.

Think about how you use your iPhone most often: holding it with one hand. That leaves only one hand to tap/swipe/gesture on the screen.

Keeping the ergonomics of holding your iPhone with one hand in mind, consider several potential control schemes for moving your ship and firing your laser cannon:

1) Single-tap to move, double-tap to fire

Suppose you single-tapped on the left side of the ship to move it left, single-tapped on the right of the ship to move it right, and double-tapped to make it fire. This wouldn’t work well for a couple of reasons.

First, recognizing both single-taps and double-taps in the same view requires you to delay recognition of the single-tap until the double-tap fails or times out. When you’re furiously tapping the screen, this delay will make the controls unacceptably laggy. Second, single-taps and double-taps might sometimes get confused, both by you, the pilot, and by the code. Third, the ship movement single-taps won’t work well when your ship is near the extreme left- or right-edge of the screen. Scratch that control scheme!

2) Swipe to move, single-tap to fire

This approach is a little better. Single-tapping to fire your laser cannon makes sense as both are discrete actions: one tap equals one blast from your canon. It’s intuitive. But what about using swipes to move your ship?

This won’t work because swipes are considered a discrete gesture. In other words, either you swiped or you didn’t. Using the length of a swipe to proportionally control the amount of left or right thrust applied to your ship breaks your user’s mental model of what swipes mean and the way they function. In all other apps, swipes are discrete and the length of a swipe is not considered meaningful. Scratch this control scheme as well.

3) Tilt your device left/right to move, single-tap to fire

It’s already been established that a single-tap to fire works well. But what about tilting your device left and right to move your ship left and right? This is your best option, as you’re already holding your iPhone in the palm of your hand and tilting your device to either side merely requires you to twist your wrist a bit. You have a winner!

Now that you’ve settled on the control scheme, you’ll first tackle tilting your device to move your ship.

Controlling Ship Movements with Device Motion

You might be familiar with UIAccelerometer, which has been available since iOS 2.0 for detecting device tilt. However, UIAccelerometer was deprecated in iOS 5.0, so iOS 8 apps should use CMMotionManager, which is part of Apple’s CoreMotion framework.

The CoreMotion library has already been added to the starter project, so there’s no need for you to add it.

Your code can retrieve accelerometer data from CMMotionManager in two different ways:

  1. Pushing accelerometer data to your code: In this scenario, you provide CMMotionManager with a block that it calls regularly with accelerometer data. This doesn’t fit well with your scene’s update() method that ticks at regular intervals of 1/60th of a second. You only want to sample accelerometer data during those ticks — and those ticks likely won’t line up with the moment that CMMotionManager decides to push data to your code.
  2. Pulling accelerometer data from your code: In this scenario, you call CMMotionManager and ask it for data when you need it. Placing these calls inside your scene’s update() method aligns nicely with the ticks of your system. You’ll be sampling accelerometer data 60 times per second, so there’s no need to worry about lag.

Your app should only use a single instance of CMMotionManager to ensure you get the most reliable data. To that effect, declare and initialize the following property at the top of GameScene:

let motionManager: CMMotionManager = CMMotionManager()

Now, add the following code to didMoveToView(), right after the contentCreated = true line:

motionManager.startAccelerometerUpdates()

This new code kicks off the production of accelerometer data. At this point, you can use the motion manager and its accelerometer data to control your ship’s movement.

Add the following method just below moveInvadersForUpdate():

func processUserMotionForUpdate(currentTime: CFTimeInterval) {
 
  // 1
  let ship = childNodeWithName(kShipName) as SKSpriteNode
 
  // 2
  if let data = motionManager.accelerometerData {
 
    // 3
    if (fabs(data.acceleration.x) > 0.2) {
 
      // 4 How do you move the ship?
      println("How do you move the ship: \(ship)")
 
    }
  }
}

Dissecting this method, you’ll find the following:

  1. Get the ship from the scene so you can move it.
  2. Get the accelerometer data from the motion manager. It is an Optional, that is a variable that can hold either a value or no value. The if let data statement allows to check if there is a value in accelerometerData, if is the case assign it to the constant data in order to use it safely within the if’s scope.
  3. If your device is oriented with the screen facing up and the home button at the bottom, then tilting the device to the right produces data.acceleration.x > 0, whereas tilting it to the left produces data.acceleration.x < 0. The check against 0.2 means that the device will be considered perfectly flat/no thrust (technically data.acceleration.x == 0) as long as it's close enough to zero (data.acceleration.x in the range [-0.2, 0.2]). There's nothing special about 0.2, it just seemed to work well for me. Little tricks like this will make your control system more reliable and less frustrating for users.
  4. Hmmm, how do you actually use data.acceleration.x to move the ship? You want small values to move the ship a little and large values to move the ship a lot. The answer is — physics, which you'll cover in the next section!

Translating Motion Controls into Movement via Physics

Sprite Kit has a powerful built-in physics system based on Box 2D that can simulate a wide range of physics like forces, translation, rotation, collisions, and contact detection. Each SKNode, and thus each SKScene and SKSpriteNode, has an SKPhysicsBody attached to it. This SKPhysicsBody represents the node in the physics simulation.

Add the following code right before the final return ship line in makeShip():

// 1
ship.physicsBody = SKPhysicsBody(rectangleOfSize: ship.frame.size)
 
// 2
ship.physicsBody!.dynamic = true
 
// 3
ship.physicsBody!.affectedByGravity = false
 
// 4
ship.physicsBody!.mass = 0.02

Taking each comment in turn, you'll see the following:

  1. Create a rectangular physics body the same size as the ship.
  2. Make the shape dynamic; this makes it subject to things such as collisions and other outside forces.
  3. You don't want the ship to drop off the bottom of the screen, so you indicate that it's not affected by gravity.
  4. Give the ship an arbitrary mass so that its movement feels natural.

Now replace the println statement in processUserMotionForUpdate (right after comment //4) with the following:

ship.physicsBody!.applyForce(CGVectorMake(40.0 * CGFloat(data.acceleration.x), 0))

The new code applies a force to the ship's physics body in the same direction as data.acceleration.x. The number 40.0 is an arbitrary value to make the ship's motion feel natural.

Finally, add the following line to the top of update():

processUserMotionForUpdate(currentTime)

Your new processUserMotionForUpdate now gets called 60 times per second as the scene updates.

Note: If you've been testing your code on simulator up till now, this would be the time to switch to your device. You won't be able to test the tilt code unless you are running the game on an actual device.

Build and run your game and try tilting your device left or right; Your ship will fly off the side of the screen, lost in the deep, dark reaches of space. If you tilt hard and long enough in the opposite direction, you might get your ship to come flying back the other way. But at present, the controls are way too flaky and sensitive. You'll never kill any invaders like this!

An easy and reliable way to prevent things from escaping the bounds of your screen during a physics simulation is to build what's called an edge loop around the boundary of your screen. An edge loop is a physics body that has no volume or mass but can still collide with your ship. Think of it as an infinitely-thin wall around your scene.

Since your GameScene is a kind of SKNode, you can give it its own physics body to create the edge loop.

Add the following code to createContent() right before the setupInvaders() line:

physicsBody = SKPhysicsBody(edgeLoopFromRect: frame)

The new code adds the physics body to your scene.

Build and run your game once more and try tilting your device to move your ship, as below:

coremotion

What do you see? If you tilt your device far enough to one side, your ship will collide with the edge of the screen. It no longer flies off the edge of the screen. Problem solved!

Depending on the ship's momentum,you may also see the ship bouncing off the edge of the screen, instead of just stopping there. This is an added bonus that comes for free from Sprite Kit's physics engine — it's a property called restitution. Not only does it look cool, but it is what's known as an affordance since bouncing the ship back towards the center of the screen clearly communicates to the user that the edge of the screen is a boundary that cannot be crossed.

Where to Go From Here?

Here is the example project for the game up to this point.

So far, you've created invaders, your ship, and a Heads Up Display (HUD) and drawn them on-screen. You've also coded logic to make the invaders move automatically and to make your ship move as you tilt your device.

In part two of this tutorial, you'll add firing actions to your ship as well as the invaders, along with some collision detection so you'll know when you've hit the invaders — and vice versa! You'll also polish your game by adding both sound effects as well as realistic images to replace the colored rectangles that currently serve as placeholders for invaders and your ship.

In the meantime, if you have any questions or comments, please feel free to join in the discussions below!

How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 1 is a post from: Ray Wenderlich

The post How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 1 appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 16: Pop Decay Animation

How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 2

$
0
0
Learn how to make a game like Space Invaders!

Learn how to make a game like Space Invaders!

Update note: This tutorial was updated for iOS 8 and Swift by Riccardo D’Antoni. Original tutorial by Joel Shapiro.

Welcome back to our 2-part Sprite Kit tutorial that teaches you how to make a game like Space Invaders!

In the first part, you created the foundation of the game. So far, you’ve added the invaders, your ship, and a Heads Up Display (HUD) to your game. You also coded the logic to make the invaders move automatically and to make your ship move as you tilted your device.

In this second and final part, you’ll add the ability for your ship and the aliens to fire on each other and blow each other up! You’ll also polish your game by adding sound effects and realistic images to replace the colored rectangles that currently serve as place holders for the invaders and your ship.

This tutorial picks up where the first part left off. If you don’t have the project already, you can download the example project where we left things off.

All right, it’s time to blow up some invaders!

Making Your Ship Fire its Laser Cannon

First, think about how you want your scene to fire the ship’s laser cannon. You decided to use single-taps to fire the cannon. But how should you detect these single taps?

You have two obvious choices:

  1. UITapGestureRecognizer – Create one and attach it to your scene’s view.
  2. touchesEnded(_:,withEvent:) – Your scene is a subclass of UIResponder; therefore, you could use this to detect touches directly.

The second approach is the best choice in this situation: touchesEnded(). The first approach gets a bit tricky when you need to detect and handle touches differently in the various scene nodes of your game, since you can only specify a single callback selector for the UITapGestureRecognizer on the scene’s view. The extra work to get this working properly just isn’t worth it in this simple case.

Since all SKNode nodes (including SKScene) can handle touches directly via touchesEnded(), the second choice is a much more natural approach to handling node-specific touches — and will pay off when you develop games with more complex tap handling.

Now that you’re going to detect user taps in your scene’s touchesEnded() method, what should you do inside that method?

Taps can happen at any point during the gameplay. Contrast that with the way your scene changes: — at discrete intervals from within the update() method. So how can you save up taps detected at any time in touchesEnded() and process them later in update() when it’s invoked by the Sprite Kit game loop?

The answer is a queue! You’re going to use a simple Array to store your taps in a FIFO (First In First Out) queue.

Add the following property at the top of GameScene.swift in order to initializes the tap queue to an empty array:

var tapQueue: Array<Int> = []

Now add the following lines to didMoveToView() right after the motionManager.startAccelerometerUpdates() line:

userInteractionEnabled = true

The above code ensures that user interactions are enabled for the scene so it can receive tap events.

Now, add the following code right after // User Tap Helpers:

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
  // Intentional no-op
}
 
override func touchesMoved(touches: NSSet, withEvent event: UIEvent)  {
  // Intentional no-op
}
 
override func touchesCancelled(touches: NSSet, withEvent event: UIEvent) {
  // Intentional no-op
}
 
override func touchesEnded(touches: NSSet, withEvent event: UIEvent)  {
 
  if let touch : AnyObject = touches.anyObject() {
 
    if (touch.tapCount == 1) {
 
      // add a tap to the queue
      self.tapQueue.append(1)
    }
  }
}

The first three methods are just empty stubs; they’re added because Apple suggests doing so when you override touchesEnded() without calling super().

The touchesEnded() method itself is fairly simple. It just adds an entry to the queue. You don’t need a custom class to store the tap in the queue since all you need to know is that a tap occurred. Therefore, you use the integer 1 as a mnemonic for single tap.

Since you know that the invaders will also eventually fire bullets at your ship, add the following enum to the top of the class:

enum BulletType {
  case ShipFiredBulletType
  case InvaderFiredBulletType
}

You’re going to use BulletType to share the same bullet code for both invaders and your ship. It appears that you and the invaders shop at the same ammunition stores! :]

Next, add the following properties:

let kShipFiredBulletName = "shipFiredBullet"
let kInvaderFiredBulletName = "invaderFiredBullet"
let kBulletSize = CGSizeMake(4, 8)

Now, add the following method at the end of the “Scene Setup and Content Creation” section:

func makeBulletOfType(bulletType: BulletType) -> SKNode! {
 
  var bullet: SKNode!
 
  switch (bulletType) {
  case .ShipFiredBulletType:
    bullet = SKSpriteNode(color: SKColor.greenColor(), size: kBulletSize)
    bullet.name = kShipFiredBulletName
  case .InvaderFiredBulletType:
    bullet = SKSpriteNode(color: SKColor.magentaColor(), size: kBulletSize)
    bullet.name = kInvaderFiredBulletName
    break;
  default:
    bullet = nil
  }
 
  return bullet
}

This method is relatively straightforward: it simply creates a rectangular colored sprite to represent a bullet and sets the name of the bullet so you can find it later in your scene.

Now, add the following methods to the // Bullet Helpers section:

func fireBullet(bullet: SKNode, toDestination destination:CGPoint, withDuration duration:CFTimeInterval, andSoundFileName soundName: String) {
 
  // 1
  let bulletAction = SKAction.sequence([SKAction.moveTo(destination, duration: duration), SKAction.waitForDuration(3.0/60.0), SKAction.removeFromParent()])
 
  // 2
  let soundAction = SKAction.playSoundFileNamed(soundName, waitForCompletion: true)
 
  // 3
  bullet.runAction(SKAction.group([bulletAction, soundAction]))
 
  // 4
  self.addChild(bullet)
}
 
func fireShipBullets() {
 
  let existingBullet = self.childNodeWithName(kShipFiredBulletName)
 
  // 1
  if existingBullet == nil {
 
    if let ship = self.childNodeWithName(kShipName) {
 
      if let bullet = self.makeBulletOfType(.ShipFiredBulletType) {
 
        // 2
        bullet.position =
          CGPointMake(ship.position.x, ship.position.y + ship.frame.size.height - bullet.frame.size.height / 2)
 
        // 3
        let bulletDestination = CGPointMake(ship.position.x, self.frame.size.height + bullet.frame.size.height / 2)
 
        // 4
        self.fireBullet(bullet, toDestination: bulletDestination, withDuration: 1.0, andSoundFileName: "ShipBullet.wav")
 
      }
    }
  }
}

Going through the code in fireBullet() step-by-step, you do the following:

  1. Create an SKAction that moves the bullet to the desired destination and then removes it from the scene. This sequence executes the individual actions consecutively — the next action only takes place after the previous action has completed. Hence the bullet is removed from the scene only after it has been moved.
  2. Play the desired sound to signal that the bullet was fired. All sounds are included in the starter project and iOS knows how to find and load them.
  3. Move the bullet and play the sound at the same time by putting them in the same group. A group runs its actions in parallel, not sequentially.
  4. Fire the bullet by adding it to the scene. This makes it appear onscreen and starts the actions.

Here’s what you do in fireShipBullets():

  1. Only fire a bullet if there isn’t one currently on-screen. It’s a laser cannon, not a laser machine gun — it takes time to reload!
  2. Set the bullet’s position so that it comes out of the top of the ship.
  3. Set the bullet’s destination to be just off the top of the screen. Since the x coordinate is the same as that of the bullet’s position, the bullet will fly straight up.
  4. Fire the bullet!

The decision in //1 to only allow one ship bullet on-screen at the same time is a gameplay decision, not a technical necessity. If your ship can fire thousands of bullets per minute, Space Invaders would be too easy. Part of the fun of your game is choosing your shots wisely and timing them to collide with invaders.

Your laser cannon is almost ready to fire!

Add the following to the Scene Update Helpers section:

func processUserTapsForUpdate(currentTime: CFTimeInterval) {
  // 1
  for tapCount in self.tapQueue {
    if tapCount == 1 {
      // 2
      self.fireShipBullets()
    }
    // 3
    self.tapQueue.removeAtIndex(0)
  }
}

Let’s review the above code:

  1. Loop over your tapQueue.
  2. If the queue entry is a single-tap, handle it. As the developer, you clearly know that you only handle single taps for now, but it’s best to be defensive against the possibility of double-taps (or other actions) later.
  3. Remove the tap from the queue.

Note: processUserTapsForUpdate() completely consumes the queue of taps at each invocation. Combined with the fact that fireShipBullets() will not fire another bullet if one is already onscreen, this emptying of the queue means that extra or rapid-fire taps will be ignored. Only the first tap needed to fire a bullet will matter.

Finally, add the following code as the first line in update():

processUserTapsForUpdate(currentTime)

This invokes processUserTapsForUpdate() during the update loop and processes any user taps.

Build your game, run, and fire away!

laser_test

Making Invaders Attack

Awesome, your ship can finally fire on those evil invaders! You’ll have them on the run soon enough.

But you’ve probably noticed that your bullets pass straight through invaders instead of blowing them up. That’s because your bullets aren’t yet smart enough to detect when they’ve hit an invader. You’re going to fix that in a moment.

First, you’ll make the invaders return fire by adding the code below to the // Scene Update Helpers section:

func fireInvaderBulletsForUpdate(currentTime: CFTimeInterval) {
 
  let existingBullet = self.childNodeWithName(kInvaderFiredBulletName)
 
  // 1
  if existingBullet == nil {
 
    var allInvaders = Array<SKNode>()
 
    // 2
    self.enumerateChildNodesWithName(kInvaderName) {
      node, stop in
 
      allInvaders.append(node)
    }
 
    if allInvaders.count > 0 {
 
      // 3
      let allInvadersIndex = Int(arc4random_uniform(UInt32(allInvaders.count)))
 
      let invader = allInvaders[allInvadersIndex]
 
      // 4
      let bullet = self.makeBulletOfType(.InvaderFiredBulletType)
      bullet.position = CGPointMake(invader.position.x, invader.position.y - invader.frame.size.height / 2 + bullet.frame.size.height / 2)
 
      // 5
      let bulletDestination = CGPointMake(invader.position.x, -(bullet.frame.size.height / 2))
 
      // 6
      self.fireBullet(bullet, toDestination: bulletDestination, withDuration: 2.0, andSoundFileName: "InvaderBullet.wav")
    }
  }
}

The central logic for the above method is as follows:

  1. Only fire a bullet if one’s not already on-screen.
  2. Collect all the invaders currently on-screen.
  3. Select an invader at random.
  4. Create a bullet and fire it from just below the selected invader.
  5. The bullet should travel straight down and move just off the bottom of the screen.
  6. Fire off the invader’s bullet.

Add the following line to the end of update():

fireInvaderBulletsForUpdate(currentTime)

This invocation of fireInvaderBulletsForUpdate() starts the invaders firing back at you.

Build, run, and you should see the invaders firing their purple bullets at your ship, as shown in the screenshot below:

laser_foe_test

As a matter of game design, notice that the invaders’ bullets are purple while your ship’s bullets are green. This strong color contrast makes it easy to see the difference between bullets in the heat of battle.

Also, you should hear a different sound when your ship fires versus when an invader fires. The use of different sounds is partly stylistic, to give your game rich audio and make it more immersive. But it’s also partly an accessibility issue since 7 – 10% of men and 0.5% – 1% women are color blind. The differentiation in sound effects will make your game more playable by those who are color blind.

Detecting When Bullets Hit Their Target

With all those bullets flying around on the screen it’s amazing that nothing blows up! That’s because your game has no hit detection. It needs to detect when your ship’s bullets hit an invader — and when an invader’s bullet hits your ship.

You could do this manually, comparing bullet/invader/ship positions at each update() invocation and checking for hits. But why not let Sprite Kit do the work for you?

Since you’re already using physics bodies, Sprite Kit’s physics engine can detect when one body hits another. For this, you’ll use contact detection — not collision detection. You’re not using physics to move bullets or invaders, so you’re not interested in the physical collisions between them. Contact detection merely detects when one physics body overlaps another in space; it doesn’t otherwise move or affect the bodies in contact.

Some games have many distinct types of physics bodies and are not interested in contact between all types of physics bodies. Sprite Kit will only check for contact between those categories of physics bodies that you tell it to check.

This is both a speed optimization and a correctness constraint, as some types of contact may not be desired. Controlling which physics bodies are checked for contact begins by defining category bitmasks.

Add the following new properties to GameScene:

let kInvaderCategory: UInt32 = 0x1 << 0
let kShipFiredBulletCategory: UInt32 = 0x1 << 1
let kShipCategory: UInt32 = 0x1 << 2
let kSceneEdgeCategory: UInt32 = 0x1 << 3
let kInvaderFiredBulletCategory: UInt32 = 0x1 << 4

These strange-looking constants are bitmasks. A bitmask is basically a way of stuffing multiple on/off variables into a single 32-bit unsigned integer. A bitmask can have 32 distinct values when stored as a UInt32. Each of these five categories defines a type of physics body. Notice how the number to the right of the << operator is different in each case; that guarantees each bitmask is unique and distinguishable from the others.

Add the following code to createContent() right after the line that creates the physics body:

physicsBody!.categoryBitMask = kSceneEdgeCategory

This new code sets the category for the physics body of your scene.

Add the following code to makeShip() right before the return ship line to set up the categories for your ship:

// 1
ship.physicsBody!.categoryBitMask = kShipCategory
// 2
ship.physicsBody!.contactTestBitMask = 0x0
// 3
ship.physicsBody!.collisionBitMask = kSceneEdgeCategory

Here's the breakdown of the above code:

  1. Set the ship's category.
  2. Don't detect contact between the ship and other physics bodies.
  3. Do detect collisions between the ship and the scene's outer edges.

Note: You didn't need to set the ship's collisionBitMask before because only your ship and the scene had physics bodies. The default collisionBitMask of "all" was sufficient in that case.

Since you'll be adding physics bodies to invaders next, setting your ship's collisionBitMask precisely ensures that your ship will only collide with the sides of the scene and won't also collide with invaders.

While you're at it, you should set the category for the invaders since this will help detect collisions between your ship's bullets and the invaders.

Add the following to the end of makeInvaderOfType() right before the return invader line:

invader.physicsBody = SKPhysicsBody(rectangleOfSize: invader.frame.size)
invader.physicsBody!.dynamic = false
invader.physicsBody!.categoryBitMask = kInvaderCategory
invader.physicsBody!.contactTestBitMask = 0x0
invader.physicsBody!.collisionBitMask = 0x0

This code gives your invader a physics body and identifies it as an invader using kInvaderCategory. It also indicates that you don't want invaders to contact or collide with other entities.

Your next step is to categorize bullets and set their contact and collision masks.

Add the following inside the case .ShipFiredBulletType clause of makeBulletOfType():

bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.frame.size)
bullet.physicsBody!.dynamic = true
bullet.physicsBody!.affectedByGravity = false
bullet.physicsBody!.categoryBitMask = kShipFiredBulletCategory
bullet.physicsBody!.contactTestBitMask = kInvaderCategory
bullet.physicsBody!.collisionBitMask = 0x0

The above code identifies ship-fired bullets as such and tells Sprite Kit to check for contact between ship-fired bullets and invaders, but that collisions should be ignored.

That takes care of the ship's bullets — now on to the invaders' bullets!

Add the following inside the case .InvaderFiredBulletType clause of makeBulletOfType():

bullet.physicsBody = SKPhysicsBody(rectangleOfSize: bullet.frame.size)
bullet.physicsBody!.dynamic = true
bullet.physicsBody!.affectedByGravity = false
bullet.physicsBody!.categoryBitMask = kInvaderFiredBulletCategory
bullet.physicsBody!.contactTestBitMask = kShipCategory
bullet.physicsBody!.collisionBitMask = 0x0

This code is similar to the previous block: it identifies invader-fired bullets as such and tells Sprite Kit to check for contact between invader-fired bullets and your ship, and again, ignores the collision aspect.

Note: In order for contact detection to work, the ship-fired bullets must be defined as dynamic by setting bullet.physicsBody.dynamic = true. If not, Sprite Kit won't check for contact between these bullets and the static invaders as their definition is invader.physicsBody.dynamic = false.

Invaders are static because they aren't moved by the physics engine. Sprite Kit won't check for contact between two static bodies, so if you need to check for contact between two categories of physics bodies, at least one of the categories must have a dynamic physics body.

You may be wondering why the contactTestBitMask values are not symmetrical. For example, why are you setting an invader's contactTestBitMastk = 0x0 but a ship-fired bullet's contactTestBitMask = kInvaderCategory?

The reason is that when Sprite Kit checks for contact between any two physics bodies A and B, only one of the bodies needs to declare that it should test for contact with the other, not both. As long as either A declares that it can contact with B, or B declares that it can contact with A, contact will be detected. It's not necessary for both bodies to declare that they should test for contact with the other.

Setting the contactTestBitMask on only one type of body like you've done seems more manageable. You might prefer to set contactTestBitMask values on both types of bodies, and that's fine, as long as you're consistent in choosing one approach or the other.

With these changes, your game's physics engine will detect contact between ship-fired bullets and the invaders, and between invader-fired bullets and your ship. But how does the physics engine inform your game of these contacts?

The answer is to use SKPhysicsContactDelegate.

Implementing the Physics Contact Delegate Methods

Still in GameScene.swift, modify the class line to look like the following:

class GameScene: SKScene, SKPhysicsContactDelegate {

This declares your scene as a delegate for the physics engine. The didBeginContact() method of SKPhysicsContactDelegate executes each time two physics bodies make contact, based on how you set your physics bodies' categoryBitMask and contactTestBitMask. You'll implement didBeginContact in just a moment.

Much like taps, contact can happen at any time. Consequently, didBeginContact can execute at any time. But in keeping with your discrete time ticks, you should only process contact during those ticks when update is called. So, just like taps, you'll create a queue to store contacts until they can be processed via update.

Add the following new property at the top of the class:

var contactQueue = Array<SKPhysicsContact>()

Now add the following code to the end of didMoveToView(), right after the userInteractionEnabled = true line:

physicsWorld.contactDelegate = self

This just initializes an empty contact queue and sets the scene as the contact delegate of the physics engine.

Next, add this method to the // Physics Contact Helpers section:

func didBeginContact(contact: SKPhysicsContact!) {
  if contact != nil {
    self.contactQueue.append(contact)
  }
}

This method simply records the contact in your contact queue to handle later when update() executes.

Still in the same section, add the following method:

func handleContact(contact: SKPhysicsContact) {
  //1
  // Ensure you haven't already handled this contact and removed its nodes
  if (contact.bodyA.node?.parent == nil || contact.bodyB.node?.parent == nil) {
    return
  }
 
  var nodeNames = [contact.bodyA.node!.name!, contact.bodyB.node!.name!]
 
  // 2
  if (nodeNames as NSArray).containsObject(kShipName) && (nodeNames as NSArray).containsObject(kInvaderFiredBulletName) {
 
    // 3
    // Invader bullet hit a ship
    self.runAction(SKAction.playSoundFileNamed("ShipHit.wav", waitForCompletion: false))
 
    contact.bodyA.node!.removeFromParent()
    contact.bodyB.node!.removeFromParent()
 
 
  } else if ((nodeNames as NSArray).containsObject(kInvaderName) && (nodeNames as NSArray).containsObject(kShipFiredBulletName)) {
 
    // 4
    // Ship bullet hit an invader
    self.runAction(SKAction.playSoundFileNamed("InvaderHit.wav", waitForCompletion: false))
    contact.bodyA.node!.removeFromParent()
    contact.bodyB.node!.removeFromParent()
 
  }
}

This code is relatively straightforward, and explained below:

  1. Don't allow the same contact twice.
  2. containsObject is not yet implemented in Swift's Array and you should cast the Array to NSArray like so (instanceOfSwiftArray as NSArray) in order to get access to NSArray's methods.
  3. If an invader bullet hits your ship, remove your ship and the bullet from the scene and play a sound.
  4. If a ship bullet hits an invader, remove the invader and the bullet from the scene and play a different sound.

Add the following method to the // Scene Update Helpers section:

func processContactsForUpdate(currentTime: CFTimeInterval) {
 
  for contact in self.contactQueue {
    self.handleContact(contact)
 
    if let index = (self.contactQueue as NSArray).indexOfObject(contact) as Int? {
      self.contactQueue.removeAtIndex(index)
    }
  }
}

The above code just drains the contact queue, calling handleContact for each contact in the queue and then remove the contact with the newly added method in the Array extension.

Add the following line to the very top of update() to call your queue handler:

processContactsForUpdate(currentTime)

Build and run you app, and start firing at those invaders!

destroy_foes

Now, when your ship’s bullet hits an invader, the invader disappears from the scene and an explosion sound plays. In contrast, when an invader’s bullet hits your ship, the code removes your ship from the scene and a different explosion sound plays.

Depending on your playing skill (or lack thereof!), you may have to run a few times to see both invaders and your ship get destroyed.

You will notice that when the ship is hit the app crashes, this is due to let ship = self.childNodeWithName(kShipName) as SKSpriteNode, in fact you should do a conditional downcast with as?.

Now you can substitute let ship = self.childNodeWithName(kShipName) as SKSpriteNode with:

if let ship = self.childNodeWithName(kShipName) as? SKSpriteNode { ... }

Next, you should encase the whole processUserMotionForUpdate‘s code within the if statement:

func processUserMotionForUpdate(currentTime: CFTimeInterval) {
 
  // 1
  if let ship = self.childNodeWithName(kShipName) as? SKSpriteNode {
 
    // 2
    if let data = motionManager.accelerometerData {
 
      // 3
      if (fabs(data.acceleration.x) > 0.2) {
 
        // 4 How do you move the ship?
        ship.physicsBody!.applyForce(CGVectorMake(40.0 * CGFloat(data.acceleration.x), 0))
 
      }
    }
  }
}

Just hit Command R to run the game, you will see that the bug is finally squashed! :]

Updating Your Heads Up Display (HUD)

Your game looks good, but it’s lacking a certain something. There’s not much dramatic tension to your game. What’s the advantage of hitting an invader with your bullet if you don’t get credit? What’s the downside to being hit by an invader’s bullet if there’s no penalty?

You’ll rectify this by awarding score points for hitting invaders with your ship’s bullets, and by reducing your ship’s health when it gets hit by an invader’s bullet.

Add the following properties to the top of the class:

var score: Int = 0
var shipHealth: Float = 1.0

Your ship’s health starts at 100% but you will store it as a number ranging from 0 to 1. The above sets your ship’s initial health.

Now, replace the following line in setupHud():

healthLabel.text = String(format: "Health: %.1f%%", 100.0)

With this:

healthLabel.text = String(format: "Health: %.1f%%", self.shipHealth * 100.0)

The new line sets the initial HUD text based on your ship’s actual health value instead of a static value of 100.

Next, add the following two methods to the // HUD Helpers section:

func adjustScoreBy(points: Int) {
 
  self.score += points
 
  let score = self.childNodeWithName(kScoreHudName) as SKLabelNode
 
  score.text = String(format: "Score: %04u", self.score)
}
 
func adjustShipHealthBy(healthAdjustment: Float) {
 
  // 1
  self.shipHealth = max(self.shipHealth + healthAdjustment, 0)
 
  let health = self.childNodeWithName(kHealthHudName) as SKLabelNode
 
  health.text = String(format: "Health: %.1f%%", self.shipHealth * 100)
 
}

These methods are fairly straightforward: update the score and the score label, and update the ship’s health and the health label. //1 merely ensures that the ship’s health doesn’t go negative.

The final step is to call these methods at the right time during gameplay. Replace handleContact() with the following updated version:

func handleContact(contact: SKPhysicsContact) {
 
  // Ensure you haven't already handled this contact and removed its nodes
  if (contact.bodyA.node!.parent == nil || contact.bodyB.node!.parent == nil) {
    return
  }
 
  var nodeNames = [contact.bodyA.node!.name!, contact.bodyB.node!.name!]
 
  if (nodeNames as NSArray).containsObject(kShipName) && (nodeNames as NSArray).containsObject(kInvaderFiredBulletName) {
 
    // Invader bullet hit a ship
    self.runAction(SKAction.playSoundFileNamed("ShipHit.wav", waitForCompletion: false))
 
    // 1
    self.adjustShipHealthBy(-0.334)
 
    if self.shipHealth <= 0.0 {
 
      // 2
      contact.bodyA.node!.removeFromParent()
      contact.bodyB.node!.removeFromParent()
 
    } else {
 
      // 3
      let ship = self.childNodeWithName(kShipName)!
 
      ship.alpha = CGFloat(self.shipHealth)
 
      if contact.bodyA.node == ship {
 
        contact.bodyB.node!.removeFromParent()
 
      } else {
 
        contact.bodyA.node!.removeFromParent()
      }
 
    }
 
  } else if ((nodeNames as NSArray).containsObject(kInvaderName) && (nodeNames as NSArray).containsObject(kShipFiredBulletName)) {
 
    // Ship bullet hit an invader
    self.runAction(SKAction.playSoundFileNamed("InvaderHit.wav", waitForCompletion: false))
    contact.bodyA.node!.removeFromParent()
    contact.bodyB.node!.removeFromParent()
 
    // 4
    self.adjustScoreBy(100)
  }
}

Here’s what’s changed in the method:

  1. Adjust the ship’s health when it gets hit by an invader’s bullet.
  2. If the ship’s health is zero, remove the ship and the invader’s bullet from the scene.
  3. If the ship’s health is greater than zero, only remove the invader’s bullet from the scene. Dim the ship’s sprite slightly to indicate damage.
  4. When an invader is hit, add 100 points to the score.

The above also explains why you store the ship’s health as a value between 0 and 1, even though your health starts at 100. Since alpha values range from 0 to 1, you can use the ship’s health value as the alpha value for for your ship to indicate progressive damage. That’s pretty handy!

Build and run your game again; you should see the score change when your bullets hit an invader; as well, you should see your ship’s health change when your ship is hit, as below:

ship-hud

Polishing Your Invader and Ship Images

You’ve been incredibly patient working with these less-than-menacing red, green, blue and magenta rectangles. Keeping the visuals simple has worked well because it allowed you to focus ruthlessly on getting your game logic correct.

Now you’ll add some actual image sprites to make your game much more realistic — and more fun to play!

Replace makeInvaderOfType() with the following two methods:

func loadInvaderTexturesOfType(invaderType: InvaderType) -> Array<SKTexture> {
 
  var prefix: String
 
  switch(invaderType) {
  case .A:
    prefix = "InvaderA"
  case .B:
    prefix = "InvaderB"
  case .C:
    prefix = "InvaderC"
  default:
    prefix = "InvaderC"
  }
 
  // 1
  return [SKTexture(imageNamed: String(format: "%@_00.png", prefix)),
    SKTexture(imageNamed: String(format: "%@_01.png", prefix))]
}
 
func makeInvaderOfType(invaderType: InvaderType) -> SKNode {
 
  let invaderTextures = self.loadInvaderTexturesOfType(invaderType)
 
  // 2
  let invader = SKSpriteNode(texture: invaderTextures[0])
  invader.name = kInvaderName
 
  // 3
  invader.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(invaderTextures, timePerFrame: self.timePerMove)))
 
  // invaders' bitmasks setup
  invader.physicsBody = SKPhysicsBody(rectangleOfSize: invader.frame.size)
  invader.physicsBody!.dynamic = false
  invader.physicsBody!.categoryBitMask = kInvaderCategory
  invader.physicsBody!.contactTestBitMask = 0x0
  invader.physicsBody!.collisionBitMask = 0x0
 
  return invader
}

Here’s what the new code does:

  1. Loads a pair of sprite images — InvaderA_00.png and InvaderA_01.png — for each invader type and creates SKTexture objects from them.
  2. Uses the first such texture as the sprite’s base image.
  3. Animates these two images in a continuous animation loop.

All of the images were included in the starter project and iOS knows how to find and load them, so there’s nothing left to do here.

Build and run your app; you should see something similar to the screenshot below:

textures

Looks pretty cool doesn’t it? Next, you’ll replace your blocky green ship with a much more retro and stylish looking version.

Replace this piece of code inside makeShip():

let ship = SKSpriteNode(color: SKColor.greenColor(), size: kShipSize)

With the following:

let ship = SKSpriteNode(imageNamed: "Ship.png")

Your ship sprite is now constructed from an image.

Build and run your game; you should see your official-looking ship appear as below:

spaceship

Play your game for a while — what do you notice? Although you can blast happily away at the invaders, there’s no clear victory or defeat. It’s not much of a space war, is it?

Implementing the End Game

Think about how your game should end. What are the conditions that will lead to a game being over?

  • Your ship’s health drops to zero.
  • You destroy all the invaders.
  • The invaders get too close to Earth.

You’ll now add checks for each of the above conditions.

First, add the following new properties to the top of the class:

let kMinInvaderBottomHeight: Float = 32.0
var gameEnding: Bool = false

The above defines the height at which the invaders are considered to have invaded Earth, and a flag that indicates whether the game is over or not.

Now, add the following two methods to the // Game End Helpers section:

func isGameOver() -> Bool {
 
  // 1
  let invader = self.childNodeWithName(kInvaderName)
 
  // 2
  var invaderTooLow = false
 
  self.enumerateChildNodesWithName(kInvaderName) {
    node, stop in
 
    if (Float(CGRectGetMinY(node.frame)) <= self.kMinInvaderBottomHeight)   {
 
      invaderTooLow = true
      stop.memory = true
    }
  }
 
  // 3
  let ship = self.childNodeWithName(kShipName)
 
  // 4
  return invader == nil || invaderTooLow || ship == nil
}
 
func endGame() {
  // 1
  if !self.gameEnding {
 
    self.gameEnding = true
 
    // 2
    self.motionManager.stopAccelerometerUpdates()
 
    // 3
    let gameOverScene: GameOverScene = GameOverScene(size: self.size)
 
    view!.presentScene(gameOverScene, transition: SKTransition.doorsOpenHorizontalWithDuration(1.0))
  }
}

Here’s what’s happening in the first method, which checks to see if the game is over:

  1. Get all invaders that remain in the scene.
  2. Iterate through the invaders to check if any invaders are too low.
  3. Get a pointer to your ship: if the ship’s health drops to zero, then the player is considered dead and the player ship will be removed from the scene. In this case, you’d get a nil value indicating that there is no player ship.
  4. Return whether your game is over or not. If there are no more invaders, or an invader is too low, or your ship is destroyed, then the game is over.

The second method actually ends the game and displays the game over scene. Here’s what the code does:

  1. End your game only once. Otherwise, you’ll try to display the game over scene multiple times and this would be a definite bug.
  2. Stop accelerometer updates.
  3. Show the GameOverScene. You can inspect GameOverScene.swift for the details, but it’s a basic scene with a simple “Game Over” message. The scene will start another game if you tap on it.

Add the following line as the first line of code in update():

if self.isGameOver() {
  self.endGame()
}

The above checks to see if the game is over every time the scene updates. If the game is over, then it displays the game over scene.

Build and run; blast away at the invaders until your game ends. Hopefully, you’ll destroy all of the invaders before they destroy you! Once your game ends, you should see a screen similar to the following:

gameover

Tap the game over scene and you should be able to play again!

One Last Thing: Polish and Fidelity

It’s a truism of game development that the last 20% of game development takes as long as the first 80%. When you’re working on your next game, it’s a good idea to start out iterating quickly with low-fidelity art assets (e.g. your colored squares) so you can quickly figure out if your game is fun to play.

If it’s not fun to play with colored squares, it’s not going to be fun to play with fancy art work, either! Nail down your gameplay and game logic first, then build out with fancy art assets and cool sound effects.

That being said, it’s essential that you polish your game before releasing it to the App Store. The App Store is a crowded market and spit and polish will distinguish your app from the competition. Try to add little animations, storylines and a dash of cute factor that will delight your users. Also, consider being true to the game if you’re remaking a classic.

If you’re a fan of Space Invaders, you’ll know that your remake is missing one important element. In the original game, the invaders march faster the closer they get to the bottom of the screen.

This was an artifact of the early CPU used to run the first Space Invaders game – the game loop ran faster and faster with fewer invaders because there was less work to do with each loop cycle. The game’s programmer, Tomohiro Nishikado, decided to leave this behavior in the game as a challenging game mechanic.

You’ll update your game to incorporate this game mechanic as well to please the retro gaming purists out there.

Convert the instance constant let timePerMove: CFTimeInterval = 1.0 to variable var:

var timePerMove: CFTimeInterval = 1.0

Then add the following method to the // Invader Movement Helpers section:

func adjustInvaderMovementToTimePerMove(newTimerPerMove: CFTimeInterval) {
 
  // 1
  if newTimerPerMove <= 0 {
      return
  }
 
  // 2
  let ratio: CGFloat = CGFloat(self.timePerMove / newTimerPerMove)
  self.timePerMove = newTimerPerMove
 
  self.enumerateChildNodesWithName(kInvaderName) {
    node, stop in
    node.speed = node.speed * ratio
  }
 
}

Let’s examine this code:

  1. Ignore bogus values — a value less than or equal to zero would mean infinitely fast or reverse movement, which doesn’t make sense.
  2. Set the scene’s timePerMove to the given value. This will speed up the movement of invaders within moveInvadersForUpdate. Record the ratio of the change so you can adjust the node’s speed accordingly.
  3. Speed up the animation of invaders so that the animation cycles through its two frames more quickly. The ratio ensures that if the new time per move is 1/3 the old time per move, the new animation speed is 3 times the old animation speed. Setting the node’s speed ensures that all of the node’s actions run more quickly, including the action that animates between sprite frames.

Now, you need something to invoke this new method.

Modify determineInvaderMovementDirection() as indicated by comments below:

case .Right:
  //3
  if (CGRectGetMaxX(node.frame) >= node.scene!.size.width - 1.0) {
    proposedMovementDirection = .DownThenLeft
 
    // Add the following line
    self.adjustInvaderMovementToTimePerMove(self.timePerMove * 0.8)
 
    stop.memory = true
  }
case .Left:
  //4
  if (CGRectGetMinX(node.frame) <= 1.0) {
    proposedMovementDirection = .DownThenRight
 
    // Add the following line
    self.adjustInvaderMovementToTimePerMove(self.timePerMove * 0.8)
 
    stop.memory = true
  }

The new code simply reduces the time per move by 20% each time the invaders move down. This increases their speed by 25% (4/5 the move time means 5/4 the move speed).

Build and run your game, and watch the movement of the invaders; you should notice that those invaders move faster and faster as they get closer to the bottom of the screen:

Final Screen

This was a quick and easy code change that made your game that much more challenging and fun to play. If you’re going to save the Earth from invading hordes, you might as well do it right! Spending time on seemingly minor tweaks like this is what makes the difference between a good game and a GREAT game.

Where to Go From Here?

Here is the final project from this Sprite Kit tutorial.

I encourage you to experiment with your SKInvaders game. Play with it, tweak it and see what you can do! Breaking your code, fixing it, then finally seeing an awesome new feature come to life is one of the many thrills of game development.

Through this tutorial series you learned some new tricks about Sprite Kit by building a very cool classic game along the way. If you want to learn how to build more fun games like this, check out our brand new book iOS Games by Tutorials, where you’ll learn how to make five complete games from scratch!

Enjoy playing your new game; I look forward to hearing from you with comments below or questions in the forums!

How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 2 is a post from: Ray Wenderlich

The post How To Make a Game Like Space Invaders with Sprite Kit and Swift Tutorial: Part 2 appeared first on Ray Wenderlich.

Video Tutorial: iOS Animation with Swift Part 17: Pop Spring Animations

iOS 8 by Tutorials Updated for Xcode 6.1

$
0
0
iOS 8 by Tutorials Updated for Xcode 6.1!

iOS 8 by Tutorials Updated for Xcode 6.1!

Good news – we have updated iOS 8 by Tutorials for Xcode 6.1!

Xcode 6.1 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

In addition to updating the book for Xcode 6.1, the authors also fixed some errata pointed out by readers – thanks for reporting what you found!

Here’s how you can get the update:

  • If you’re an iOS 8 by Tutorials customer, you can download the update for free on your My Loot page (version 1.3).
  • If you haven’t picked up a copy of iOS 8 by Tutorials yet, grab your copy now.

3 new Swift books updated for Xcode 6.1, and 2 to go. The remaining 2 updates (Core Data by Tutorials and iOS Games by Tutorials) are coming soon – stay tuned.

We hope you enjoy this update!

iOS 8 by Tutorials Updated for Xcode 6.1 is a post from: Ray Wenderlich

The post iOS 8 by Tutorials Updated for Xcode 6.1 appeared first on Ray Wenderlich.

iOS 8 Metal Tutorial with Swift Part 2: Moving to 3D

$
0
0
Learn how to render a 3D cube with Metal!

Learn how to render a 3D cube with Metal!

Welcome back to our iOS 8 Metal tutorial series!

In the first part of the series, you learned how to get started with Metal and render a simple 2D triangle.

In this second part of the series, you’ll learn how to set up a series of matrix transformations to move to full 3D. In the process, you will learn:

  • How to use model, view, and projection transformations
  • How to use matrices to transform geometry
  • How to pass uniform data to your shaders
  • How to use backface culling to optimize your drawing

Get ready to rock – it’s time for more Metal!

Getting Started

First, download the starter project – this is the same state where you left it off in the previous tutorial.

Build and run on your Metal-compatible device, and make sure you see the same triangle as before.

The most beautiful triangle I've ever seen!

Next, download this Matrix4 Helper Class that I have created for you, and add it to your project. When prompted if you’d like to configure an Objective-C bridging header, click Yes.

You’ll learn more about matrices later in this tutorial, so for now just enjoy this short overview of Matrix4.

There’s a built-in library on iOS called GLKit, that contains a library of handy 3D math routines called GLKMath. This includes a class to work with 3D matrices called GLKMatrix4.

You’re going to need to work with matrices a lot in this tutorial, so it would be good to be able to use this class. However, GLKMatrix4 is a C struct, so you can’t use it directly from Swift.

That’s why I created this class for you. It is a simple Objective-C class wrapper around the C struct, so you can use GLKMatrix4 from Swift. Here’s an illustration of the setup:

Screen Shot 2014-09-05 at 4.23.05 PM

Again, you’ll learn more about matrices later; I just wanted to have an overview of what this class is for now.

Refactor to a Node Class

For now, the starter project has everything set up in ViewController.swift. Although this was the easiest way to get started, it doesn’t scale well as your app gets larger.

In this section, you’ll refactor your project by following five steps:

  1. Create a Vertex Structure
  2. Create a Node Class
  3. Create a Triangle Subclass
  4. Refactor your View Controller
  5. Refactor your Shaders

Let’s get started!

Note: This section is optional, since at the end of this section you’ll be right where you started, just with a cleaner project and a colored triangle. If you’d like go straight to the 3D stuff, feel free to skip ahead to the “Creating a Cube” section. We’ll have a starter project waiting for you there.

1) Create a Vertex Structure

Create a new class with the iOS\Source\Swift File template and name it Vertex.swift.

Open Vertex.swift and replace the contents with the following:

struct Vertex{
 
  var x,y,z: Float     // position data
  var r,g,b,a: Float   // color data
 
  func floatBuffer() -> [Float] {
    return [x,y,z,r,g,b,a]
  }
 
};

This is a structure that will store the position and color of each vertex. floatBuffer() is a handy method that returns the vertex data as an array of Floats in strict order.

2) Create a Node Class

Create a new class with the iOS\Source\Swift File template and name it Node.swift.

Open Node.swift and replace the contents with the following:

import Foundation
import Metal
import QuartzCore
 
class Node {
 
  let name: String
  var vertexCount: Int
  var vertexBuffer: MTLBuffer
  var device: MTLDevice
 
  init(name: String, vertices: Array<Vertex>, device: MTLDevice){
    // 1
    var vertexData = Array<Float>()
    for vertex in vertices{
      vertexData += vertex.floatBuffer()
    }
 
    // 2
    let dataSize = vertexData.count * sizeofValue(vertexData[0])
    vertexBuffer = device.newBufferWithBytes(vertexData, length: dataSize, options: nil)
 
    // 3
    self.name = name
    self.device = device
    vertexCount = vertices.count
  }
 
}

Let’s go over this section by section:

Since Node is an object to draw, you need to provide it with the vertices it contains, a name for convenience, and a device to create buffers and render later on.

  1. You go through each vertex and form a single buffer with floats, which will look like this:
  2. Screen Shot 2014-09-05 at 5.28.41 PM

  3. Then, you ask the device to create a vertex buffer with the float buffer you created above.
  4. You set the instance variables.

Nothing fancy, eh?

Next, you need to move some of the render code that is currently in ViewController to Node. Specifically, you want to move the code that is responsible for rendering a particular buffer of vertices.

To do this, add this new method to Node.swift:

func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, clearColor: MTLClearColor?){
 
  let renderPassDescriptor = MTLRenderPassDescriptor()
  renderPassDescriptor.colorAttachments[0].texture = drawable.texture
  renderPassDescriptor.colorAttachments[0].loadAction = .Clear
  renderPassDescriptor.colorAttachments[0].clearColor = MTLClearColor(red: 0.0, green: 104.0/255.0, blue: 5.0/255.0, alpha: 1.0)
  renderPassDescriptor.colorAttachments[0].storeAction = .Store
 
  let commandBuffer = commandQueue.commandBuffer()
 
  let renderEncoderOpt = commandBuffer.renderCommandEncoderWithDescriptor(renderPassDescriptor)
  if let renderEncoder = renderEncoderOpt {
    renderEncoder.setRenderPipelineState(pipelineState)
    renderEncoder.setVertexBuffer(vertexBuffer, offset: 0, atIndex: 0)
    renderEncoder.drawPrimitives(.Triangle, vertexStart: 0, vertexCount: vertexCount, instanceCount: vertexCount/3)
    renderEncoder.endEncoding()
  }
 
  commandBuffer.presentDrawable(drawable)
  commandBuffer.commit()
}

This code should be a review from the previous tutorial. You can see that it has been copied from ViewController‘s render() method, but updated to use the vertex data for this node.

That’s it for the node class for now – time to create a subclass for the triangle!

3) Create a Triangle Subclass

Create a new class with the iOS\Source\Swift File template and name it Triangle.swift.

Open Triangle.swift and replace the contents with the following:

import Foundation
import Metal
 
class Triangle: Node {
 
  init(device: MTLDevice){
 
    let V0 = Vertex(x:  0.0, y:   1.0, z:   0.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
    let V1 = Vertex(x: -1.0, y:  -1.0, z:   0.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
    let V2 = Vertex(x:  1.0, y:  -1.0, z:   0.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
 
    var verticesArray = [V0,V1,V2]
    super.init(name: "Triangle", vertices: verticesArray, device: device)
  }
 
}

Here you subclass the Node class you just wrote for the triangle. In the initializer, you define the three vertices that make up the triangle, and pass that data to the superclass’s initializer.

It’s looking nice and clean already!

4) Refactor your View Controller

Now that you have all of the pieces in place, let’s refactor your view controller to use your new Triangle class.

Open ViewController.swift and delete following line:

var vertexBuffer: MTLBuffer! = nil

The node object will hold vertexBuffer so you don’t need it here.

Next, replace:

let vertexData:[Float] = [
    0.0, 1.0, 0.0,
    -1.0, -1.0, 0.0,
    1.0, -1.0, 0.0]

With:

var objectToDraw: Triangle!

And replace:

// 1
let dataSize = vertexData.count * sizeofValue(vertexData[0])
// 2
vertexBuffer = device.newBufferWithBytes(vertexData, length: dataSize, options: nil)

With:

objectToDraw = Triangle(device: device)

Now, when objectToDraw initializes and is ready to use, the only thing missing is calling the draw method from objectToDraw in the ViewController render method.

Finally, replace the render() method with the following:

func render() {
  var drawable = metalLayer.nextDrawable()
  objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable, clearColor: nil)
}

Build and run, and… uh-oh, where’d the triangle go?

bkvtq

The triangle has disappeared!

Do you have any ideas why that might be? Try to think of an answer, and then check to see if you are correct. Hint: take a look at the data inside the Vertex structure!

Solution Inside SelectShow>

5) Refactor your Shaders

Open Shaders.metal and take a good look at the vertex shader. You’ll notice it returns a float4 value for the position of each vertex and takes an array of packed_float3, which is data from a vertex buffer.

Now you’ll create two structures to hold Vertex data that passes to vertex shader, and one for vertex shader to return. It’ll be more clear when you will see the code.

Add this to Shaders.metal below using namespace metal; :

struct VertexIn{
  packed_float3 position;
  packed_float4 color;
};
 
struct VertexOut{
  float4 position [[position]];  //1
  float4 color;
};

You want vertex shader function to return VertexOut struct instead of just float4.

Note that vertex shaders must always return a position. In VertexOut, you specify the position component with special qualifier [[position]].

Now, modify the vertex shader code, so it looks like this:

vertex VertexOut basic_vertex(                           // 1
  const device VertexIn* vertex_array [[ buffer(0) ]],   // 2
  unsigned int vid [[ vertex_id ]]) {
 
  VertexIn VertexIn = vertex_array[vid];                 // 3
 
  VertexOut VertexOut;
  VertexOut.position = float4(VertexIn.position,1);
  VertexOut.color = VertexIn.color;                       // 4
 
  return VertexOut;
}
  1. Mark the vertex shader as returning a VertexOut instead of a float4.
  2. Mark the vertex_array as containing VertexIn vertices instead of packed_float3. Note that the VertexIn structure maps to the Vertex structure you created earlier.
  3. Get the current vertex from the array.
  4. Create a VertexOut and pass data from VertexIn to VertexOut, which returns at the end.

You might ask, “Why not to use VertexIn as a return value, since the data is the same?”

Good question! At the moment that would work, but you’ll need to have different structures later after applying transformations to position value.

Build and run. Oh, look who’s back!

Guess who's back / back again / Triangle's back / tell a friend...

Triangle’s back, tell a friend…

But you haven’t used the vertex color component, which now passes to vertex shader.

You should fix that by modifying the fragment shader to look like this:

fragment half4 basic_fragment(VertexOut interpolated [[stage_in]]) {  //1
  return half4(interpolated.color[0], interpolated.color[1], interpolated.color[2], interpolated.color[3]); //2
}
  1. The vertex shader will pass you the VertexOut structure – however its values will be interpolated based on the position of the fragment you’re rendering. More on this later.
  2. Now you simply return color for the current fragment instead of the hardcoded white color.

Build and run. You should be blinded by colors:

IMG_2420

Now, you may be wondering how you got rainbow colors in the middle of the triangle, considering you only specified three color values in the triangle.

As hinted earlier, the color values are interpolated based on the fragment you’re drawing. For example, the fragment on the bottom of the triangle 50% between the green and blue vertices would be blended as 50% green, 50% blue. This is done for you automatically; for any kind of value that you pass from the vertex shader to the fragment shader.

Okay, very nicely done so far! Now that your project is nicely refactored, it will be much easier to change from a triangle to a cube.

Creating a Cube

Note: If you skipped the previous section, download this starter project with the newly refactored code. The only difference other than general cleanliness is the triangle is now colored. Feel free to take a look through and get comfortable with the changes.

Your next task is to create a cube instead of a triangle. For that, as with all object models, you’ll create subclass of Node class.

Create a new class with the iOS\Source\Swift File template and name it Cube.swift.

Open Cube.swift and replace the contents with the following:

import UIKit
import Metal
 
class Cube: Node {
 
  init(device: MTLDevice){
 
    let A = Vertex(x: -1.0, y:   1.0, z:   1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
    let B = Vertex(x: -1.0, y:  -1.0, z:   1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
    let C = Vertex(x:  1.0, y:  -1.0, z:   1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
    let D = Vertex(x:  1.0, y:   1.0, z:   1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0)
 
    let Q = Vertex(x: -1.0, y:   1.0, z:  -1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
    let R = Vertex(x:  1.0, y:   1.0, z:  -1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
    let S = Vertex(x: -1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
    let T = Vertex(x:  1.0, y:  -1.0, z:  -1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0)
 
    var verticesArray:Array<Vertex> = [
      A,B,C ,A,C,D,   //Front
      R,T,S ,Q,R,S,   //Back
 
      Q,S,B ,Q,B,A,   //Left
      D,C,T ,D,T,R,   //Right
 
      Q,A,D ,Q,D,R,   //Top
      B,S,T ,B,T,C    //Bot
    ]
 
    super.init(name: "Cube", vertices: verticesArray, device: device)
  }
}

That looks rather familiar, don’t you think? It’s almost a carbon copy of the Triangle implementation, it just has eight vertices instead of three.

Also, each side comprises two triangles. For a better understanding, it might help to sketch it out on paper.
Cube__PSF_

Next open ViewController.swift and change the objectToDraw property to a cube:

var objectToDraw: Cube!

Also, inside init(), change the line that initializes objectToDraw to make it a cube:

objectToDraw = Cube(device: device)

Build and run. It might not look like it, but believe it or not, you’ve made a cube!

IMG_2435

What you see now is just the cube’s front face — an up-close selfie, if you will. Also it stretches over the display aspect ratio.

Don’t believe me? Doubt your cube-making skills? Okay, for your own sanity you’ll modify Cube so it’s smaller.

Rework the lines with vertices data so they look like this:

let A = Vertex(x: -0.3, y:   0.3, z:   0.3, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
let B = Vertex(x: -0.3, y:  -0.3, z:   0.3, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
let C = Vertex(x:  0.3, y:  -0.3, z:   0.3, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
let D = Vertex(x:  0.3, y:   0.3, z:   0.3, r:  0.1, g:  0.6, b:  0.4, a:  1.0)
 
let Q = Vertex(x: -0.3, y:   0.3, z:  -0.3, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
let R = Vertex(x:  0.3, y:   0.3, z:  -0.3, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
let S = Vertex(x: -0.3, y:  -0.3, z:  -0.3, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
let T = Vertex(x:  0.3, y:  -0.3, z:  -0.3, r:  0.1, g:  0.6, b:  0.4, a:  1.0)

Build and run.

IMG_2436

Cube is smaller, but something just isn’t right here. Wait, is it that you have to painstakingly modify vertices every time you need to modify a node? There’s got to be a better way!

And indeed there is – that is where matrices come in.

Introduction to Matrices

First things first, what is a matrix?

A matrix is a rectangular array of numbers (Sorry, Neo!). In 3D gaming, you’ll often see a 4×4 sized matrix — with four columns and four rows.

Also note that you’re using the GLKit column-based GLKMatrix4, so elements are placed like this:

Screen Shot 2014-09-03 at 1.43.20 PM

With matrices, you can transform your object in three ways:

  1. Translation: Shift the object along x, y and z axis
  2. Rotation: Rotate the object around any axis
  3. Scale: Change object size along any axis. (Please note that in this tutorial, you’ll always scale proportionally along all axes.)

Screen Shot 2014-09-03 at 1.36.17 PM

How does that work? First, you create an instance of Matrix4, like this (you don’t need to add this or the rest of the code in this section, this is just to illustrate):

var modelTransformationMatrix = Matrix4()

Then you use methods to apply transformations, like this:

modelTransformationMatrix.translate(positionX, y: positionY, z: positionZ)
modelTransformationMatrix.rotateAroundX(rotationX, y: rotationY, z: rotationZ)
modelTransformationMatrix.scale(scale, y: scale, z: scale)

There’s some math behind this that you can learn about in a Linear Algebra course. It’s great if you understand it, but it’s not necessary to do so for this tutorial.

Before you continue, open HelloMetal-BridgingHeader.h and import your Matrix4 class – you’ll need that in the following sections.

#import "Matrix4.h"

Model Transformation

The first transformation you’ll need is the model transformation. This transformation converts your node’s coordinates from local coordinates to world coordinates. In other words, it allows you to move your model around your world.

Let’s see how this works. Open Node.swift and add the following new properties:

var positionX:Float = 0.0
var positionY:Float = 0.0
var positionZ:Float = 0.0
 
var rotationX:Float = 0.0
var rotationY:Float = 0.0
var rotationZ:Float = 0.0
var scale:Float     = 1.0

These are convenience properties that you will set in order to position, rotate, or scale the node within the world. You will construct a model matrix from these which you will use to apply the model transformation.

To do this, add the following method at the end of Node:

func modelMatrix() -> Matrix4 {
    var matrix = Matrix4()
    matrix.translate(positionX, y: positionY, z: positionZ)
    matrix.rotateAroundX(rotationX, y: rotationY, z: rotationZ)
    matrix.scale(scale, y: scale, z: scale)
    return matrix
}

In this method, you generate a matrix from those parameters.

Now you need is to pass this matrix to the shader so it can apply the model transformation. To do this, you need to understand the concept of uniform data.

Uniform Data

So far, you have passed data that is different for each vertex to shaders, by using vertex arrays. But the model matrix will be the same across an entire model, so it would be a waste of space to copy it for each vertex.

When you have some data that is the same across an entire model, you want to pass the data to the shader a different way: as uniform data.

The first step to do this is to put your data into a buffer object, which represents memory accessible to both the CPU and GPU.

In Node.swift, add this right below var vertexBuffer: MTLBuffer:

var uniformBuffer: MTLBuffer?

Add this right after renderEncoder.setVertexBuffer(self.vertexBuffer, offset: 0, atIndex: 0):

// 1
var nodeModelMatrix = self.modelMatrix()
// 2
uniformBuffer = device.newBufferWithLength(sizeof(Float) * Matrix4.numberOfElements(), options: nil)
// 3
var bufferPointer = uniformBuffer?.contents()
// 4
memcpy(bufferPointer!, nodeModelMatrix.raw(), UInt(sizeof(Float)*Matrix4.numberOfElements()))
// 5
renderEncoder.setVertexBuffer(self.uniformBuffer, offset: 0, atIndex: 1)

Here’s the section-by-section breakdown:

  1. Call the method you wrote earlier to convert the convenience properties (like position and rotation) into a model matrix.
  2. Ask the device to create a buffer with shared CPU/GPU memory.
  3. Get a raw pointer from buffer (similar to void * in Objective-C).
  4. Copy your matrix data into the buffer.
  5. Pass uniformBuffer (with data copied) to the vertex shader. This is similar to how you sent the buffer of vertex-specific data, except you use index 1 instead of 0.

There is one problem with this code; it’s in a render method that should be called, hopefully, 60 times per second. In this case, you’re creating a new buffer 60 times per second.

Continuously allocating memory each frame is expensive and not recommended in production apps; we’ll show a better way to do this in future tutorials (and you can also see it in the iOS Metal Game template). However, to keep things simple in this tutorial, we will do it this way for now.

You passed matrix to vertex shader, but you’re not using it yet. To fix this, open Shaders.metal and add this structure right below VertexOut.

struct Uniforms{
  float4x4 modelMatrix;
};

Right now, it only holds one component, but later it will hold one more matrix.

Second, modify your vertex shader so it looks like this:

vertex VertexOut basic_vertex(
  const device VertexIn* vertex_array [[ buffer(0) ]],
  const device Uniforms&  uniforms    [[ buffer(1) ]],           //1
  unsigned int vid [[ vertex_id ]]) {
 
  float4x4 mv_Matrix = uniforms.modelMatrix;                     //2
 
  VertexIn VertexIn = vertex_array[vid];
 
  VertexOut VertexOut;
  VertexOut.position = mv_Matrix * float4(VertexIn.position,1);  //3
  VertexOut.color = VertexIn.color;
 
  return VertexOut;
}

Here’s what’s going on with this chunk of code:

  1. You add a second parameter for the uniform buffer, marking that it is incoming in slot 1 (to match up with the code you wrote earlier).
  2. You get a handle to the model matrix in the uniforms structure.
  3. To apply the model transformation to a vertex, you simply multiply the vertex position by the model matrix.

You’re done with that part, now back to working with the cube to test it.

In Cube.swift change vertices back to this:

let A = Vertex(x: -1.0, y:   1.0, z:   1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
let B = Vertex(x: -1.0, y:  -1.0, z:   1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
let C = Vertex(x:  1.0, y:  -1.0, z:   1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
let D = Vertex(x:  1.0, y:   1.0, z:   1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0)
 
let Q = Vertex(x: -1.0, y:   1.0, z:  -1.0, r:  1.0, g:  0.0, b:  0.0, a:  1.0)
let R = Vertex(x:  1.0, y:   1.0, z:  -1.0, r:  0.0, g:  1.0, b:  0.0, a:  1.0)
let S = Vertex(x: -1.0, y:  -1.0, z:  -1.0, r:  0.0, g:  0.0, b:  1.0, a:  1.0)
let T = Vertex(x:  1.0, y:  -1.0, z:  -1.0, r:  0.1, g:  0.6, b:  0.4, a:  1.0)

In ViewController.swift add following after objectToDraw = Cube(device: device)

objectToDraw.positionX = -0.25
objectToDraw.rotationZ = Matrix4.degreesToRad(45);
objectToDraw.scale = 0.5

Build and run.

IMG_2438

As expected, it is scaled down, shifted left and rotated 45 degrees around the Z axis.

This proves one thing: mathematical matrices are much cooler than any other matrices :]

Screen Shot 2014-09-08 at 2.34.05 PM

Now it’s time for some science — you’ll shift the cube along axis X , Y and Z at once. For that, add following code right below objectToDraw.positionX = -0.25 :

objectToDraw.positionY =  0.25
objectToDraw.positionZ = -0.25

Build and run.

IMG_2439

Cube shifts along X and Y, but what’s wrong with Z? You set .positionZ to be -0.25, so the cube should have moved away from you, but it didn’t.

You might think that there is some problem with matrix you passed, but that’s not the problem at all. In fact, the cube did move back, but you can’t see it.

To understand the problem, you need to understand another type of transform: the projection transform.

Projection Transformation

A projection transformation converts your node’s coordinates from camera coordinates to normalized coordinates. Depending on the type of projection you use, you’ll get different effects.

There are two projection types to know: orthographic and perspective.

Perspective is on the left and ortho is on the right. The camera or point of view is located on the axis origin.

zyGF1

Understanding perspective projection is easy, because its so similar to how your eyes see the world. Ortho is a bit harder but not that bad, because you’ve been working with the cube in orthographic mode!

Look at it another way: imagine that you’re standing on a railway and looking along it. In perspective mode, the rails look like this:

tracks_3

In orthographic mode, the picture is deformed and the rails are parallel.

In the picture below, you can see another perspective projection. It’s a chopped pyramid, and inside that pyramid is where your scene renders. The whole scene is projects onto the pyramid’s top face, similarly, that top face will be your device screen.

Screen Shot 2014-09-04 at 2.07.06 PM

Right now, Metal renders everything using orthographic projection, so you need to transform the scene to a perspective look. This calls for a matrix that describes perspective projection.

To recap the whole concept, you have a cube (your scene space), and you want to transform it into a chopped pyramid. To do that, you’ll create a projection matrix that describes the chopped pyramid above and maps it to your normalized box.

Matrix4 already has a method to create a perspective projection matrix, so you’ll work with that first.

Add the following new property to ViewController.swift:

var projectionMatrix: Matrix4!

Next, add the following at the top of viewDidLoad():

projectionMatrix = Matrix4.makePerspectiveViewAngle(Matrix4.degreesToRad(85.0), aspectRatio: Float(self.view.bounds.size.width / self.view.bounds.size.height), nearZ: 0.01, farZ: 100.0)

85.0 degrees specifies the camera’s vertical angle of view. You don’t need a horizontal value because you pass the aspect ratio of the view, and you also pass near and far planes to specify the field of view.

In other words, everything that is closer or farther will not display.

Now, modify the render() method inside Node.swift — specifically, you need to add one more parameter. Make the render method name look like this:

func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, projectionMatrix: Matrix4, clearColor: MTLClearColor?)

You added the projectionMatrix parameter.

Now you want to include projectionMatrix in the uniform buffer, which will pass to vertex shader later. Since the uniform buffer will now contain two matrices instead of one, you need to increase its size.

Replace:

uniformBuffer = device.newBufferWithLength(sizeof(Float) * Matrix4.numberOfElements(), options: nil)

With this:

uniformBuffer = device.newBufferWithLength(sizeof(Float) * Matrix4.numberOfElements() * 2, options: nil)

Now look for this:

memcpy(bufferPointer!, nodeModelMatrix.raw(), UInt(sizeof(Float)*Matrix4.numberOfElements()))

And add this after it:

memcpy(bufferPointer! + sizeof(Float)*Matrix4.numberOfElements(), projectionMatrix.raw(), UInt(sizeof(Float)*Matrix4.numberOfElements()))

Now both matrices pass to the uniforms buffer. All you need to do now is to use this projection matrix in your shader.

Go to Shaders.metal and modify Uniforms to include projectionMatrix:

struct Uniforms{
  float4x4 modelMatrix;
  float4x4 projectionMatrix;
};

Next in the vertex shader, you want to get projection matrix, so find this:

float4x4 mv_Matrix = uniforms.modelMatrix;

And add this after:

float4x4 proj_Matrix = uniforms.projectionMatrix;

To apply this matrix transformation to your position, you simply multiply matrix and position, just as you did with modelMatrix.

So, replace:

VertexOut.position = mv_Matrix * float4(VertexIn.position,1);

With this:

VertexOut.position = proj_Matrix * mv_Matrix * float4(VertexIn.position,1);

Finally, you need to pass in the projection matrix from your render method in ViewController.swift.

Replace:

objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable, clearColor: nil)

With:

objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable,projectionMatrix: projectionMatrix, clearColor: nil)

Also, change the translation parameters for objectToDraw so it looks like this:

objectToDraw.positionX = 0.0
objectToDraw.positionY =  0.0
objectToDraw.positionZ = -2.0
objectToDraw.rotationZ = Matrix4.degreesToRad(45);
objectToDraw.scale = 0.5

Build and run. Now it sort of looks like a cube, but it’s still messed up for some reason.

IMG_2440

You’ll fix it in a moment, but right now, take a moment to recap what you’ve just done.

  1. You added a model transformation, which allows you to modify an object’s location, size and rotation.
  2. You added a projection transformation, which allows you to shift from an orthographic to a more natural perspective projection.

There are actually two more transformations beyond this that are typically used in a 3D rendering pipeline:

  1. View Transformation: What if you want to look at the scene from a different position? You could move every object in the scene by modifying all of their model transformations, but this is inefficient. It is often convenient to have a separate transformation that represents how you’re looking at the scene; i.e. the “camera”.
  2. Viewport transformation: Basically, this takes the little world you’ve created in normalized coordinates and maps it to the device screen. This is done automatically by Metal, so you don’t need to do anything – it’s just something worth knowing.

Here’s the plan for the rest of the tutorial:

  1. You’ll add a View transformation
  2. You’ll make the cube rotate
  3. You’ll fix your cube’s peculiar transparency

View Transformation

A view transformation converts your node’s coordinates from world coordinates to camera coordinates. In other words, it allows you to move your camera around your world.

Adding a view transformation is fairly easy. Open Node.swift and change the render method declaration so it looks like this:

func render(commandQueue: MTLCommandQueue, pipelineState: MTLRenderPipelineState, drawable: CAMetalDrawable, parentModelViewMatrix: Matrix4, projectionMatrix: Matrix4, clearColor: MTLClearColor?)

You added parentModelViewMatrix, which represents the camera position and will be put to use to transform the scene.

Inside render(), find:

var nodeModelMatrix = self.modelMatrix()

And add this after it:

nodeModelMatrix.multiplyLeft(parentModelViewMatrix)

Note that you don’t pass this matrix to the shader as you did with the previous two matrices. Instead, you’re making a model view matrix which is a multiplication of the model matrix with the view matrix. It’s quite common to pass them pre-multiplied like this for efficiency.

Now, you just need to pass the new parameter to render(). Open ViewController.swift, and change :

objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable,projectionMatrix: projectionMatrix, clearColor: nil)

To this:

var worldModelMatrix = Matrix4()
worldModelMatrix.translate(0.0, y: 0.0, z: -7.0)
 
objectToDraw.render(commandQueue, pipelineState: pipelineState, drawable: drawable, parentModelViewMatrix: worldModelMatrix, projectionMatrix: projectionMatrix ,clearColor: nil)

Also, delete these lines:

objectToDraw.positionX = 0.0
objectToDraw.positionY =  0.0
objectToDraw.positionZ = -2.0
objectToDraw.rotationZ = Matrix4.degreesToRad(45);
objectToDraw.scale = 0.5

You don’t need to move the object back, because you’re moving the point of view.

Build and run.

IMG_2441

To understand the View transformation a little better, go ahead and do some more modifications.

Still in render() inside ViewController.swift, find:

worldModelMatrix.translate(0.0, y: 0.0, z: -7.0)

And add this below it:

worldModelMatrix.rotateAroundX(Matrix4.degreesToRad(25), y: 0.0, z: 0.0)

Build and run.

IMG_2445

You rotated the whole scene around the x-axis or changed the camera direction, whichever way you prefer to think about it :]

A Rotating Cube

Now let’s modify the project so it rotates your cube over time.

To do this, open Node.swift and add the following new property:

var time:CFTimeInterval = 0.0

This is simply a property that tracks how long the node was around.

Now, add the following method to the end of the class:

func updateWithDelta(delta: CFTimeInterval){
    time += delta
}

Next open ViewController.swift and add this new property:

var lastFrameTimestamp: CFTimeInterval = 0.0

Next, change:

timer = CADisplayLink(target: self, selector: Selector("gameloop"))

To be this:

timer = CADisplayLink(target: self, selector: Selector("newFrame:"))

And replace this:

func gameloop() {
  autoreleasepool {
    self.render()
  }
}

With this:

// 1
func newFrame(displayLink: CADisplayLink){
 
  if lastFrameTimestamp == 0.0
  {
    lastFrameTimestamp = displayLink.timestamp
  }
 
  // 2
  var elapsed:CFTimeInterval = displayLink.timestamp - lastFrameTimestamp
  lastFrameTimestamp = displayLink.timestamp
 
  // 3
  gameloop(timeSinceLastUpdate: elapsed)
}
 
func gameloop(#timeSinceLastUpdate: CFTimeInterval) {
 
  // 4
  objectToDraw.updateWithDelta(timeSinceLastUpdate)
 
  // 5
  autoreleasepool {
    self.render()
  }
}

Nice work! Here’s what you did, step-by-step:

  1. The display link now calls newFrame() every time the display refreshes. Note that the display link is passed as a parameter.
  2. You calculate time between this frame and the previous one. Note that it’s inconsistent because some frames might be skipped.
  3. You call gameloop(), but with the time since the last update as a parameter.
  4. You update your node by using updateWithDelta() before rendering.
  5. Now, when a node is updated, you can call the render method.

Finally, you need to override updateWithDelta in Cube class. Open Cube.swift and add this new method:

override func updateWithDelta(delta: CFTimeInterval) {
 
  super.updateWithDelta(delta)
 
  var secsPerMove: Float = 6.0
  rotationY = sinf( Float(time) * 2.0 * Float(M_PI) / secsPerMove)
  rotationX = sinf( Float(time) * 2.0 * Float(M_PI) / secsPerMove)
}

Nothing fancy here, all you’re doing is calling super() to update the time property. Then you set cube rotation properties to be a function of sin, which basically mean that your cube will rotate to some point and then rotate back.

Build and run, and enjoy your rotating cube!

IMG_2456

Your cube should now have a little life to it, spinning back and forth like a little cube-shaped dancer.

Fixing the Transparency

The last part is to fix the cube’s transparency, but first, you should understand the cause. It’s really quite simple and a little peculiar — Metal sometimes draws pixels of the back face of the cube before the front face.

So, how do you fix it?

There are two ways:

  1. One approach you can take is depth testing. With this method, you store each point’s depth value, so that when the two points are drawn at the same point on the screen, only the one with lower depth is drawn.
  2. The second approach is backface culling. This means that every triangle drawn is visible from just one side. So in effect, the back face isn’t drawn until it turns toward the camera. This is based on the order you specify the vertices of the triangles.

You’re going to use backface culling to solve the problem here, as it’s a more efficient solution when there is only one model. The rule you must keep is this: all triangles must be specified as counter-clockwise, otherwise, it won’t draw them.

Lucky for you, when I set up the cube vertices I organized them so every triangle is indeed specified as counter-clockwise, so you can just focus on learning how to use backface culling.

Open Node.swift and add find this in render():

if let renderEncoder = renderEncoderOpt {

And add this right below:

//For now cull mode is used instead of depth buffer
renderEncoder.setCullMode(MTLCullMode.Front)

Build and run.

IMG_2447

Now your cube should be free of transparency. What a beautiful cube!

Where to Go From Here?

Here is the final example project from this iOS 8 Metal Tutorial.

Congratulations, you have learned a ton about moving to 3D in the new Metal API! You now have an understanding of model, view, projection, and viewport transformations, matrices, passing uniform data, backface culling, and more.

We may write some more tutorials in this series covering texturing, lighting, and importing models if there’s enough interest – add a comment below if you’d would like to see more!

In the meantime, be sure to check out some great resources from Apple:

You also might enjoy the OpenGL ES video tutorials on our site, where Ray explains how many of these same concepts work in OpenGL ES, but with even more detail.

If you have questions, comments or discoveries to share, please leave them in the comments below!

iOS 8 Metal Tutorial with Swift Part 2: Moving to 3D is a post from: Ray Wenderlich

The post iOS 8 Metal Tutorial with Swift Part 2: Moving to 3D appeared first on Ray Wenderlich.

Core Data by Tutorials Updated for Xcode 6.1

$
0
0
Core Data by Tutorials Updated for Xcode 6.1!

Core Data by Tutorials Updated for Xcode 6.1!

Good news – Aaron, Saul, Matthew, and Pietro have updated Swift by Tutorials for Xcode 6.1!

Xcode 6.1 has a few small changes to Swift – mostly minor syntax things – but we wanted to make sure that all the instructions work without any issues.

In addition to updating the book for Xcode 6.1, the authors also fixed some errata pointed out by readers – thanks all!

Here’s how you can get the update:

  • If you’re a Core Data by Tutorials customer, you can download the update for free on your My Loot page (version 1.1).
  • If you haven’t picked up a copy of the Core Data by Tutorials yet, grab your copy now.

4 new Swift book updates down, 1 to go. The final new Swift book (iOS Games by Tutorials) will be updated for Xcode 6.1 soon!

Aaron, Saul, Matthew, and Pietro and I hope you enjoy this update!

Core Data by Tutorials Updated for Xcode 6.1 is a post from: Ray Wenderlich

The post Core Data by Tutorials Updated for Xcode 6.1 appeared first on Ray Wenderlich.


Video Tutorial: Introduction to Unity Part 15: Using Sounds

Video Tutorial: Introduction to Unity Part 16: Terrain Generation

Readers’ App Reviews – October 2014

$
0
0
FruitDating03

Games, Games, Games!

Happy Halloween!

As we think about pumpkin carving, costumes, and candy, there’s one more thing to think about – awesome creations by the iOS community.

October brings us some great apps made by fellow readers:

  • A game about herding sheep
  • A dating game for fruit
  • A game for people who love retro arcades
  • And of course, much more!

This is not a trick; it’s a treat! :]



Fruit Dating

FruitDating03Have you ever wanted to help a piece of fruit find its true love? Now’s your chance!

Fruit Dating is a sliding puzzle game where you’re a matchmaker, finding each piece of fruit find their soul mate.

With adorbable graphics and more than 60 well designed levels, Fruit Dating is really fun and casual iOS game. Obstacles and tile types introduced in later levels bring the challenge.

Controls are simple effortless swipes. All I ask is for more levels! I couldn’t get enough.

Fire Command

firecommand
Fire Command is a fantastic missile command style game with some truly awesome old-school graphics and sound effects.

Fire Command brings the spirit of the retro back, but with a blazing explosion of awesome style. A sweet soundtrack and retro sound effects round up the experience.

And what retro game wouldn’t be complete without a high-score table? GameCenter takes care of that.

Dash Up!

dashup
Dash Up (from one of our favorite developers, known for “I Want Ice Cream”) is a simple but addicting new game recently featured by Apple – congrats Johan!

Dash Up is easy; just tap to bounce as high as you can. But constantly moving blocks hunt you! Dodge, Duck, Dip, Dive, and… Dodge your way to the top.

Its simple. Its addictive. Don’t believe me? Give it a try, and tell me when you beat my high score: 12. I dare you! :]

Good Time Tracker

goodtimetracking
Good Time Tracker is a powerful app perfect for tracking our time through the day. As we bounce around from task to task its still valuable to track individual time spent for multiple projects or priorities. Good Time Tracker is perfect for that.

Good Time Tracker lets you track durations or start/end times. Silo work into tasks which can be attached to projects. Run reports for individial projects or periods of time. See a summary of your goals for the week or month.

Good Time Tracker does a good way of just getting out of the way and letting you track your time at your own pace.

Barn Rush

barnrush
Barn Rush is a cute simple game for kids, but I found myself rather addicted as well. :]

Barn Rush is all about rescuing chicks and ducklings from the bad Raccoon as you snake around the barnyard. Raccoons work in packs so watch out! Grab every bag you can to help get rid of them.

Work your way through 24 levels before moving onto an endless mode where you try to save as many chicks or ducklings as possible. Compete on GameCenter to see who the best bardyard hero is.

Grzegorz was generous enough to share some promo codes for our readers. Here are 20 promos for Barn Rush – grab em before the Raccoons!

393X4H6ETTN9
R7AHK47MLXT3
AJWATYR4LL3P
KJKKL9A63FRP
WAWF6XE643E3
L4NP9EMH9MYF
JPR46HNJTTKM
Y7X9EAL66MER
W33KH6TYETY3
E9AFJXMPL4M9
PRWRHMPT6E4A
M7F7FTE6WR3L
4YYA36RLLXYR
WLW4YW3E6MA3
TEF4E6JJRJL4
E47WHR9T9EMW
47L3ETEYNN47
44P9RKTXKWRX
KNFMRR37AWRE
FFRMAM4T3MHN

Put Your Puzzle Together

puzzletogether
Puzzles have always been fun for me. And kids love them too. Maybe thats why we get along so well. Or maybe its our love of Candy. :p

Put Your Puzzle Together is an app just for puzzling. It lets you build puzzles on the fly with pictures and stickers. And it’s just in time for Halloween, since it’s packed with halloween stickers.

The app cuts the puzzle right in front of you and then drops the pieces delightfully on the floor for you. Picking them up enlarges them while you drag them into place. You can even see a blurred picture of the puzzle behind it to give the slightest hints.

Watch My Colors

colorBubbles
This game shows you that color recognition is harder than you think!

Watch My Colors is all about the bubbles. You’re looking for two bubbles with the same color at a time. Grab matching bubbles and drag them to the corner that matches.

But you’ve got to watch your corners, they change as you color more bubbles, keeping you on your toes.

As if you didn’t just want to collect as many bubbles as possible, you can challenge your friends on GameCenter to see who can grab the most bubbles.

Prism X

Prism
Prism X is a clever login game based around lasers.

Prism X has 60 different levels where you need to get a laser from A to B. But sometimes theres a C, D, E, and more!

Later, they throw in multiple colored lasers. And combine that with 10 different types of optical diffusers and you’ve got a very wide array of possibilities to blow your mind.

Prism X is a great way to give your brain a workout and have some fun at the same time.

MADOW | Sheep Happens

madow
Herding sheep is never easy.

Madow is a game all about corralling these helplessly silly animals down a mountain side dotted with cliffs. You control the bridges. But sheep aren’t smart enough to wait, so you better be ready.

Did I mention not all sheep are created equal? Yea Red sheep are blazing fast and black shee are slow. And of course, you only get to control half the bridges at a time, so choose carefully.

OMG LOL

omglol

Texting has basically taken over all our lives. But are we any good at it? Lets find out.

OMG LOL Is a game just for the texters. Those double thumb junkies with a quick draw holster for their iPhone. You get barraged with text after text and its up to you to respond with the right emotion before its too late. We can’t keep our friends waiting!

Don’t miss the BRB bomb. Everyone needs a break once and a while.

OMG this app is awesome, BRB after I play some more ;]

Zero Lives

zerolives
Zero Lives doesn’t need an introduction. Just tap and play. Its as elegance as it is simple.

Zero Lives is an elegant puzzle game. The directive? Collect as many hearts as you can in ever more complex levels. Along the way meet new obstacles and patterns. Think through the order of your moves because some maps are more asymmetric than they appear.

There are plenty of levels and they certainly get challenging. Just play and enjoy yourself.



Honorable Mentions

Every month I get more submissions than I can handle. I give every app a shot, but I can’t write about them all. These are still great apps made by readers like you. Its no a popularity contest or even a favorite picking contest. I just try to get a glimpse of what the community is working on through your submissions. Take a moment and checkout these other great apps I didn’t have time to showcase properly.

Blox 3D Junior
Join the Colors
SHYN
Balloon-Popping Monster
Acid Storm
Tipster, The Tip Calculator
AutoSelfies
Spritz Read
12framework
Colorized
Quick Stop NYC



Where To Go From Here?

Each month, I really enjoy seeing what our community of readers comes up with. The apps you build are the reason we keep writing tutorials. Make sure you tell me about your next one, submit here!

If you’ve never made an app, this is the month! Check out our free tutorials to become an iOS star. What are you waiting for – I want to see your app next month!

I hope you have a Happy Halloween, and eat a lot of candy! :]

Readers’ App Reviews – October 2014 is a post from: Ray Wenderlich

The post Readers’ App Reviews – October 2014 appeared first on Ray Wenderlich.

Early Bird Discount for RWDevCon Ending

$
0
0

This is just a quick note to remind you that the early bird discount for RWDevCon ends in just a few hours!

As explained in the previous video, RWDevCon is going to be something really special, due to its focus on hands-on experience, team coordination, inspiration, and friendship.

If you’ve been thinking of attending, now’s the time! You can register here:

The team and I look forward to meeting you in DC! :]

Early Bird Discount for RWDevCon Ending is a post from: Ray Wenderlich

The post Early Bird Discount for RWDevCon Ending appeared first on Ray Wenderlich.

Video Tutorial: Introduction to Unity Part 17: The Unity GUI

Viewing all 4373 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>