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

Video Tutorial: Beginning Core Data Part 1: Getting Started


Swift Stained Glass Logo Giveaway!

$
0
0

I recently came across Howard Perlman from Stained Glass Logos, who specializes in making beautiful stained glass logos for technologies we know and love, like Ruby on Rails, WordPress, or Linux:

StainedGlassLogos

I thought these looked amazing, so I asked Howard if he’d be willing to make something special for the readers of raywenderlich.com. He then made this amazing Swift logo:

Swift stained glass logo

Looks amazing, eh? I know I’d love one of these on my patio!

Howard has kindly offered to donate this to a lucky reader of raywenderlich.com, to help spread the word about his stained glass logo business.

Swift stained glass logo - larger shot.

To enter to win this unique prize, simply leave a comment on this post answering the following question:

  • What’s your favorite new feature of iOS, watchOS, or Swift announced at WWDC 2015?

In 24 hours, we’ll choose a random lucky winner. To be eligible to win, you must live in the United States. Also, raywenderlich.com team members are not eligible to win – sorry guys and gals! :]

If you have a logo you’d like in stained glass (whether Swift or otherwise), be sure to contact Howard – he takes custom orders. We hope you enjoy the Swift stained glass logo, and thanks for reading raywenderlich.com! :]

The post Swift Stained Glass Logo Giveaway! appeared first on Ray Wenderlich.

Swift Interview Questions and Answers

$
0
0

I KNOW iOS

Even though Swift is only a year old, it’s already one of the most popular languages. Its syntax looks very easy — so easy that when it was announced JavaScript developers felt like the image to the right.

In reality, Swift, is a complex language. It embraces both object oriented and functional approaches, and it’s still evolving with each new release.

There’s a lot to Swift – but how can you test how much you’ve learned? In this article, the raywenderlich.com Tutorial Team and I have put together a list of sample Swift interview questions.

You can use these questions to interview candidates to test their Swift knowledge, or test your own! And if you don’t know the answer, don’t worry: each question has a solution so you can learn.

The questions are split into two sections:

  • Written questions: Good to include in a take-by-email programming test, since it sometimes involves writing a bit of code.
  • Verbal questions: Good to ask over the phone or in a face-to-face interview, as they can be answered more easily verbally.

Also, each section is split into three levels:

  • Beginner: Suitable for a beginner to Swift, who’s read a book or two on the subject and started working with Swift in their own apps.
  • Intermediate: Suitable for someone who’s got a strong interest in language concepts, who has been reading a lot of blog posts about Swift and experimenting with it further.
  • Advanced: Suitable for the best of the best only – folks who enjoy thoroughly exploring the language, challenging themselves, and using the cutting-edge techniques.

If you want to try answering these questions, I suggest you keep a Playground open to play with the code attached to the question before answering. Answers were tested against Xcode 7.0 beta 6.

Ready? Buckle up, it’s time to go!

Note: Special thanks to raywenderlich.com Tutorial Team members Warren Burton, Greg Heo, Mikael Konutgan, Tim Mitra, Luke Parham, Rui Peres, and Ray Wenderlich who helped me come up with some of these questions, and test them for difficulty level.


Written Questions

Beginners

Hello there, padowan. I’ll start you off with the basics.

Question #1 – Swift 1.0 or later
What’s a better way to write this for loop with ranges?

for var i = 0; i < 5; i++ {
  print("Hello!")
}
Solution Inside: Answer SelectShow>


Question #2 – Swift 1.0 or later
Consider the following:

struct Tutorial {
  var difficulty: Int = 1
}
 
var tutorial1 = Tutorial()
var tutorial2 = tutorial1
tutorial2.difficulty = 2

What’s the value of tutorial1.difficulty and tutorial2.difficulty? Would this be any different if Tutorial was a class? Why?

Solution Inside: Answer SelectShow>


Question #3 – Swift 1.0 or later

view1 is declared with var, and view2 is declared with let. What’s the difference here, and will the last line compile?

import UIKit
 
var view1 = UIView()
view1.alpha = 0.5
 
let view2 = UIView()
view2.alpha = 0.5 // Will this line compile?
Solution Inside: Answer SelectShow>


Question #4 – Swift 1.0 or later
This code sorts an array of names alphabetically and looks complicated. Simplify it and the closure as much as you can.

let animals = ["fish", "cat", "chicken", "dog"]
let sortedAnimals = animals.sort { (one: String, two: String) -> Bool in
  return one < two
}
Solution Inside: Answer SelectShow>


Question #5 – Swift 1.0 or later
This code creates two classes, Address and Person, and it creates two instances to represent Ray and Brian.

class Address {
  var fullAddress: String
  var city: String
 
  init(fullAddress: String, city: String) {
    self.fullAddress = fullAddress
    self.city = city
  }
}
 
class Person {
  var name: String
  var address: Address
 
  init(name: String, address: Address) {
    self.name = name
    self.address = address
  }
}
 
var headquarters = Address(fullAddress: "123 Tutorial Street", city: "Appletown")
var ray = Person(name: "Ray", address: headquarters)
var brian = Person(name: "Brian", address: headquarters)

Suppose Brian moves to the new building across the street, so you update his record like this:

brian.address.fullAddress = "148 Tutorial Street"

What’s going on here? What’s wrong with this?

I know it

Solution Inside: Answer SelectShow>


Intermediate

Now to step up the difficulty and the trickiness. Are you ready?

Question #1 – Swift 2.0 or later
Consider the following:

var optional1: String? = nil
var optional2: String? = .None

What’s the difference between nil and .None? How do the optional1 and optional2 variables differ?

Solution Inside: Answer SelectShow>


Question #2 – Swift 1.0 or later
Here’s a model of a thermometer as a class and a struct:

public class ThermometerClass {
  private(set) var temperature: Double = 0.0
  public func registerTemperature(temperature: Double) {
    self.temperature = temperature
  }
}
 
let thermometerClass = ThermometerClass()
thermometerClass.registerTemperature(56.0)
 
public struct ThermometerStruct {
  private(set) var temperature: Double = 0.0
  public mutating func registerTemperature(temperature: Double) {
    self.temperature = temperature
  }
}
 
let thermometerStruct = ThermometerStruct()
thermometerStruct.registerTemperature(56.0)

This code fails to compile. Where? Why?

Tip: Read it carefully and think about it a bit before testing it in a Playground.

Solution Inside: Answer SelectShow>


Question #3 – Swift 1.0 or later
What will this code print out and why?

var thing = "cars"
 
let closure = { [thing] in
  print("I love \(thing)")
}
 
thing = "airplanes"
 
closure()
Solution Inside: Answer SelectShow>


Question #4 – Swift 2.0 or later
Here’s a global function that counts the number of unique values in an array:

func countUniques<T: Comparable>(array: Array<T>) -> Int {
  let sorted = array.sort(<)
  let initial: (T?, Int) = (.None, 0)
  let reduced = sorted.reduce(initial) { ($1, $0.0 == $1 ? $0.1 : $0.1 + 1) }
  return reduced.1
}

It uses < and == operators, so it restricts T to types that implement, the Comparable protocol.

You call it like this:

countUniques([1, 2, 3, 3]) // result is 3

Rewrite this function as an extension method on Array so that you can write something like this:

[1, 2, 3, 3].countUniques() // should print 3
Solution Inside: Answer SelectShow>


Question #5 - Swift 2.0 or later
Here's a function to calculate divisions given to two (optional) doubles. There are three preconditions to verify before performing the actual division:

  • The dividend must contain a non nil value
  • The divisor must contain a non nil value
  • The divisor must not be zero
func divide(dividend: Double?, by divisor: Double?) -> Double? {
  if dividend == .None {
    return .None
  }
 
  if divisor == .None {
    return .None
  }
 
  if divisor == 0 {
    return .None
  }
 
  return dividend! / divisor!
}

This code works as expected but has two issues:

  • The preconditions could take advantage of the guard statement
  • It uses forced unwrapping

Improve this function using the guard statement and avoid the usage of forced unwrapping.

Solution Inside: Answer SelectShow>


Oh, hi there. You're now at the midpoint and I see you're going strong. Shall we see how you fare with some advanced questions?

Think you're clever, do you? This is when I step in.

Advanced

Question #1 - Swift 1.0 or later
Consider the following structure that models a thermometer:

public struct Thermometer {
  public var temperature: Double
  public init(temperature: Double) {
    self.temperature = temperature
  }
}

To create an instance, you can obviously use this code:

var t: Thermometer = Thermometer(temperature:56.8)

But it would be nicer to initialize it this way:

var thermometer: Thermometer = 56.8

Can you? How? Hint: it has to do with convertibles, but not convertibles like Camaros and Mustangs :)

Solution Inside: Answer SelectShow>


Question #2 - Swift 1.0 or later

Swift has a set of predefined operators that perform different types of operations, such as arithmetic or logic. It also allows creating custom operators, either unary or binary.
Define and implement a custom ^^ power operator with the following specifications:

  • Takes two Ints as parameters
  • Returns the first parameter raised to the power of the second
  • Ignores potential overflow errors
Solution Inside: Answer SelectShow>


Question #3 - Swift 1.0 or later
Can you define an enumeration with raw values like this? Why?

enum Edges : (Double, Double) {
  case TopLeft = (0.0, 0.0)
  case TopRight = (1.0, 0.0)
  case BottomLeft = (0.0, 1.0)
  case BottomRight = (1.0, 1.0)
}
Solution Inside: Answer SelectShow>


Question #4 - Swift 2.0 or later
Consider the following code that defines Pizza as a struct and Pizzeria as a protocol, with an extension that includes a default implementation for the method makeMargherita():

struct Pizza {
  let ingredients: [String]
}
 
protocol Pizzeria {
  func makePizza(ingredients: [String]) -> Pizza
  func makeMargherita() -> Pizza
}
 
extension Pizzeria {
  func makeMargherita() -> Pizza {
    return makePizza(["tomato", "mozzarella"])
  }
}

You'll now define the restaurant Lombardi’s as follows:

struct Lombardis: Pizzeria {
  func makePizza(ingredients: [String]) -> Pizza {
    return Pizza(ingredients: ingredients)
  }
  func makeMargherita() -> Pizza {
    return makePizza(["tomato", "basil", "mozzarella"])
  }
}

The following code creates two instances of Lombardi's. Which of the two will make a margherita with basil?

let lombardis1: Pizzeria = Lombardis()
let lombardis2: Lombardis = Lombardis()
 
lombardis1.makeMargherita()
lombardis2.makeMargherita()
Solution Inside: Answer SelectShow>


Question #5 - Swift 2.0 or later
The following code has a compile time error. Can you spot where and why it happens?

struct Kitten {
}
 
func showKitten(kitten: Kitten?) {
  guard let k = kitten else {
    print("There is no kitten")
  }
 
  print(k)
}

Hint: There are three ways to fix it.

Solution Inside: Answer SelectShow>


Verbal Questions

Yeah, that's right...I'm a Swift jedi
You're good, but you can't claim jedi status yet. Anybody can figure out the code, but how do you do with more open-ended questions of theory and practice?

To answer some of them you still might need to play with the code in a Playground.

Beginners

Question #1 - Swift 1.0 or later
What is an optional and what problem do optionals solve?

Solution Inside: Answer SelectShow>


Question #2 - Swift 1.0 or later
When should you use a structure, and when should you use a class?

Solution Inside: Answer SelectShow>


Question #3 - Swift 1.0 or later
What are generics and what problem do they solve?

Solution Inside: Answer SelectShow>


Question #4 - Swift 1.0 or later
There are a few cases when you can't avoid using implicitly unwrapped optionals. When? Why?

Solution Inside: Answer SelectShow>


Question #5 - Swift 1.0 or later
What are the various ways to unwrap an optional? How do they rate in terms of safety?
Hint: There are six ways.

Solution Inside: Answer SelectShow>


cant believe

Intermediate

Time to rachet up the challenge here. Seems you're doing just fine so far, but let's see if you make it through these questions.

Question #1 - Swift 1.0 or later
Is Swift an object-oriented language or a functional language?

Solution Inside: Answer SelectShow>


Question #2 - Swift 1.0 or later
Which of the following features are included in Swift?

  1. Generic classes
  2. Generic structs
  3. Generic protocols
Solution Inside: Answer SelectShow>


Question #3 - Swift 1.0 or later
In Objective-C, a constant can be declared like this:

const int number = 0;

Here is the Swift counterpart:

let number = 0

Is there any difference between them? If yes, can you explain how they differ?

Solution Inside: Answer SelectShow>


Question #4 - Swift 1.0 or later
To declare a static property or function you use the static modifier on value types. Here's an example for a structure:

struct Sun {
  static func illuminate() {}
}

For classes, it's possible to use either the static or the class modifier. They achieve the same goal, but in reality they're different. Can you explain how they differ?

Solution Inside: Answer SelectShow>


Question #5 - Swift 1.0 or later
Can you add a stored property by using an extension? Explain.

Solution Inside: Answer SelectShow>


Advanced

Oh boy, you're a clever one, aren't you? It's time to step it up another notch.

Question #1 - Swift 1.2
In Swift 1.2, can you explain the problem with declaring an enumeration with generic types? Take for example an Either enumeration with two generic types T and V, with T used as the associated value type for a Left case and V for a Right case:

enum Either<T, V> {
  case Left(T)
  case Right(V)
}

Pro tip: Inspect this case in an Xcode project, not in a Playground. Also notice that this question is related to Swift 1.2 so you'll need Xcode 6.4.

Solution Inside: Answer SelectShow>


Question #2 - Swift 1.0 or later
Are closures value or reference types?

Solution Inside: Answer SelectShow>


Question #3 - Swift 1.0 or later
The UInt type is used to store unsigned integers. It implements the following initializer for converting from a signed integer:

init(_ value: Int)

However, the following code generates a compile time error exception if you provide a negative value:

let myNegative = UInt(-1)

Knowing that a negative number is internally represented, using two's complement as a positive number, how can you convert an Int negative number into an UInt while keeping its memory representation?

Solution Inside: Answer SelectShow>


Question #4 - Swift 1.0 or later
Can you describe a situation where you might get a circular reference in Swift, and how you'd solve it?

Solution Inside: Answer SelectShow>


Question #5 - Swift 2.0 or later
Swift 2.0 features a new keyword to make recursive enumerations. Here is an example of such an enumeration with a Node case that takes two associated value types, T and List:

enum List<T> {
    case Node(T, List<T>)
}

What's that keyword?

Solution Inside: Answer SelectShow>


Where To Go From Here?

Congrats on making it to the end, and don't feel bad if you didn't actually know all the answers!

Some of these questions are pretty complicated and Swift is a rich, expressive language. There's a lot to learn. Moreover, Apple keeps improving it with new features, so even the best of us may not know it all.

To get to know Swift or build upon what you already know, be sure to check out our in-depth, tutorial-rich book, Swift by Tutorials, or sign up for our hands-on tutorial conference RWDevCon!

Of course, the ultimate resource for all aspects of Swift is the official The Swift Programming Language by Apple.

At the end of the day, using a language is the best way to learn it. Just play with it in a Playground or adopt it in a real project. Swift works (almost) seamlessly with Objective-C, so building on an existing project you already know is an excellent way to learn the ins and outs.

Thanks for visiting and working through these questions! Feel free to chime in below with your questions, problems and discoveries. I wouldn't mind if you wanted to pose some of your own challenges too. We can all learn from each other. See you in the forums!

The post Swift Interview Questions and Answers appeared first on Ray Wenderlich.

In-App Purchases Tutorial: Getting Started

$
0
0
Get started with in-app purchases to grow your app revenue!

Get started with in-app purchases to grow your app revenue!

Update note: This tutorial was updated for iOS 8 and Swift by Ray Fix. Original tutorial was by site editor-in-chief Ray Wenderlich.

One of the great things about being an iOS devleoper is that there are a variety of models you can use to make money off of your apps, including paid, free with ads, and in-app purchases.

In-app purchases are a particularly compelling option, for several reasons:

  • You can earn more money than just the price of your app. Some users are willing to spend a lot more on extra content!
  • You can release your app for free (which is a no-brainer download for most people), and if they enjoy it they can purchase more.
  • Once you have it implemented, you can keep adding additional content to the same app (rather than having to make a new app to earn more money!)

You can use In-App Purchases with varying business models. For example, the Ray Wenderlich app Wild Fables comes with three stories included with more available as in-app purchases. Battle Map 2 is an example of a paid app with optional extra content as in-app purchases.

In this tutorial, you’ll learn how to use in-app purchases to unlock local content embedded in your app.

This tutorial assumes that you are familiar with basic Swift and iOS programming concepts. If these concepts are new to you, check out some of the other tutorials on this site.

Getting Started

For this tutorial, you’re going to make a little app called In App Rage. The app allows users to buy rage comics, sometimes called “F7U12”. Readers of this site will undoubtedly recognize the genre. They’re basically funny little comics where someone goes through a common and frustrating situation, resulting in a wild rage or other humorous expression.

noautocom

Before you can start coding, you’ll need to create a placeholder app in the iOS Developer Center and iTunes Connect.

First, log into the iOS Developer Center. Select Identifiers under iOS Apps and then select the App IDs tab. Click the + button and complete the form like the following:

Dev_Portal_AppID

You must change the bundle identifier to have your own unique prefix. A common practice is to use your domain name in reverse. If all fails use a made-up one based on your name or something else unique.

Notice that In-App Purchase (and GameKit) are enabled by default. When you’re done, click Continue and then Submit. Viola – you have a new App ID! Now you’ll use it to create a new app in iTunes Connect.

Log onto iTunes Connect, click My Apps then + to add a new iOS App. If you’re prompted to choose an app type, select New iOS App (obviously). Then complete the form as shown below:

InApp_ITC_Create

If you are quick in getting to this step, you might notice that the Bunde ID is not showing up in the dropdown list. Apparently, this takes time to propagate. Take this opportunity to obey your Apple Watch, stand up, and walk around the block. Refresh the page when you get back and hopefully it will be there.

Also you’ll have to tweak the app Name, because app names need to be unique across the App Store. I’ve added an entry for this one. Maybe replace the RAF with your own initials.

Managing In App Purchases

The reason you just created a placeholder app is that before you can code in-app purchases, you have to set them up in iTunes Connect. Now that you have a placeholder app, just click In-App Purchases, as shown below:

new_app

Then click Create New in the upper left corner:

The Create New button for In-App Purchases

You will get to a screen that lets you select the type of In-App Purchase you want to add. Note that there are are two types of frequently-used In-App Purchases:

  • Consumables: can be bought more than once and can be used up. Like extra lives, in-game currency, temporary power-ups, and the like.
  • Non-Consumables. Something that you buy once, and expect to have it permanently. Things like extra levels, unlockable content, etc.

For In App Rage, you are going to be selling comics. Once the user purchases them, they should always have them, so choose Non-Consumable.

nonconsume

Note: Any Non-Consumable purchase should be available to a user on any device they have. You don’t get to charge a user twice if they have two devices!

We’ll talk more about how to allow the user to restore the non-consumable content they purchased on other devices later.

There is no such requirement for consumables though – consumables can be for just the device the user bought them on. If you want consumables to be cross-device, you’d have to implement that yourself with iCloud or some other technology.

Next, you will be taken to a page to enter some information about your in-app purchase. Fill in the fields according to the screenshot below:

InApp_ITC_NightlyRage

Let’s cover what each of these fields means:

  • Reference Name: This is what shows up in iTunes Connect for this in-app purchase. It can be whatever you want since you won’t see it anywhere in the app.
  • Product ID: Also known as “product identifier” in the Apple docs, this is the unique string that identifies your in-app purchase. Usually it’s best to start out with your Bundle ID, and then append a unique name for the purchase. In order for the sample code in this tutorial to work well without modification, you will need to use a certain naming convention discussed below.
  • Cleared for Sale: If this in-app purchase is OK for users to purchase as soon as the app becomes available.
  • Price Tier: How much this in-app purchase should cost.

After you’ve set that up, scroll down to the Language section and click Add Language. Fill out the form that pops up with the following information:

InApp_ITC_Language

This information will be returned to you when you query the App Store later on for the in-app purchases that are available. Prices will be in the correct currency for the part of the world you are selling in and you can also enable/disable these purchases on the fly. Don’t worry about the descriptions – you won’t be using them in this tutorial, so you can just use the Display Name for those.

You will also notice that there are fields for review Notes and Screenshots. While ultimately you will need to provide these for Apple’s review process, you do not need them for testing in the sandbox.

In order for the sample app to work without changes, your Product ID should take the form “YYYYY.XXXXX” where YYYYY is your unique name (mine was org.rayfix.inapprage) and XXXXX is the name of the image to be displayed. The names are: nightlyrage, girlfriendofdrummer, iphonerage, and updog.

You can now click Save. Great you just created your first In-App purchase. Now, repeat the process three more times for the remaining purchases. When you’re done, your purchases should look like this:

alliaps

You might notice that this process takes a while. I could imagine it gets annoying if you have a ton of in-app purchases in your app. Luckily you’re not in that situation, If you are in your app, draw me a rage comic :]

Quick Tour of the Starter Project

Download the starter project, unzip it and open in Xcode. Open MasterViewController.swift. This class imports StoreKit and displays a table view of available in-app purchases. Purchases are stored in an array of SKProduct objects. Each row (if not purchased) has a “Buy” button that lets you purchase the product. An NSNumberFormatter is used to show the localized price. Once purchased, you can view the comic for that purchase using the detail view. Finally, a “Restore” button lets you restore all previous purchases.

You will notice that MasterViewController.swift is using an object called RageProducts.store of type IAPHelper to do the heavy lifting. However, this class is currently stubbed out. If you build and run the app you will not run at this point.

Matching the Identifiers

For anything to work, you need to match up the bundle identifier and product identifiers in your app to the same ones you entered in iTunes Connect.

Select your project target in Project Navigator and then the General tab Change the value of Bundle Identifier to match. I used “org.rayfix.inappragedemo” but yours will be different.

inappragedemo_xcodeproj_and_iOS_Simulator_-_iPhone_5_-_iPhone_5___iOS_8_3__12F69_

Next change the product identifiers to match what you entered. Open RageProducts.swift and notice the list of four in-app purchases.

You probably only need to change the Prefix constant to match what you used in the previous sections. (It is marked with the TODO comment.)

Note: Many recommend that you pull the list of product identifiers from a web server so you can add new in-app purchases dynamically rather than requiring an app update. For this tutorial, you’re going to keep things simple and just hard-code in the product identifiers for this app.

Listing In-App Purchases

The RageProduct.store is an instance of IAPHelper. This object interacts with the StoreKit API to list and perform purchases. Open IAPHelper.swift and notice that is not yet implemented. You will now do so.

The first thing you need to do is get a list of in-app purchases from Apple’s server. Add the following private properties to IAPHelper class.

/// MARK: - Private Properties
 
// Used to keep track of the possible products and which ones have been purchased.
private let productIdentifiers: Set<ProductIdentifier>
private var purchasedProductIdentifiers = Set<ProductIdentifier>()
 
// Used by SKProductsRequestDelegate
private var productsRequest: SKProductsRequest?
private var completionHandler: RequestProductsCompletionHandler?

You will use these properties to perform your requests and keep track of what purchases have already been made. When you add this code you will immediately see a compiler error in init(productIdentifiers:). This is because the initialization rules of Swift dictate that you must initialize all class properties before calling super.init(). Fix that by adding the following to init(productIdentifiers:):

self.productIdentifiers = productIdentifiers

An IAPHelper is created by passing in the set of product identifiers supported. This is how RageProducts creates its store instance. Next, replace the implementation of requestProductsWithCompletionHandler(_:)

/// Gets the list of SKProducts from the Apple server calls the handler with the list of products.
public func requestProductsWithCompletionHandler(handler: RequestProductsCompletionHandler) {
	completionHandler = handler
	productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers)
	productsRequest?.delegate = self
	productsRequest?.start()
}

This code saves away the user’s completion handler so that it can be executed later. It then creates a request and fires the request off to Apple. Since IAPHelper does not yet conform to the SKProductsRequestDelegate protocol, you’ll see another compiler error. Fix that by adding the following IAPHelper extension at the end of the file:

// MARK: - SKProductsRequestDelegate
 
extension IAPHelper: SKProductsRequestDelegate {
  public func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
    println("Loaded list of products...")
    let products = response.products as! [SKProduct]
    completionHandler?(success: true, products: products)
    clearRequest()
 
    // debug printing
    for p in products {
      println("Found product: \(p.productIdentifier) \(p.localizedTitle) \(p.price.floatValue)")
    }
  }
 
  public func request(request: SKRequest!, didFailWithError error: NSError!) {
    println("Failed to load list of products.")
    println("Error: \(error)")
    clearRequest()
  }
 
  private func clearRequest() {
    productsRequest = nil
    completionHandler = nil
  }
}

This extension is used to get a list of products, their titles, descriptions and prices from Apple`s server by implementing the two methods required by the SKProductsRequestDelegate protocol.

productsRequest(_:didReceiveResponse:) is called when the list is succesfully retrieved. It receives an array of SKProduct objects and passes them to the previously saved completion handler. The handler reloads the table with new data. If a problem occurs, productsRequest(_:didFailWithError:) is called. In either case, when the request finishes you clear the request and completion handler with clearRequest().

Build and run now. You should now see a list of products in the table view. This part should work even in the simulator without a sandbox account.

InApp_ProductList

Didn’t work? If this didn’t work for you, there are a number of things to check (this list courtesy of itsme.manish and abgtan from the forums:

  • Go to Settings\iTunes & App Stores, log out of any account, and try again so you’re sure you’re using a Sandbox account.
  • Does your project’s Bundle ID match your App ID?
  • Check this link – if it doesn’t respond, the iTunes sandbox may be down.
  • Have you enabled In-App Purchases for your App ID?
  • Are you using the full product ID when when making an SKProductRequest?
  • Have you waited several hours since adding your product to iTunes Connect?
  • Are your bank details active on iTunes Connect?
  • Have you tried deleting the app from your device and reinstalling?

Tried all that and still stuck? Try the old forum thread or this thread’s comments for discussion with other readers.

Purchased Items

You want to be able to determine which items are already purchased. To do this you will use the purchasedProductIdentifiers property you added. If a product identifier is contained in this set, the user has purchased the item. The method for checking this is straightforward. Find the isProductPurchased(_:) function and replace the implementation with the following:

return purchasedProductIdentifiers.contains(productIdentifier)

Every time your app starts you don’t want to have to go to Apple’s server to find out if a particular purchase has been made. It is a good idea to save this information locally. You will use NSUserDefaults to save purchasedProductIdentifiers. Add the following before the call to super in your init(productIdentifiers:) method:

for productIdentifier in productIdentifiers {
	let purchased = NSUserDefaults.standardUserDefaults().boolForKey(productIdentifier)
	if purchased {
		purchasedProductIdentifiers.insert(productIdentifier)
		println("Previously purchased: \(productIdentifier)")
	} else {
		println("Not purchased: \(productIdentifier)")
	}
}

For each of your product identifiers, you check to see if the value is stored in NSUserDefaults and if it is, you insert it into the set. Later, you’ll also add an identifier to the set after a purchase is made.

Making Purchases (Show Me The Money!)

That’s great, but you need to be able to make purchases. How do you do that? That is what you will implement next. Still in IAPHelper.swift, replace the purchaseProduct(_:) implementation with the following:

/// Initiates purchase of a product.
public func purchaseProduct(product: SKProduct) {
	println("Buying \(product.productIdentifier)...")
	let payment = SKPayment(product: product)
	SKPaymentQueue.defaultQueue().addPayment(payment)
}

This creates a payment object using a SKProduct (which you got from the server) to add to a payment queue. There’s a singleton SKPaymentQueue object called defaultQueue(). Boom! Money in the bank!

How do you know if the payment went through? For that, you need your IAPHelper to observer transactions happening on the SKPaymentQueue. Go back to your init(productIdentifiers:) method and add the following line to the end of the function, right after super.init().

SKPaymentQueue.defaultQueue().addTransactionObserver(self)

This results in a compiler error because IAPHelper needs to conform to the SKPaymentTransactionObserver protocol. If you think of the compiler as a helpful todo list generator, this is the next item on the list!

Go to the end of the file and add the following extension and methods:

extension IAPHelper: SKPaymentTransactionObserver { 
  /// This is a function called by the payment queue, not to be called directly.
  /// For each transaction act accordingly, save in the purchased cache, issue notifications,
  /// mark the transaction as complete.
  public func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
    for transaction in transactions as! [SKPaymentTransaction] {
      switch (transaction.transactionState) {
      case .Purchased:
        completeTransaction(transaction)
        break
      case .Failed:
        failedTransaction(transaction)
        break
      case .Restored:
        restoreTransaction(transaction)
        break
      case .Deferred:
        break
      case .Purchasing:
        break
      }
    }
  }
 
  private func completeTransaction(transaction: SKPaymentTransaction) {
    println("completeTransaction...")
    provideContentForProductIdentifier(transaction.payment.productIdentifier)
    SKPaymentQueue.defaultQueue().finishTransaction(transaction)
  }
 
  private func restoreTransaction(transaction: SKPaymentTransaction) {
    let productIdentifier = transaction.originalTransaction.payment.productIdentifier
    println("restoreTransaction... \(productIdentifier)")
    provideContentForProductIdentifier(productIdentifier)
    SKPaymentQueue.defaultQueue().finishTransaction(transaction)
  }
 
  // Helper: Saves the fact that the product has been purchased and posts a notification.
  private func provideContentForProductIdentifier(productIdentifier: String) {
    purchasedProductIdentifiers.insert(productIdentifier)
    NSUserDefaults.standardUserDefaults().setBool(true, forKey: productIdentifier)
    NSUserDefaults.standardUserDefaults().synchronize()
    NSNotificationCenter.defaultCenter().postNotificationName(IAPHelperProductPurchasedNotification, object: productIdentifier)
  }
 
  private func failedTransaction(transaction: SKPaymentTransaction) {
    println("failedTransaction...")
    if transaction.error.code != SKErrorPaymentCancelled {
      println("Transaction error: \(transaction.error.localizedDescription)")
    }
    SKPaymentQueue.defaultQueue().finishTransaction(transaction)
  }
}

That is a lot of code! So let’s go through it in detail. paymentQueue(_:updatedTransactions:) is the only method actually required by the protocol. It gets called when one or more transactions’ states change. This method goes through an array of updated transactions and looks at their state. Based on that state it calls other methods defined here: completeTransaction(_:), restoreTransaction(_:) or failedTransaction(_:).

If the transaction was completed or restored, it adds to the set of purchases and saves the identifier in NSUserDefaults. It also posts a notification with that transaction so that any interested object in the app can listen for it to do things like update the user interface. Finally, in both the case of success or failure, it marks the transaction as finished.

Restoring Payments

If the user deletes and re-installs the app, or if they install it on another device, they need to be able to recover their purchases. In fact, Apple may reject your app if you do not implement the ability to restore non-consumable purchases.

You are already listening for when purchases have been restored. But you need to write the method that initiates it. Find the restoreCompletedTransactions() method and add the following to it:

SKPaymentQueue.defaultQueue().restoreCompletedTransactions()

That was almost too easy! You’ve already set the transaction observer and implemented the method to handle restoring transactions in the previous step.

In App Purchases, Accounts, and the Sandbox

While you’re running your app in Xcode, you’re not making transactions against the real in-app purchase servers – you’re running against sandbox servers.

This means you can buy things without fear of getting charged, etc. But you need to set up a test account, and also make sure you’re logged out of the store with your real account if you’re testing on device.

To make accounts, log onto iTunes Connect and click Users and Roles. Click Sandbox User then follow the buttons to create a test user.

Then go to your iPhone and make sure you’re logged out of your current account. To do this, go to the Settings app and tap iTunes & App Store. Tap your iCloud account name, and then select Sign Out.

Finally, go ahead and build and run your app and attempt to purchase a rage comic. Enter your test user account information and if all goes well, it should purchase with a happy check mark next to it. You can tap on it and see the comic! The list of purchases should look like this:

InApp_Final

Payment Permissions

Some devices and accounts may not permit in-app purchase. This can happen, for example, if parental controls are set to disallow it. Apple requires that you handle this situation gracefully; not doing so will likely result in an app rejection.

Open IAPHelper.swift and add the following method to the class:

public class func canMakePayments() -> Bool {
	return SKPaymentQueue.canMakePayments()
}

When canMakePayments() is false, your master view controller should display cells differently. For example, don’t show a “Buy” button, and simply say “Not Available” instead of listing the price.

To do this, open MasterViewController.swift and update the implementation of tableView(_:cellForRowAtIndexPath) as follows:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
	let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
 
	let product = products[indexPath.row]
	cell.textLabel?.text = product.localizedTitle
 
	if RageProducts.store.isProductPurchased(product.productIdentifier) {
		cell.accessoryType = .Checkmark
		cell.accessoryView = nil
		cell.detailTextLabel?.text = ""
	}
	else if IAPHelper.canMakePayments() {
		priceFormatter.locale = product.priceLocale
		cell.detailTextLabel?.text = priceFormatter.stringFromNumber(product.price)
 
		var button = UIButton(frame: CGRect(x: 0, y: 0, width: 72, height: 37))
		button.setTitleColor(view.tintColor, forState: .Normal)
		button.setTitle("Buy", forState: .Normal)
		button.tag = indexPath.row
		button.addTarget(self, action: "buyButtonTapped:", forControlEvents: .TouchUpInside)
		cell.accessoryType = .None
		cell.accessoryView = button
	} else {
		cell.accessoryType = .None
		cell.accessoryView = nil
		cell.detailTextLabel?.text = "Not Available"
	}
	return cell
}

This implementation will make the display more appropriate in the case where payments cannot be made with the device.

And there you have it – an app with in-app purchase!

Where To Go From Here?

Here is In App Rage Final.zip with all of the code you’ve developed above. Feel free to re-use the in-app purchase helper class.

One shortcoming of the sample app is that it doesn’t indicate to the user when it is communicating with Apple. A possible improvement would be to display a spinner or HUD control at appropriate times. This UI enhancement, however, is beyond the scope of this tutorial.

In-app purchases can be an important part of your business model – use them wisely and be sure to follow the guidelines about restoring purchases and failing gracefully, and you’ll be well on your way to success!

If any of you have questions or comments about this tutorial please join the forum discussion below!

And to end things off with a laugh, here’s a great iOS app rage comic made by Jayant C Varma from the original Objective-C version of this tutorial! :]

Coming Up With An iOS App Idea Rage Comic by Jayant Varma

The post In-App Purchases Tutorial: Getting Started appeared first on Ray Wenderlich.

Video Tutorial: Beginning Core Data Part 4: Predicates & Sorting

Season Finale with Mic and Jake – Podcast S04 E10

$
0
0
The Season 4 grand finale!

The Season 4 grand finale!

In the grand finale of Season 4, Mic and Jake talk about Core Text, current projects, season highlights, and much more.

[Subscribe in iTunes] [RSS Feed]

Our Sponsor

Interested in sponsoring a podcast episode? We sell ads via Syndicate Ads, check it out!

Links

Contact Us

Where To Go From Here?

We hope you enjoyed this episode of our podcast. Be sure to subscribe in iTunes to get notified when the next episode comes out.

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

The post Season Finale with Mic and Jake – Podcast S04 E10 appeared first on Ray Wenderlich.

RWDevCon 2016: Choose Your Topics!

$
0
0

RWDevCon

Next March, we are running an iOS conference focused on high quality hands-on tutorials called RWDevCon 2016.

One of the unique things about RWDevCon is it’s coordinated as a team.

That means we can do some cool things, like let you decide the content of the conference. Here’s how it works:

  1. Send your suggestions. First we’ll send an email to everyone who’s bought a ticket, asking for ideas for tutorials. For example, you might suggest a tutorial on UIStackView, a beginning OS X development series, or Swift 2 error handling.
  2. Vote your favorites. We’ll put the most common suggestions on a survey, and you can vote on which you’d like in the conference.
  3. Enjoy your top picks. Based on the results, we’ll be sure to cover everyone’s top picks, and match speakers to topics based on experience. w00t!

There’s no other conference like this – RWDevCon is truly a conference where you decide what’s inside.

We’ll be sending out a call for suggestions tomorrow, so if you’d like to be a part of the decision making process, grab your ticket today.

Also, I just wanted to give you a heads up that the current $100 off early bird discount will be ending in 1 week; another reason to grab your ticket now.

We can’t wait to see what you choose this year! :]

The post RWDevCon 2016: Choose Your Topics! appeared first on Ray Wenderlich.

UIAppearance Tutorial: Getting Started

$
0
0
Didn't you wish you could customize your pets?

Didn’t you wish you could customize your pets?

Although skeuomorphism in iOS apps is a thing of the past, that doesn’t mean you’re limited to the stock appearance of controls in your iOS app.

While you can develop your own controls and app stylings from scratch, Apple recommends that you use standard UIKit controls and take advantage of the various customization techniques in iOS. This is because UIKit controls are highly efficient, and your customizations to the controls should be mostly future-proof.

In this UIAppearance tutorial, you’ll use some basic UI customization techniques to customize a plain Pet Finder app and make it stand out from the pack! :]

Getting Started

Download the starter project for this tutorial here. The app has many of the standard UIKit controls and looks extremely vanilla.

Open the project and have a look around to get a feel for its structure. Build and run and you’ll see the main UI elements of Pet Finder:

plain-600x500

There’s a navigation bar and a tab bar. The main screen shows a list of pets; tap a pet to see some details about it. As well there’s a search screen and — aha! A screen that allows you to select a theme for your app. That sounds like a pretty good place to start!

Supporting Themes

Many apps don’t allow users to select a theme, and it’s not always advisable to ship an app with a theme selector. If you have little control over the content your app displays then you may quickly find yourself in a position where one of your themes clashes with the content other’s have generated or shared. However, you might want to test different themes during development to see which ones work best for your app, or you might A/B test your app with your beta users to see which style is the most popular.

In this UIAppearance tutorial, you’ll create a number of themes for your app that you can try out to see which one is most aesthetically pleasing.

Select File\New\File… and choose iOS\Source\Swift File. Click Next and type Theme as the name of the file. Finally click Next, followed by Create. Xcode automatically opens your new file, which contains just a single line of code.

Delete the single line and replace it with the following:

import UIKit
 
enum Theme {
  case Default, Dark, Graphical
 
  var mainColor: UIColor {
    switch self {
    case .Default:
      return UIColor(red: 87.0/255.0, green: 188.0/255.0, blue: 95.0/255.0, alpha: 1.0)
    case .Dark:
      return UIColor(red: 242.0/255.0, green: 101.0/255.0, blue: 34.0/255.0, alpha: 1.0)
    case .Graphical:
      return UIColor(red: 10.0/255.0, green: 10.0/255.0, blue: 10.0/255.0, alpha: 1.0)
    }
  }
}

This adds an enum with the different themes for your app. For now, all themes only have a mainColor that’s specific to that particular theme.

Next, add the following struct:

struct ThemeManager {
 
}

This will let you use a theme in the app. It’s still empty, but that will change soon enough!

Next, add the following line right above the enum declaration:

let SelectedThemeKey = "SelectedTheme"

Now, add the following method to ThemeManager:

static func currentTheme() -> Theme {
  if let storedTheme = NSUserDefaults.standardUserDefaults().valueForKey(SelectedThemeKey)?.integerValue {
    return Theme(rawValue: storedTheme)!
  } else {
    return .Default
  }
}

Nothing overly complex here: this is the main method you’ll use to style the app. It uses NSUserDefaults to persist the current theme, and uses it every time you launch your app.

To test that this works, open AppDelegate.swift and add the following line to application(_:didFinishLaunchingWithOptions):

println(ThemeManager.currentTheme().mainColor)

Build and run. You should the following printed to the console:

UIDeviceRGBColorSpace 0.94902 0.396078 0.133333 1

At this point, you have three themes and can manage them through ThemeManager. Now it’s time to go use them in your app.

Applying Themes to Your Controls

Back in Theme.swift, add the following method to ThemeManager:

static func applyTheme(theme: Theme) {
  // 1 
  NSUserDefaults.standardUserDefaults().setValue(theme.rawValue, forKey: SelectedThemeKey)
  NSUserDefaults.standardUserDefaults().synchronize()
 
  // 2
  let sharedApplication = UIApplication.sharedApplication()
  sharedApplication.delegate?.window??.tintColor = theme.mainColor
}

Here’s a quick run-through of the above code:

  1. You first persist the selected theme using NSUserDefaults.
  2. Then you get your current (selected) theme and apply the main color to the tintColor property of your application’s window. You’ll learn more about tintColor in just a moment.

Now the only thing you need to do is to call this method. There’s no better place than in AppDelegate.swift.

Replace the println() statement you added earlier with the following:

let theme = ThemeManager.currentTheme()
ThemeManager.applyTheme(theme)

Build and run. You’ll see that your new app looks decidedly more green:

theme_applied1

Navigate through the app; there are green accents everywhere! But you didn’t change any of your controllers or views. What is this black — er, green — magic?! :]

Applying Tint Colors

Since iOS 7, UIView has exposed the tintColor property, which is often used to define the primary color indicating selection and interactivity states for interface elements throughout an app.

When you specify a tint for a view, the tint is automatically propagated to all subviews in that view’s view hierarchy. Because UIWindow inherits from UIView, you can specify a tint color for the entire app by setting the window’s tintColor, which is exactly what you did in applyTheme() above.

Click on the Gear icon in the top left corner of your app; a table view with a segmented control slides up, but when you select a different theme and tap Apply, nothing changes. Time to fix that.

Open SettingsTableViewController.swift and add these lines to applyTheme(), just above dismiss():

if let selectedTheme = Theme(rawValue: themeSelector.selectedSegmentIndex) {
  ThemeManager.applyTheme(selectedTheme)
}

Here you call the method you added to ThemeManager, which sets the selected theme’s mainColor on the tintColor property of the root UIWindow instance.

Next, add the following line to the bottom of viewDidLoad() to select the theme persisted to NSUserDefaults when the view controller is first loaded:

themeSelector.selectedSegmentIndex = ThemeManager.currentTheme().rawValue

Build and run. Tap the settings button, select Dark, and then tap Apply. The tint in your app will change from green to orange right before your eyes:

theme_applied2

Eagle-eyed readers likely noticed these colors were defined in mainColor(), in ThemeType.

But wait, you selected Dark, and this doesn’t look dark. To get this effect working, you’ll have to customize a few more things.

Customizing the Navigation Bar

Open Theme.swift and add the following two methods to Theme:

var barStyle: UIBarStyle {
  switch self {
  case .Default, .Graphical:
    return .Default
  case .Dark:
    return .Black
  }
}
 
var navigationBackgroundImage: UIImage? {
  return self == .Graphical ? UIImage(named: "navBackground") : nil
}

These methods simply return an appropriate bar style and background image for the navigation bar for each theme.

Next, add the following lines to the bottom of applyTheme():

UINavigationBar.appearance().barStyle = theme.barStyle
UINavigationBar.appearance().setBackgroundImage(theme.navigationBackgroundImage, forBarMetrics: .Default)

Okay — why does this work here, and not earlier when you set barStyle on your UINavigationBar instance?

UIKit has an informal protocol called UIAppearance that most of its controls conform to. When you call appearance() on UIKit classes— not instances —it returns a UIAppearance proxy. When you change the properties of this proxy, all the instances of that class automatically get the same value. This is very convenient as you don’t have to manually style each control after it’s been instantiated.

Build and run. Select the Dark theme and the navigation bar should now be much darker:

theme_applied3

This looks a little better, but you still have some work to do.

Next, you’ll customize the back indicator. iOS uses a chevron by default, but you can code up something far more exciting! :]

Customizing the Navigation Bar Back Indicator

This change applies to all themes, so you only need to add the following lines to applyTheme() in Themes.swift:

UINavigationBar.appearance().backIndicatorImage = UIImage(named: "backArrow")
UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrowMask")

Here you’re simply setting the image and transition mask image to be used as the back indicator.

Build and run. Tap one of the pets and you should see the new back indicator:

back_button

Open Images.xcassets and find the backArrow image in the Navigation group. The image is all black, but in your app it takes on the tint color of your window and it just works.

just_works

But how can iOS just change the bar button item’s image color, and why doesn’t it do that everywhere?

As it turns out, images in iOS have three rendering modes:

  • Original: Always use the image “as is” with its original colors.
  • Template: Ignore the colors, and just use the image as a stencil. In this mode, iOS uses only the shape of the image, and colors the image itself before rendering it on screen. So when a control has a tint color, iOS takes the shape from the image you provide and uses the tint color to color it.
  • Automatic: Depending on the context in which you use the image, the system decides whether it should draw the image as “original” or “template”. For items such as back indicators, navigation control bar button items and tab bar images, iOS ignores the image colors by default unless you change the rendering mode.

Head back to the app, tap one of the pets and tap Adopt. Watch the animation of the back indicator in the navigation bar carefully. Can you see the problem?

mask1

When the Back text transitions to the left, it overlaps the indicator and looks pretty bad:

To fix this, you’ll have to change the transition mask image.

Update the line where you set backIndicatorTransitionMaskImage in applyTheme(), in Themes.swift, to the following:

UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrow")

Build and run. Once again tap one of the pets and then tap Adopt. This time the transition looks much better:

mask2

The text is no longer cut off and looks like it goes underneath the indicator. So, what’s happening here?

While iOS uses all the non-transparent pixels of the back indicator image to draw the indicator, it does something entirely different with the transition mask image: it masks the indicator with the non-transparent pixels of the transition mask image so that when the text moves to the left, the indicator is only visible in the those areas.

In the original implementation, you provided an image that covered the entire surface of the back indicator so the text remained visible through the transition. But now you’re using the indicator image itself as the mask, but the text disappeared at the far right edge of the mask, not under the indicator proper.

Look at the indicator image and the “fixed” version of the mask in your image assets catalog; you’ll see they they line up perfectly with each other:

indicator_mask

The black shape is your back indicator and the red shape is your mask. You want the text to only be visible when it’s passing under the red area and hidden everywhere else.

Change the last line of applyTheme() once again, this time to use the updated mask:

UINavigationBar.appearance().backIndicatorTransitionMaskImage = UIImage(named: "backArrowMaskFixed")

Build and run. For the last time, tap one of the pets and then tap Adopt. You’ll see that the text now disappears under the image, just as you anticipated it would:

mask3

Now that your navigation bar is pixel perfect, it’s time to give the tab bar some much-needed love.

Customizing the Tab Bar

Still in Theme.swift, add the following properties to Theme:

var tabBarBackgroundImage: UIImage? {
  return self == .Graphical ? UIImage(named: "tabBarBackground") : nil
}
 
var backgroundColor: UIColor {
  switch self {
  case .Default, .Graphical:
    return UIColor(white: 0.9, alpha: 1.0)
  case .Dark:
    return UIColor(white: 0.8, alpha: 1.0)
  }
}
 
var secondaryColor: UIColor {
  switch self {
  case .Default:
    return UIColor(red: 242.0/255.0, green: 101.0/255.0, blue: 34.0/255.0, alpha: 1.0)
  case .Dark:
    return UIColor(red: 34.0/255.0, green: 128.0/255.0, blue: 66.0/255.0, alpha: 1.0)
  case .Graphical:
    return UIColor(red: 140.0/255.0, green: 50.0/255.0, blue: 48.0/255.0, alpha: 1.0)
  }
}

These properties provide appropriate tab bar background images, background colors, and secondary colors for each theme.

To apply these styles, add the following lines to applyTheme().

UITabBar.appearance().barStyle = theme.barStyle
UITabBar.appearance().backgroundImage = theme.tabBarBackgroundImage
 
let tabIndicator = UIImage(named: "tabBarSelectionIndicator")?.imageWithRenderingMode(.AlwaysTemplate)
let tabResizableIndicator = tabIndicator?.resizableImageWithCapInsets(
    UIEdgeInsets(top: 0, left: 2.0, bottom: 0, right: 2.0))
UITabBar.appearance().selectionIndicatorImage = tabResizableIndicator

Setting the barStyle and backgroundImage should be familiar by now; it’s done in exactly the same you did for UINavigationBar previously.

In the final three lines of code above, you retrieve an indicator image from the asset catalog and set its rendering mode to .AlwaysTemplate. This is an example of one context where iOS doesn’t automatically use the template rendering mode.

Finally, you create a resizable image and set it as the tab bar’s selectionIndicatorImage.

Build and run. You’ll see your newly themed tab bar:

theme_applied4

The dark theme is starting to look more, well, dark! :]

See the line below the selected tab? That’s your indicator image. Although it’s only 6 points high and 49 points wide, iOS stretches this to the full width of the tab at run time.

The next section covers resizeable images and how they work.

Customizing a Segmented Control

One element that hasn’t changed yet is the segmented control that shows the currently selected theme. Time to bring that control into the wonderful world of theming.

Add the following code to the bottom of applyTheme() in Theme.swift:

let controlBackground = UIImage(named: "controlBackground")?
   .imageWithRenderingMode(.AlwaysTemplate)
     .resizableImageWithCapInsets(UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3))
let controlSelectedBackground = UIImage(named: "controlSelectedBackground")?
   .imageWithRenderingMode(.AlwaysTemplate)
     .resizableImageWithCapInsets(UIEdgeInsets(top: 3, left: 3, bottom: 3, right: 3))
 
UISegmentedControl.appearance().setBackgroundImage(controlBackground, forState: .Normal,
    barMetrics: .Default)
UISegmentedControl.appearance().setBackgroundImage(controlSelectedBackground, forState: .Selected,
    barMetrics: .Default)

To understand the code above, first take a look at the controlBackground image in your asset catalog. The image may be tiny, but iOS knows exactly how to use it to draw the borders of your UISegmentedControl, as it’s been pre-sliced and is resizable.

What does sliced mean? Take a look at the following magnified model:

slicing

There are four 3×3 squares, one in each corner. These squares are left untouched when resizing the image, but the gray pixels get stretched horizontally and vertically as required.

In your image, all the pixels are black and assume the tint color of the control. You instruct iOS how to stretch the image using UIEdgeInsets() and passed 3 for the top, left, bottom and right parameters since your corners are 3×3.

Build and run. Tap the Gear icon in the top left and you’ll see that the UISegmentedControl now reflects your new styling:

segmented

The rounded corners are gone and have been replaced by your 3×3 square corners.

Now that you’ve tinted and styled your segmented control, all that’s left is to tint the remaining controls.

Close the settings screen in the app, and tap the magnifier in the top right corner; you’ll see another segmented control which also has your customizations, along with a UIStepper, UISlider, and UISwitch that still need to be themed.

Grab your brush and drop cloths — you’re going painting! :]

Customizing Steppers, Sliders, and Switches

To change the colors of the stepper, add the following lines to applyTheme() in Theme.swift:

UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Normal)
UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Disabled)
UIStepper.appearance().setBackgroundImage(controlBackground, forState: .Highlighted)
UIStepper.appearance().setDecrementImage(UIImage(named: "fewerPaws"), forState: .Normal)
UIStepper.appearance().setIncrementImage(UIImage(named: "morePaws"), forState: .Normal)

You’ve used the same resizable image as you did for UISegmentedControl; the only difference here is that UIStepper segments become disabled when they reach their minimum or maximum values, so you needed to specify an image for this case as well. To keep things simple, you re-use the same image.

This not only changes the color of the stepper, but you also get some nice image buttons instead of the boring + and symbols.

Build and run. Open Search to see how the stepper has changed:

stepper

UISlider and UISwitch need some theme lovin’ too.

Add the following code to applyTheme():

UISlider.appearance().setThumbImage(UIImage(named: "sliderThumb"), forState: .Normal)
UISlider.appearance().setMaximumTrackImage(UIImage(named: "maximumTrack")?
    .resizableImageWithCapInsets(UIEdgeInsets(top: 0, left: 0.0, bottom: 0, right: 6.0)), 
      forState: .Normal)
UISlider.appearance().setMinimumTrackImage(UIImage(named: "minimumTrack")?
    .imageWithRenderingMode(.AlwaysTemplate)
      .resizableImageWithCapInsets(UIEdgeInsets(top: 0, left: 6.0, bottom: 0, right: 0)), 
        forState: .Normal)
 
UISwitch.appearance().onTintColor = theme.mainColor.colorWithAlphaComponent(0.3)
UISwitch.appearance().thumbTintColor = theme.mainColor

UISlider has three main customization points: the slider’s thumb, the minimum track and the maximum track.

The thumb uses an image from your assets catalog, while the maximum track uses a resizable image in original rendering mode so it stays black regardless of the theme. The minimum track also uses a resizable image, but you’ve used the template rendering mode so that it inherits the tint of the template.

You’ve modified UISwitch by setting thumbTintColor to the main color and onTintColor as a slightly lighter version of the main color t bump up the contrast between the two.

Build and run. Tap Search and your slider and switch should appear as follows:

slider-switch

As you saw with UISegmentedControl, the appearance proxy customizes all instances of a class. But sometimes you don’t want a global appearance for a control — in these cases, you can customize just a single instance of a control.

Customizing a Single Instance

Open SearchTableViewController.swift and add the following lines to viewDidLoad():

speciesSelector.setImage(UIImage(named: "dog"), forSegmentAtIndex: 0)
speciesSelector.setImage(UIImage(named: "cat"), forSegmentAtIndex: 1)

Here you’re simply setting the image for each segment in the species selector.

Build and run. Open Search and you’ll see the segmented species selector looks like this:

species

iOS inverted the colors on the selected segment’s image without any work on your part; this is because images are automatically rendered in Template mode.

What about selectively changing the typeface on your controls? That’s easy as well.

Open PetTableViewController.swift and add the following two lines to the bottom of viewWillAppear():

view.backgroundColor = ThemeManager.currentTheme().backgroundColor    
tableView.separatorColor = ThemeManager.currentTheme().secondaryColor

Next, add the following line to the end of tableView(_:cellForRowAtIndexPath:) just before you return from the method:

cell.textLabel!.font = UIFont(name: "Zapfino", size: 14.0)

This simply changes font on the label that represents the pet’s name.

Build and run. Compare the before and after:

theme_applied5-580x500

The image below shows the before and after results of the Search screen; I think you’ll agree that the new version is much less vanilla and much more interesting that the original:

theme_applied6-580x500

Where to Go From Here?

You can download the finished project with all the tweaks from this tutorial here.

In addition to the tweaks you’ve already made, in Objective-C you can specify certain customizations to be applied to controls only when they’re contained in other controls of a specific class. For example, you can apply customizations to UITextField, but only when contained in a UINavigationBar.

Unfortunately, you cannot use this kind of customization in Swift, yet. The good news is that iOS 9 will add this functionality, and I’ll update this tutorial accordingly once it’s released.

I hope you enjoyed this UIAppearance tutorial and learned how easy it can be to tweak your UI. If you have any comments or questions about this tutorial, please join the forum discussion below!

The post UIAppearance Tutorial: Getting Started appeared first on Ray Wenderlich.


Video Tutorial: Beginning Core Data Part 5: Editing & Deleting Data

Video Tutorial: Beginning Core Data Part 6: Conclusion

360iDev 2015 Conference Highlights

$
0
0
360iDev 2015 Conference Highlights!

360iDev 2015 Conference Highlights!

A record-breaking 390 attendees — including a full slate of 55 speakers — recently descended upon Denver, Colorado to take part in the annual 360 iDev conference.

360iDev was broken into three tracks — design, code and business — and had something to offer to anyone involved in the business of developing apps. With 61 sessions to choose from, it was easy to find find a mix of talks tailored to your interests.

In this year’s conference, the talks tended to focus on three overarching themes:

  1. The state of independent iOS developers
  2. Swift and functional programming
  3. Auto Layout and Adaptive Layout

In this article, I’ll share my own thoughts of the conference along with those of the 11 raywenderlich.com team members who were at the conference, and share a selection of quality presentations from 360iDev 2015 below, grouped by theme. Let’s dive in!

The State of Independent iOS Developers

Keynote: Still Here – Josh Michaels

“Steve Jobs’ educational device is now a casino.” – Josh Michaels

360f-josh

The conference opened with a keynote by Josh Michaels, a rare successful independent developer. It seems that lately our iOS and Mac indie developer heroes have been faltering. Josh reminded the gathered developers that the current playing field has changed.

He asked audience members to stand up if they’d contributed to shipping an app; nearly the entire room stood. He then asked those who are making money from apps to remain standing. Only around five out of the 390 attendees remained standing.

Josh went on to explain that the venture-capital backed apps had deflated prices and inflated app building costs. As many indies have complained, the upgrade revenue never arrived. Apple created a store offering free upgrades, with no reward to developers. As he showed a screenshot of the big budget & top selling apps he stated, “Steve Jobs’ educational device is now a casino.”

360-casino

Josh went on to explains that this situation exists because the app market has reached maturity. Unsurprisingly, this is how capitalism works, and for indies it’s better to accept that easy early days are over. He then presented his 2015 guide to being an indie developer:

  1. Live cheaply.
  2. Make something that you would use.
  3. Spend no more than 4 weeks on version 1.
  4. Ride that wave.
  5. GOTO Step 1.

Being indie is a lifestyle choice, and Josh advised developers that remaining exclusive to Apple will be a losing battle in the long run. He urged developers to focus on their work, diversify their interests and their income sources. He notes that “Think Different” is about pushing against the dominant paradigm; Apple, being the dominant paradigm, is no longer the way to think different.

What’s In It For Us After the Indiepocalipse – Marin Todorov

360g-marin

[Video link]

Next raywenderlich.com team member Marin Todorov took us on a journey though his own trials and tribulations as an indie developer.

He started by tracing the history of the “Indiepocalypse” – from its origins in a collection of doom and gloom articles published by iOS-Goodies.com to the current state where app sales continue to decline, and large companies dominate the market.

Marin went on to describe his struggles developing a keyboard extension with his partner. Their app Doodle Doodle suffered from a seemingly ever-changing set of rules arbitrarily declared by Apple. Eventually the app shipped, but like many keyboard extensions, suffers from an obtuse and lengthy installation process.

Being limited by the lack of in-app purchases or advertising options, the app could only be purchased outright. Most iOS customers expect apps to be free, which limits an indie keyboard extension app’s success. The final slap in the face is an alert view that states giving the app the full access it needs logs keyboard use and exposes credit card data to the developer.

Marin tells of an enlightening Coursera course he viewed: Developing Innovative Ideas for New Companies. The course draws parallels between the telegraph industry and developing for the App Store. In the early years of communications, messages were sent by coach and it was possible for anyone with sufficient skills to develop a telegraph business. Eventually, the market grew until the telephone was invented — at which point the market died. The app market began in 2008; it’s reached its mid-point in 2015 and if you extrapoalate the data then it should die off by 2017.

Marin read from a transcript of Steve Jobs’ introduction of the App Store. Apple would create the App Store, collect the funds, distribute the apps and App Store Search — Marin pauses here — would also provide the market. Apple didn’t promise that you would get rich. Marin’s advice, similar to others, is be realistic about success, make a high quality app, team up, launch into a niche, contribute to the community, write books and share your code.

Succeeding Slowly: A Practical Guide To Going Indie – Charles Perry

360f-charles

“If you can take a nap without asking permission: you’re an indie!” – Charles Perry

[Video Link]

Charles Perry, founder of MetaKite Software and host of the Release Notes podcast, provided some advice for those contemplating going indie. There’s lots of money to be made on the App Store — but only for a few developers. Why would you want to go indie? The answer is: “freedom”!

At past conferences, Charles has given a few talks about making a living selling apps on the iOS App Store, Mac App Store and through self-managed sales of OS X software. His podcast also focuses on the business of being indie.

His guide in brief suggests that a developer should set a profit target, start saving, conceive of a product, execute the product, build momentum and then take the leap into the indie lifestyle. In response to Josh Michael’s keynote where he claims indies have lost, Charle counters that they didn’t lose, “…they failed to adjust.” As mentioned in other indie development talks, Charles reiterated we are no longer in an early app market. Indie developers need to adjust to the mature market and build a mature business.

Swift and Functional Programming

Switching Your Brain to Swift – Greg Heo

[Video link]

360f-greg

raywenderlich.com team member Greg Heo presented one of the most popular talks to a standing-room only crowd. Was it about striking it rich on the app store, or how to run a mobile iOS consulting firm from a beach in Bora Bora? Nope – it was about making the switch to developing in Swift and covered the differences between Swift and Objective-C.

Greg started the talk by polling the audience and found the vast majority had not written more than one hundred lines of Swift code. Drawing on analogies from Objective-C and C++, Greg attempted to lift the veil on Swift. He patiently explained the aspects of types and type safety by exploring how Optional types play an important role, and used the analogy of unwrapping or unboxing to reveal a puppy. The point, he says, is an Optional is more like the box than the puppy, which the box may or may not contain.

He went on to demonstrate how Swift and Objective-C can work together and demonstrated some of the ways that Swift works with Objective-C. He also covered some of the newer features of Objective-C that work with Swift. The talk helped clarify where the limits of Objective-C lie.

Greg’s Example Code on Github

Bringing Swift into your Objective-C Projects – René Cacheaux

360g-rene

raywenderlich.com team member Rene Cacheaux’s talk was based on the experiences of his development team as they transitioned a large project from Objective-C to Swift. He began by stating he doesn’t dislike Objective-C, but because Apple went all in he’s since adopted the language. Swift is more concise and makes for safer, less crash-prone projects.

Using the Lord of the Rings as a metaphor, he tells of his fellowship’s journey. The poor framework support was the Mines of Moria, the project scheme bugs the Black Gates of Mordor. Gollum was the enterprise coding troubles that chased them on their journey and shipping an all-Swift app was analogous to destroying the Ring at Mount Doom.

The benefits of Swift are found in working with one file, without the need for .h or .m files or extensions. The downsides are that Swift doesn’t support macros and there was initial incompatibility with third-party libraries. The massive changes between Swift 1.0 and 1.2 posed many challenges, as did the limited ability to port Swift elements back to Objective-C.

Réné said his team decided to approach the project in a vertical fashion:

360-rene

They began by converting one view controller, then moved downwards through child classes, then through persistence, networking and other utilities. Once the first vertical slice was converted, they moved on the the next vertical slice. Eventually, his team arrived at a complete rewrite — and Sauron was defeated! :]

360f-collaborating

Bridging the Gap: Functional Programming in Objective C & Swift – Chris Woodward

Functional programming gained a lot of attention with the introduction of Swift, and was mentioned in some of the more popular sessions at WWDC 2015. In his talk, Chris Woodward noted that wrapping your head around functional programming while making the switch to Swift can be incredibly challenging for object-oriented developers.

Many apps consist of complex and tangled logic, with thousands and thousands of lines of code. Managing this requires a complex mental model resulting in code that’s hard to read, reason about, extend, fix and test. Chris contended that humans have a limited capacity to store things. By grouping things together, our own mental storage capacity can go up and reduce the human bottleneck. So how do you avoid complex code? Add structure, avoid extra dependencies and adopt a functional style.

Chris stated this state of coding nirvana could be reached through the use of short functions. He laid out a few functional rules stating that functions should not share mutable state or cause side effects. Chris also discussed filtering using predicates, map and reduce functions. The main takeaways of the talk was that code should be readable and a functional style could be used in any language that supports anonymous functions.

Auto Layout and Adaptive Layout Talks

Universal Layout Workshop – Sam Davies

360f-sam2

Six hands-on workshops preceded the conference, covering debugging, prototyping, core motion, HealthKit and animations; the format is quite similar to that of the hands-on tutorials at RWDevCon.

One of the highlights was the Universal Layout workshop, covered by raywenderlich.com team member Sam Davies. Sam presented a three-and-a-half hour review of layout in iOS, size classes, Adaptive Layout and stack views.

He began with a quick refresher on Auto Layout, and offered some tips to clarify some idiosyncrasies of using Auto Layout in Interface Builder. For example, when Control-dragging to create constraints, the direction of the drag changes the contextual menu that pops up. Also, bullets that appear in the contextual menu indicate which constraints already exist. He also suggested updating the frames in Interface Builder so the design time frames satisfy the constraints.

The introduction of multitasking in iOS 9 lets multiple apps appear on the screen at the same time. Adaptive Layout and size classes, which once appeared arbitrary, are now extremely important in the multitasking paradigm. If you already use Auto Layout, you’re ahead of the multitasking game.

Sam suggested that you handle layout as follows:

  1. Build your base layout first (Any, Any).
  2. Choose the Size Class overrides for the other sizes.
  3. Uninstall the irrelevant constraints.
  4. Add new relevant constraints.
  5. Rinse & Repeat.

Rotation methods should be avoided in the future; a combination of Auto Layout and Adaptive Layout will handle device rotation, since it’s really the size of the view that’s changing. In the end you avoid the “angry” red errors and the “less angry” orange warnings.

New in iOS 9, stack views now simplify the process of creating layouts, and Sam gave a great overview and demo of how they work as well. After seeing Sam give this talk, I have to say Stack Views are my new favorite thing!

Sam’s Auto Layout Workshop on GitHub

Solving Auto Layout Problems – Jack Cox

In another standing-room only talk, Jack Cox covered many tips and tricks for working with the often-challenging world of Auto Layout. He covered table views and scroll views, which by their variable nature create challenges for Auto Layout. Like Sam’s workshop, Jack covered stack views and the issues that surround them. For each issue, he provided a value on the “Auto Layout pain scale” with scroll views and table views providing moderate pain, while stack views present the least amount of pain. Debugging Auto Layout, he said, provides the worst kind of pain. :]

Jack provided a walkthrough debugging session dealing with the root causes of Auto Layout debugging pain: conflicts and ambiguity. Jack demonstrated one interesting way to reveal the workings under the hood: while breaking down the Visual Formatting Language, he explained how to convert the console output of po [[UIWindow keyWindow] _autolayoutTrace] into a formula that makes sense.

Jack’s Auto Layout Problem’s on GitHub

Sam explaining angry contraints

Sam explaining angry contraints

Mastering Auto Layout – Justin Williams

[Video link]

Justin Williams’ talk on Auto Layout began by covering the new iOS 9 layout anchors and the default 8-pt values set by Apple. He switched to the code and demonstrated how to modify the layout anchors through increaseMargin() or decreaseMargin() actions. Expounding further on the new hotness of layout anchors, he once again used code to create a simple form with its view elements centered neatly in a minimum number of lines.

His third coding demonstration covered the new Layout Guides, which can simplify complex layout scenarios in a minimal amount of code. He closed out the session by showcasing some Auto Layout debugging tips. Similar to others who spoke on Auto Layout, he suggested using the identifier property on constraints, which you can print out to the console and use to identify the element’s constraints in the output. You can then output a view’s constraints by overriding viewDidLayoutSubviews() like this:

override func viewDidLayoutSubviews()
    {
        super.viewDidLayoutSubviews()
        print("self.view.constraints = \(self.view.constraints)")
    }

Justin’s Mastering Auto Layout on GitHub

raywenderlich.com team members Aaron Douglas, Marin Tordorov, Derek Selander, Ellen Shapiro and Ryan Poolos

raywenderlich.com team members Aaron Douglas, Marin Tordorov, Derek Selander, Ellen Shapiro and Ryan Poolos

Fun & Games

The conference was more than just talks – there was some fun & games too!

Stump Jr 360: Not Dead Yet – Hosted by Tom Harrington

Presenting the...Experts?

Presenting the…Experts?

The second annual “Stump the Experts Speakers 360” picks up where the WWDC favorite “Stump the Experts” leaves off. A rag-tag collection of “experts” takes on the gathered audience in a game-show style battle of inane Apple trivia. The hosts present questions to challenge the audience, who in turn write trivia questions on 3×5 index cards.

The event is rife with comedic moments, and most often useless trivia, with points awarded to each side. Prizes consist of extremely valuable 5 1/4″ inch floppies that may have been overwritten, old eWorld and Newton stickers and bits of a tree stump from Tom’s own backyard. This session is a true highlight, and I look forward to many more years of Stump the Speakers 360 or whatever they choose to call it.

Full disclosure: I did manage to correctly answer a question in both the first and second “Stump”! :]

Game Dev Jam – hosted by Tom Ortega

360f-gamejam

Each year I’ve attended 360|iDev there’s been an all-nighter dev jam, where bleary-eyed developers show off their work first thing in the morning to the collected masses. Three years ago, Sprite Kit had just been released, so there were lots of games produced based on the new framework as well as Unity and Cocos2D.

This year’s game jam featured WatchKit app and several games, one of them built by three developers — including raywenderlich.com team member Ryan Poolos — who recently took the indie plunge. The game dev jam and accompanying board game night provided a great way to socialize and collaborate with other developers from around the world.

Other Interesting Talks

There are a few more other interesting thoughts that I thought you might like to hear about.

Apple Pay What Happens When You Tap – Stephan Huda

[Video link]

Stephan Huda, a principal engineer at Shopkeep, covered the ins and outs of paying for services with credit cards, near field communication (NFC), ApplePay and loyalty programs. Delving into the mechanisms of each, he began by explaining what information is stored in a credit card’s magnetic strip. He then presented an overview of the transaction process, from the merchant terminal, through a payment processor, to the card issuer. The transaction travels from the issuer to the acquirer who sends the approval back to the merchant.

He then described how NFC payments are processed using cryptography and a “secure element” chip in your device. While your device’s chip is powered by a nearby NFC reader, the secure element combines your account, a secure key and a unique transaction key. The transaction follows a similar process to the credit card, but with the extra encoded information related to the active transaction.

The details behind the payment process was covered lightly “with lots of hard waving” in Session 701 at WWDC 2015, but the exact process remains undisclosed by Apple. Stephan speculated that a transaction contains a series of merchant identifiers along with encrypted information in a manner that may be similar to NFC.

Localization Explained – Ellen Shapiro

360g-ellen

I attended the talk of raywenderlich.com team member Ellen Shapiro mostly out of curiosity, having employed localization in several apps myself. To my surprise and delight, Ellen’s talk illuminated many aspects of localization that I either wasn’t aware or hadn’t considered. She began with the statistics that 66% of Apple’s revenue comes from outside of the United States — 41% from China alone.

Localization, or as Ellen prefers, “internationalization”, is more complicated than it appears. Ellen presented a complete set of considerations and tips when adapting your app for a broader audience. Using NSLocalizedString along with a key and comment is the first step most developers are aware of. Running a genstrings script on a Swift or Objective-C file will generate a “.strings” file which can then be sent out to create translation files and placed into relative lprog folders. Ellen pointed out that the Base.lprog is the fallback location for missing translations.

Storyboards can also support localization using a strings file that bears the storyboard’s name. Ellen noted that numeric values are often displayed and handled differently in other languages and developers need to be aware of the different date formats and timezones used internationally. Developers should be mindful that iOS 9 will automatically handle right-to-left language orientations. Also new in iOS 9 is NSPersonNameComponentsFormatter, which deals with the various ways first names, family names, initials and titles display across languages. All in all, Ellen’s talk was good overview if you’re planning to sell your apps in a worldwide market.

Super Computing for iOS and Macs With Metal – Jeff Biggus

360f-jeff

Jeff Biggus presented a well-attended talk on super computing which contained a fascinating overview of the chips that work alongside and separate from the CPU.

Jeff gave a brief history of the chips beginning with the CUDA chip in 2007. In 2008, Apple introduced OpenCL, which permitted the same code to be run on any hardware that supported the OpenCL framework. From there, the market started to fragment. AMD brought out the Mantle API in 2013 for standard CPUs with embedded GPUs. Apple followed this with Metal for Mac and iOS; the Vulkan project began to use AMD’s code and Google decided to go with Vulkan. Jeff’s hope is that Apple also adopts project Vulkan in future.

Jeff brought along a demo project that displayed a Mandelbrot image on the Mac. Using the CPU, zooming in on the Mandelbrot was a sluggish operation. Jeff then demonstrated various combinations of settings in the app and changes to the processing used. Finally, he landed on pure Metal, which uses the GPUs; the Mandelbrot scaled up smoothly at hundreds of processes per second.

In the middle of his very complex talk of maths, chips and technology, Jeff displayed a very welcome image of a puppy! It was a refreshing break in a technical but otherwise great talk on the subject.

Jeff’s Code Examples on GitHub

Where to Go From Here?

I can’t recommend 360iDev highly enough; it’s a great experience for any developer, designer or anyone involved in app production.

The hosts John Wilker, Nicole Wilker, and Tom Ortega make the conference feel like home, and the collective masses are super friendly. No matter what obstacles might come up, I feel I cannot afford to miss this conference. Every year I’ve attended I come away re-energized, enlightened and ready to take on the next year’s work.

Tom Ortega and John Wilker

Tom Ortega and John Wilker

Ray’s said a number of times that 360iDev is one of his favorite iOS conferences — and I’d have to agree. If you’re looking for more hands-on tutorials, check out RWDevCon which runs March 11th-12th, 2016 in Washington D.C.; it and 360iDev are both at the top of my own personal list of conferences.

Let us know what you think! Did you attend? Will you attend next year? Will you step up and submit a talk of your own? Please join the forum discussion below!

The post 360iDev 2015 Conference Highlights appeared first on Ray Wenderlich.

Video Tutorial: Intermediate Core Data: Series Introduction

Video Tutorial: Intermediate Core Data Part 1: Core Data Stack

How to Create a Tower Defense Game in Unity – Part 1

$
0
0

blocks-twitter

Tower defense games are incredibly popular, and no wonder — few things are more satisfying than watching your defense obliterate evil invaders! In this two-part tutorial, you build a tower defense game with Unity!

You’ll learn how to…

  • Create waves of enemies
  • Make them follow waypoints
  • Build and upgrade towers them and let them reduce your enemies to pixels

At the end, you’ll have a framework for this genre that you can expand upon!

Note: You need to know Unity basics, like how to add game assets and components, understand prefabs and know some basic C#. To learn those things I recommend completing the Unity tutorials by Chris LaPollo.

I’m using the OS X version of Unity, but this tutorial works on Windows too.

A View from the Ivory Tower

In this tutorial, you build a tower defense game, where enemies — little bugs — crawl towards a cookie that belongs to you and your minions, which are of course monsters! You can place and upgrade monsters at strategic points for a bit of gold.

The player must kill the bugs before they feast on your cookie. Each wave of enemies is successively harder to defeat. The game ends when you survive all waves (Victory!) or when five enemies reach the cookie. (Defeat!).

Here’s a screenshot of the finished game:

Monsters Unite! Protect your cookie!

Monsters Unite! Protect the cookie!

Getting Started

If you don’t already have Unity 5 or newer, download it from Unity’s website.

Also, download this starter project, unzip and open the TowerDefense-Part1-Starter project in Unity.

The starter project includes art and sound assets, along with prebuilt animations and a few helpful scripts. The scripts aren’t directly related to tower defense games, so they won’t be explained here. However, if you’d like to learn more about creating Unity 2D animations, check out this Unity 2D tutorial.

The project also contains prefabs you’ll later expand upon to create characters. Finally, the project includes a scene with its background and user interface set up.

Open GameScene, found in the folder Scenes, and set your Game view’s aspect ratio to 4:3 to ensure the labels line up properly with the background. You should see the following in the Game view:

Starter Project Screenshot

Credits:

  • The art for the project comes from a free art pack by Vicki Wenderlich! You can find more awesome graphics from her at gameartguppy.
  • The cool music is from BenSound who has some great soundtracks!
  • Thanks goes to Michael Jasper for the impactful camera shake.

Starter project – check!
Assets – check!
The first step towards world domination… ehm, I mean your tower defense game…is done!

X Marks the Spot: Placement

Monsters can only post up at spots marked with an x.

To add these to the scene, drag and drop Images\Objects\Openspot from the Project Browser into the Scene view. For now, position doesn’t matter.

With Openspot selected in the Hierarchy, click Add Component in the Inspector and select Physics 2D\Box Collider 2D. Unity displays the box collider with a green line in the Scene view. You’ll use this collider to detect mouse clicks on that spot.

Unity automatically detects the proper size for the collider. How cool is that?

Unity automatically detects the proper size for the collider. How cool is that?

Following the same steps, add an Audio\Audio Source component to Openspot. Set the Audio Source’s AudioClip to tower_place, which you can find in the Audio folder, and deactivate Play On Awake.

You need to create 11 more spots. While it’s tempting to repeat all those steps, Unity has a great solution for that: Prefabs!

Drag and drop Openspot from the Hierarchy into the Prefabs folder in the Project Browser. Its name then turns blue in the Hierarchy to show that it’s connected to a prefab. Like this:

prefab

Now that you have a prefab, you can create as many copies as you need. Just drag and drop Openspot from the Prefabs folder in the Project Browser into the Scene view. Do this 11 times to make a total of 12 Openspot objects in the scene.

Now use the Inspector to set the positions of these 12 Openspot objects to the following coordinates:

  • (-5.2, 3.5, 0)
  • (-2.2, 3.5, 0)
  • (0.8, 3.5, 0)
  • (3.8, 3.5, 0)
  • (-3.8, 0.4, 0)
  • (-0.8, 0.4, 0)
  • (2.2, 0.4, 0)
  • (5.2, 0.4, 0)
  • (-5.2, -3.0, 0)
  • (-2.2, -3.0, 0)
  • (0.8, -3.0, 0)
  • (3.8, -3.0, 0)

When you’re done, your scene should look like this.

Spot positions for the tower defense game

Place Monsters

To make placing easier, the project’s Prefab folder contains a Monster prefab.

Monster prefab - Ready for use

Monster prefab – Ready for use

At this point, it consists of an empty game object with three different sprites and their shooting animations as their children.

Each sprite represents the monster at a different power level. The prefab also contains an Audio Source component, which you’ll trigger to play a sound whenever the monster shoots a laser.

You’ll now create a script that can place a Monster on an Openspot.

In the Project Browser, select Openspot in the Prefabs folder. In the Inspector, click Add Component, then choose New Script and name it PlaceMonster. Select C Sharp as the Language and click Create and Add. Because you added the script to the Openspot prefab all Openspots in your scene now also have the script attached. Neat!

Double click on the script to open it in MonoDevelop. Then add these two variables:

public GameObject monsterPrefab;
private GameObject monster;

You’ll instantiate a copy of the object stored in monsterPrefab to create a monster, and store it in monster so you can manipulate it during the game.

One Monster Per Location

Add the following method to allow only one monster per location:

private bool canPlaceMonster() {
  return monster == null;
}

In canPlaceMonster() you check whether the monster variable is still null. If so, it means there is currently no monster here and it’s okay to place one.

Now add the following code to actually place a monster when the player clicks this GameObject:

//1
void OnMouseUp () {
  //2
  if (canPlaceMonster ()) {
    //3
    monster = (GameObject) 
      Instantiate(monsterPrefab, transform.position, Quaternion.identity);
    //4
    AudioSource audioSource = gameObject.GetComponent<AudioSource>();
    audioSource.PlayOneShot(audioSource.clip);
 
    // TODO: Deduct gold
  }
}

This code places a monster on mouse click or tap. So how does this work?

  1. Unity automatically calls OnMouseUp when a player taps a GameObject’s physics collider.
  2. When called, this method places a new monster if canPlaceMonster() returns true.
  3. You create the monster with Instantiate, a method that creates an instance of a given prefab with the specified position and rotation. In this case, you copy monsterPrefab, give it the current GameObject’s position and no rotation, cast the result to a GameObject and store it in monster.
  4. Finally, you call PlayOneShot to play the sound effect attached to the object’s AudioSource component.

Now your PlaceMonster script can place a new monster, but you still have to specify the prefab.

Use The Right Prefab

Save the file and switch back to Unity.

To assign the monsterPrefab variable, first select Openspot in the Prefabs folder in the project browser.

In the Inspector, click on the circle to the right of the PlaceMonster (Script) component’s Monster Prefab field, and select Monster from the dialog that appears.

Assign Prefab

That’s it. Run the scene and build monsters on various x spots with a click or tap.

Success! You can build monsters. However they look like a weird mush because all child sprites of your monster are drawn. You’ll fix this next.

Success! You can build monsters. However they look like a weird mush because all child sprites of your monster are drawn. You’ll fix this next.

Level Up Those Monsters

In the image below, you see how your monsters look increasingly horrifying at higher levels.

It's so fluffy! But if you try to steal its cookie this monster can turn into a real killer.

It’s so fluffy! But if you try to steal its cookie, this monster can turn into a killer.

A script acts as the basis for implementing a leveling system for the monsters. It tracks how powerful the monster should be on each level, and of course, the current level of a monster.

Add this script now.

Select Prefabs/Monster in the Project Browser. Add a new C# script named MonsterData. Open the script in MonoDevelop and add the following code above the MonsterData class.

[System.Serializable]
public class MonsterLevel {
  public int cost;
  public GameObject visualization;
}

This creates MonsterLevel. It groups the cost (in gold, which you’ll support later) and the visual representation for a specific monster level.

You add [System.Serializable] at the top to make instances of the class editable from the inspector. This allows you to quickly change all values in the Level class — even while the game is running. It’s incredibly useful for balancing your game.

Define Monster Levels

In this case, you’ll store predefined MonsterLevel in a List<T>.

Why not simply use MonsterLevel[]? Well, you’ll need the index of a particular MonsterLevel object several times. While it’s not difficult to write code for that, you’ll use IndexOf(), which implements the functionality for Lists. No need to reinvent the wheel this time. :]

Reinventing the wheel is usually a bad idea. (from )

Reinventing the wheel is usually a bad idea (from Michael Vroegop)

At the top of MonsterData.cs, add the following using statement:

using System.Collections.Generic;

This gives you access to generic data structures, so you can use the List<T> class in your script.

Note: Generics are a powerful part of C#. They allow you to define type-safe data structures without committing to a type. This is practical for container classes like lists and sets. To learn more about generics, have a look at Introduction to C# Generics.

Now add the following variable to MonsterData to store a list of MonsterLevel:

public List<MonsterLevel> levels;

Using generics, you ensure the levels List can only ever contain MonsterLevel objects.

Save the file and switch to Unity to configure each stage.

Select Prefabs/Monster in the Project Browser. In the Inspector, you can now see a Levels field in the MonsterData (Script) component. Set its size to 3.

Screen Shot 2015-07-24 at 11.26.28 AM

Next, set the cost for each level to the following values:

  • Element 0: 200
  • Element 1: 110
  • Element 2: 120

Now assign the visualization field values.

Expand Prefabs/Monster in the project browser so that you can see its children. Drag and drop the child Monster0 to Element 0‘s visualization field.

Repeat to assign Monster1 to Element 1 and Monster2 to Element 2. See the following GIF that demonstrates this process:

assign-monsters2

When you select the Prefabs/Monster, the prefab should look like this:

Definition of the monsters’ levels in the inspector.

Definition of the monsters’ levels in the inspector.

Define the Current Level

Switch back to MonsterData.cs in MonoDevelop, and add another variable to MonsterData.

private MonsterLevel currentLevel;

In the private variable currentLevel you’ll store the… wait for it … current level of the monster. I bet you did not see that one coming :]

Now set currentLevel and make it accessible to other scripts. Add the following to MonsterData, along with instance variable declarations:

//1
public MonsterLevel CurrentLevel {
  //2
  get {
    return currentLevel;
  }
  //3
  set {
    currentLevel = value;
    int currentLevelIndex = levels.IndexOf(currentLevel);
 
    GameObject levelVisualization = levels[currentLevelIndex].visualization;
    for (int i = 0; i < levels.Count; i++) {
      if (levelVisualization != null) {
        if (i == currentLevelIndex) {
          levels[i].visualization.SetActive(true);
        } else {
          levels[i].visualization.SetActive(false);
        }
      }
    }
  }
}

Quite a bit of C# there, eh? Take it all it turn:

  1. Define a property for the private variable currentLevel. With a property defined, you can call just like any other variable: either as CurrentLevel (from inside the class) or as monster.CurrentLevel (from outside it). You can define custom behavior in a property’s getter or setter method, and by supplying only a getter, a setter or both, you can control whether a property is read-only, write-only or read/write.
  2. In the getter, you return the value of currentLevel.
  3. In the setter, you assign the new value to currentLevel. Next you get the index of the current level. Finally you iterate over all the levels and set the visualization to active or inactive, depending on the currentLevelIndex. This is great because it means that whenever someone sets currentLevel, the sprite updates automatically. Properties sure do come handy!

Add the following implementation of OnEnable:

void OnEnable() {
  CurrentLevel = levels[0];
}

This sets CurrentLevel upon placement, making sure that it shows only the correct sprite.

Note: It’s important to initialize the property in OnEnable instead of OnStart, because you call the order methods when prefabs are instantiated.

OnEnable will be called immediately when you create the prefab (if the prefab was saved in an enabled state), but OnStart isn’t called until after the object starts running as part of the scene.

You’ll need to check this data before you place a monster, so you initialize it in OnEnable.

Save the file and switch to Unity. Run the project and place monsters; now they display the correct and lowest level sprites.

No more mushyness

Upgrade Those Monsters

Switch back to MonoDevelop and add the following method to MonsterData:

public MonsterLevel getNextLevel() {
  int currentLevelIndex = levels.IndexOf (currentLevel);
  int maxLevelIndex = levels.Count - 1;
  if (currentLevelIndex < maxLevelIndex) {
    return levels[currentLevelIndex+1];
  } else {
    return null;
  }
}

In getNextLevel you get the index of currentLevel and the index of the highest level provided the monster did not reach the maximal level to return the next level. Otherwise, return null.

You can use this method to figure out whether upgrading the monster is possible.

Add the following method to increase a monster’s level:

public void increaseLevel() {
  int currentLevelIndex = levels.IndexOf(currentLevel);
  if (currentLevelIndex < levels.Count - 1) {
    CurrentLevel = levels[currentLevelIndex + 1];
  }
}

Here you get the index of the current level, and then you make sure it’s not the maximum level by checking if it’s smaller than levels.Count - 1. If so, set CurrentLevel to the next level.

Test Upgrade Capability

Save the file and then switch to PlaceMonster.cs in MonoDevelop and add this new method:

private bool canUpgradeMonster() {
  if (monster != null) {
    MonsterData monsterData = monster.GetComponent<MonsterData> ();
    MonsterLevel nextLevel = monsterData.getNextLevel();
    if (nextLevel != null) {
      return true;
    }
  }
  return false;
}

First check whether there is a monster that you can upgrade by checking the monster variable for null. If this is the case, you get the current level of the monster from its MonsterData.

Then you test whether a higher level is available, which is when getNextLevel() doesn’t return null. If up-leveling is possible, you return true, otherwise, you return false.

Enable Upgrading With Gold

To enable the upgrade option, add an else if branch to OnMouseUp:

if (canPlaceMonster ()) {
  // Your code here stays the same as before
} else if (canUpgradeMonster()) {
  monster.GetComponent<MonsterData>().increaseLevel();
  AudioSource audioSource = gameObject.GetComponent<AudioSource>();
  audioSource.PlayOneShot(audioSource.clip);
  // TODO: Deduct gold
}

Check whether an upgrade is possible with canUpgradeMonster(). If yes, you access the MonsterData component with GetComponent() and call increaseLevel(), which increases the level of the monster. Lastly, you trigger the monster’s AudioSource.

Save the file and switch back to Unity. Run the game, place and upgrade as many monsters as you like…for now.

Upgrade all the monsters

All the monster upgrades

Pay Gold – Game Manager

Right now it’s possible to build and upgrade all the monsters immediately, but where’s the challenge in that?

Let’s drill down into the issue of the gold. The problem with keeping track of it is that you need to share information between different game objects.

The following image shows all the objects that want a piece of the action.

The highlighted game objects all need to know, how much gold the player owns.

The highlighted game objects all need to know, how much gold the player owns.

You’ll use a shared object that’s accessible to other objects to store this data.

Right-click in the Hierarchy and select Create Empty. Name the new game object GameManager.

Add a C# script named GameManagerBehavior to GameManager, then open the new script in MonoDevelop. You’ll display the player’s total gold in a label, so add the following line to the top of the file:

using UnityEngine.UI;

This lets you access UI-specific classes like Text, which the project uses for the labels. Now add the following variable to the class:

public Text goldLabel;

This will store a reference to the Text component used to display how much gold the player owns.

Now that GameManager knows about the label, how can you ensure the amount of gold stored in your variable and the amount displayed on the label are in sync? You’ll create a property.

Add the following code to GameManagerBehavior:

private int gold;
public int Gold {
  get { return gold; }
  set {
    gold = value;
    goldLabel.GetComponent<Text>().text = "GOLD: " + gold;
  }
}

Seem familiar? It’s similar to the CurrentLevel you defined in Monster. At first, you create a private variable, gold, to store the current gold total. Then you define a property named Gold — creative, right? — and implement a getter and setter.

The getter simply returns the value of gold . The setter is more interesting. In addition to setting the variable’s value, it also sets the text field on goldLabel to display the new amount of gold.

How generous do you feel? Add the following line to Start() to give the player 1000 gold, or less if you feel miserly:

Gold = 1000;

Assign the Label Object to the Script

Save the file and switch to Unity.

In the Hierarchy, select GameManager. In the Inspector, click on the circle to the right of Gold Label. In the Select Text dialog, select the Scene tab and select GoldLabel.

Assign goldLabel

Run the scene and the label displays Gold: 1000.

1000 gold

Check the Player’s “Wallet”

Open PlaceMonster.cs in MonoDevelop, and add the following instance variable:

private GameManagerBehavior gameManager;

You’ll use gameManager to access the GameManagerBehavior component of the scene’s GameManager. To assign it, add the following to Start():

gameManager =
  GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();

You get the GameObject named GameManager using GameObject.Find(), which returns the first game object it finds with the given name. Then, retrieve its GameManagerBehavior component and store it for later.

Note: You could have accomplished this by setting the field in Unity’s editor, or by adding a static method to GameManager that returns a singleton instance from which you could get the GameManagerBehavior.

However, there’s a dark horse method in the block above: Find, which is slower at runtime but convenient and ok to use sparingly.

Get the Money!

You don’t yet deduct gold, so add this line twice inside OnMouseUp(), replacing each of the comments that read // TODO: Deduct gold:

gameManager.Gold -= monster.GetComponent<MonsterData>().CurrentLevel.cost;

Save the file and switch to Unity, upgrade some monsters and watch the Gold readout update. Now you deduct gold, but players can build monsters as long as there is space; they just get into debt.

Infinite credit

Infinite credit? Awesome! But you can’t allow this. Monsters should only be placed when the player has enough gold.

Require Gold for Monsters

Switch to PlaceMonster.cs in MonoDevelop, and replace the contents of canPlaceMonster() with the following:

int cost = monsterPrefab.GetComponent<MonsterData> ().levels[0].cost;
return monster == null && gameManager.Gold >= cost;

Retrieve the cost for placing the monster from levels in its MonsterData. You then check that monster is not null and that gameManager.Gold is bigger than the cost.

Challenge: Add the check for whether a player has enough gold in canUpgradeMonster() by yourself.

Solution Inside SelectShow>

Save and run the scene in Unity. Go ahead, just try to place unlimited monsters!

Limited gold.

Now you can only build a limited amount of monsters.

Tower Politics: Enemies, Waves and Waypoints

Time to “pave the road” for your enemies. Enemies appear at the first waypoint, move towards the next and repeat until they reach your cookie.

You’ll get the enemies marching by:

  1. Defining a road for the enemies to follow
  2. Moving the enemy along the road
  3. Rotating the enemy so it looks forward

Create a Road With Waypoints

Right-click in the Hierarchy and select Create Empty to make a new empty game object. Name it Road, and make sure it’s at position (0, 0, 0).

Now, right-click on Road in the hierarchy and create another empty game object as a child of Road. Name it Waypoint0 and set its position to (-12, 2, 0) — this is where enemies start their assault.

Road - waypoint hierarchy

Create five more waypoints the same way with the following names and positions:

  • Waypoint1: (7, 2, 0)
  • Waypoint2: (7, -1, 0)
  • Waypoint3: (-7.3, -1, 0)
  • Waypoint4: (-7.3, -4.5, 0)
  • Waypoint5: (7, -4.5, 0)

The following screenshot highlights the waypoint locations and the resulting path.

Screen Shot 2015-07-24 at 12.09.11 PM

Spawn the Enemies

Now to make some enemies to follow the road. The Prefabs folder contains an Enemy prefab. Its position is (-20, 0, 0), so new instances will spawn off screen.

Otherwise, it’s set up much like the Monster prefab, with an AudioSource and a child Sprite, and it’s a sprite so you can rotate it later without rotating the forthcoming health bar.

Move Monsters Down the Road

Add a new C# script named MoveEnemy to the Prefabs\Enemy prefab. Open the script in MonoDevelop, and add the following variables:

[HideInInspector]
public GameObject[] waypoints;
private int currentWaypoint = 0;
private float lastWaypointSwitchTime;
public float speed = 1.0f;

waypoints stores a copy of the waypoints in an array, while [HideIninspector] above waypoints ensures you cannot accidentally change the field in the inspector, but you can still access it from other scripts.

currentWaypoint tracks which waypoint the enemy is currently walking away from, and lastWaypointSwitchTime stores the time when the enemy passed over it. Finally, you store the enemy’s speed.

Add this line in Start():

lastWaypointSwitchTime = Time.time;

This initializes lastWaypointSwitchTime to the current time.

To make the enemy move along the path, add the following code to Update():

// 1 
Vector3 startPosition = waypoints [currentWaypoint].transform.position;
Vector3 endPosition = waypoints [currentWaypoint + 1].transform.position;
// 2 
float pathLength = Vector3.Distance (startPosition, endPosition);
float totalTimeForPath = pathLength / speed;
float currentTimeOnPath = Time.time - lastWaypointSwitchTime;
gameObject.transform.position = Vector3.Lerp (startPosition, endPosition, currentTimeOnPath / totalTimeForPath);
// 3 
if (gameObject.transform.position.Equals(endPosition)) {
  if (currentWaypoint < waypoints.Length - 2) {
    // 3.a 
    currentWaypoint++;
    lastWaypointSwitchTime = Time.time;
    // TODO: Rotate into move direction
  } else {
    // 3.b 
    Destroy(gameObject);
 
    AudioSource audioSource = gameObject.GetComponent<AudioSource>();
    AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
    // TODO: deduct health
  }
}

Step by step:

  1. From the waypoints array, you retrieve the start and end position for the current path segment.
  2. Calculate the time needed for the whole distance with the formula time = distance / speed, then determine the current time on the path. Using Vector3.Lerp, you interpolate the current position of the enemy between the segment’s start and end positions.
  3. Check whether the enemy has reached the endPosition. If yes, handle these two possible scenarios:
    1. The enemy is not yet at the last waypoint, so increase currentWaypoint and update lastWaypointSwitchTime. Later, you’ll add code to rotate the enemy so it points in the direction it’s moving, too.
    2. The enemy reached the last waypoint, so this destroys it and triggers a sound effect. Later you’ll add code to decrease the player’s health, too.

Save the file and switch to Unity.

Give the Enemies A Sense of Direction

In its current state, the enemies don’t know the order of the waypoints.

Select Road in the Hierarchy, and add a new C# script named SpawnEnemy. Then open it in MonoDevelop, and add the following variable:

public GameObject[] waypoints;

You’ll use waypoints to store references to the waypoint in the scene in the proper order.

Save the file and switch to Unity. Select Road in the Hierarchy and set the Size of the Waypoints array to 6.

Drag each of Road’s children into the fields, putting Waypoint0 into Element 0, Waypoint1 into Element 1, and so on.

waypoints2

Now you have an array that contains neatly ordered waypoints so there’s a path – note that they never retreat; they will die trying to get a sugar fix.

certaindeath

Check That It All Works

Head to SpawnEnemy in MonoDevelop, and add the following variable:

public GameObject testEnemyPrefab;

This keeps a reference to the Enemy prefab in testEnemyPrefab.

To create an enemy when the script starts, add the following code to Start():

Instantiate(testEnemyPrefab).GetComponent<MoveEnemy>().waypoints = waypoints;

This instantiates a new copy of the prefab stored in testEnemy and assigns it waypoints to follow.

Save the file and switch to Unity. Select Road in the Hierarchy and set its Test Enemy to the Enemy prefab.

Run the project to see the enemy follow the road.

BugFollowsRoadWithoutRotating

Did you notice they aren’t always looking where they’re going? Funny! But you’re trying to be a professional here, yes? Continue with part two to learn how to get them to put their best faces forward.

Where To Go From Here?

You’ve gotten a lot done and are well on your way to having your very own tower defense game.

Players can build monsters, but not an unlimited amount, and there’s an enemy running towards your cookie. Players have gold and can also upgrade monsters.

Download the result here.

In part two, you’ll cover spawning massive waves of enemies and blowing them away. See you in Part Two!

Use the forums below to share your questions, notes, learnings, lightbulb moments and feedback. I look forward to talking with you!

The post How to Create a Tower Defense Game in Unity – Part 1 appeared first on Ray Wenderlich.

Video Tutorial: Intermediate Core Data Part 2: Advanced Attributes


How to Create a Tower Defense Game in Unity – Part 2

$
0
0

blocks-twitter

Welcome to part two of How to Create a Tower Defense Game in Unity. You’re making a tower defense game in Unity, and at the end of part one, you could place and upgrade monsters. You also had one enemy attack the cookie.

However, the enemy had no idea which way to face! Also, it was a poor excuse for an attack. In this part, you’ll add enemy waves and arm your monsters so they can defend your precious cookie.

Getting Started

In Unity, open your completed project from the first part of this tutorial series, or if you’re just joining in now, download the starter project and open TowerDefense-Part2-Starter.

Open GameScene from the Scenes folder.

Rotate the Enemies

At the end of the last tutorial, the enemy followed the road, but appeared to have no idea which way to face.

Open MoveEnemy.cs in MonoDevelop, and add the following method to fix this.

private void RotateIntoMoveDirection() {
  //1
  Vector3 newStartPosition = waypoints [currentWaypoint].transform.position;
  Vector3 newEndPosition = waypoints [currentWaypoint + 1].transform.position;
  Vector3 newDirection = (newEndPosition - newStartPosition);
  //2
  float x = newDirection.x;
  float y = newDirection.y;
  float rotationAngle = Mathf.Atan2 (y, x) * 180 / Mathf.PI;
  //3
  GameObject sprite = (GameObject)
      gameObject.transform.FindChild("Sprite").gameObject;
  sprite.transform.rotation = 
      Quaternion.AngleAxis(rotationAngle, Vector3.forward);
}

RotateIntoMoveDirection rotates the enemy so that it always looks forward, like so:

  1. It calculates the bug’s current movement direction by subtracting the current waypoint’s position from that of the next waypoint.
  2. It uses Mathf.Atan2 to determine the angle toward which newDirection points, in radians, assuming zero points to the right. Multiplying the result by 180 / Mathf.PI converts the angle to degrees.
  3. Finally, it retrieves the child named Sprite and rotates it rotationAngle degrees along the z-axis. Note that you rotate the child instead of the parent so the health bar — you’ll add it soon — remains horizontal.

calculate angles

In Update(), replace the comment // TODO: Rotate into move direction with the following call to RotateIntoMoveDirection:

RotateIntoMoveDirection();

Save the file and switch to Unity. Run the scene; now your monster knows where he’s going.

Your bug should follow the road (Here sped up by factor 20, so it's more fun to watch)

The bug now looks where it’s going.

One single enemy? Hardly impressive. Let the hordes come. And like in every tower defense game, hordes will come in waves!

Inform the Player

Before you set the hordes into motion, you need to let the player know about the coming onslaught. Also, why not display the current wave’s number at the top of the screen?

Several GameObjects need wave information, so you’ll add it to the GameManagerBehavior component on GameManager.

Open GameManagerBehavior.cs in MonoDevelop and add these two variables:

public Text waveLabel;
public GameObject[] nextWaveLabels;

The waveLabel stores a reference to the wave readout at the top right corner of the screen. nextWaveLabels stores the two GameObjects that when combined, create an animation you’ll show at the start of a new wave, as shown below:

nextWaveAnimation

Save the file and switch to Unity. Select GameManager in the Hierarchy. Click on the small circle to the right of Wave Label, and in the Select Text dialog, select WaveLabel in the Scene tab.

Now set the Size of Next Wave Labels to 2. Then assign Element 0 to NextWaveBottomLabel and Element 1 to NextWaveTopLabel the same way as you set Wave Label.

This is what your Game Manager Behavior should look like

This is what your Game Manager Behavior should look like

If the player has lost the game, he shouldn’t see the next wave message. To handle this, switch back to GameManagerBehavior.cs in MonoDevelop and add another variable:

public bool gameOver = false;

In gameOver you’ll store whether the player has lost the game.

Once again, you’ll use a property to keep the game’s elements in sync with the current wave. Add the following code to GameManagerBehavior:

private int wave;
public int Wave {
  get { return wave; }
  set {
    wave = value;
    if (!gameOver) {
      for (int i = 0; i < nextWaveLabels.Length; i++) {
        nextWaveLabels[i].GetComponent<Animator>().SetTrigger("nextWave");
      }
    }
    waveLabel.text = "WAVE: " + (wave + 1);
  }
}

Creating the private variable, property and getter should be second nature by now. But again, the setter is a bit trickier.

You update wave with the new value.

Then you check that the game is not over. If so, you iterate over all labels in nextWaveLabels — those labels have an Animator component. To trigger the animation on the Animator you set the trigger nextWave.

Lastly, you set waveLabel‘s text to the value of wave + 1. Why the +1? – Normal human beings do not start counting at zero. Weird, I know :]

In Start(), set the value of this property:

Wave = 0;

You start counting at Wave number 0.

Save the file, then run the scene in Unity. The Wave readout properly starts at 1.

Internally you start counting with 0, but for the player everything starts with wave 1.

For the player everything starts with wave 1.

Waves: Spawn, Spawn, Spawn

It sounds obvious, but you need to be able to create more enemies to unleash the hordes — right now you can’t do that. Furthermore, you shouldn’t spawn the next wave once the current wave is obliterated — at least for now.

So, the games must be able to recognize whether there are enemies in the scene, and Tags are a good way to identify game objects.

Set Enemy Tags

Select the Enemy prefab in the Project Browser. At the top of the Inspector, click on the Tag dropdown and select Add Tag.

Create Tag

Create a Tag named Enemy.

Create new Tag

Select the Enemy prefab. In the Inspector, set its Tag to Enemy.

Define Enemy Waves

Now you need to define a wave of enemies. Open SpawnEnemy.cs in MonoDevelop, and add the following class implementation before SpawnEnemy:

[System.Serializable]
public class Wave {
  public GameObject enemyPrefab;
  public float spawnInterval = 2;
  public int maxEnemies = 20;
}

Wave holds an enemyPrefab, the basis for instantiating all enemies in that wave, a spawnInterval, the time between enemies in the wave in seconds and the maxEnemies, which is the quantity of enemies spawning in that wave.

This class is Serializable, which means you can change the values in the Inspector.

Add the following variables to the SpawnEnemy class:

public Wave[] waves;
public int timeBetweenWaves = 5;
 
private GameManagerBehavior gameManager;
 
private float lastSpawnTime;
private int enemiesSpawned = 0;

This sets up some variables for spawning that are quite similar to how you moved the enemies along waypoints.
You’ll define the game’s various waves in waves, and track the number of enemies spawned and when you spawned them in enemiesSpawned and lastSpawnTime, respectively.

Players need breaks after all that killing, so set timeBetweenWaves to 5 seconds

Replace the contents of Start() with the following code.

lastSpawnTime = Time.time;
gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();

Here you set lastSpawnTime to the current time, which will be when the script starts as soon as the scene loads. Then you retrieve the GameManagerBehavior in the familiar way.

Add this to Update():

// 1
int currentWave = gameManager.Wave;
if (currentWave < waves.Length) {
  // 2
  float timeInterval = Time.time - lastSpawnTime;
  float spawnInterval = waves[currentWave].spawnInterval;
  if (((enemiesSpawned == 0 && timeInterval > timeBetweenWaves) ||
       timeInterval > spawnInterval) && 
      enemiesSpawned < waves[currentWave].maxEnemies) {
    // 3  
    lastSpawnTime = Time.time;
    GameObject newEnemy = (GameObject)
        Instantiate(waves[currentWave].enemyPrefab);
    newEnemy.GetComponent<MoveEnemy>().waypoints = waypoints;
    enemiesSpawned++;
  }
  // 4 
  if (enemiesSpawned == waves[currentWave].maxEnemies &&
      GameObject.FindGameObjectWithTag("Enemy") == null) {
    gameManager.Wave++;
    gameManager.Gold = Mathf.RoundToInt(gameManager.Gold * 1.1f);
    enemiesSpawned = 0;
    lastSpawnTime = Time.time;
  }
  // 5 
} else {
  gameManager.gameOver = true;
  GameObject gameOverText = GameObject.FindGameObjectWithTag ("GameWon");
  gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
}

Go through this code step by step:

  1. Get the index of the current wave, and check if it’s the last one.
  2. If so, calculate how much time passed since the last enemy spawn and whether it’s time to spawn an enemy. Here you consider two cases. If it’s the first enemy in the wave, you check whether timeInterval is bigger than timeBetweenWaves. Otherwise, you check whether timeInterval is bigger than this wave’s spawnInterval. In either case, you make sure you haven’t spawned all the enemies for this wave.
  3. If necessary, spawn an enemy by instantiating a copy of enemyPrefab. You also increase the enemiesSpawned count.
  4. You check the number of enemies on screen. If there are none and it was the last enemy in the wave you spawn the next wave. You also give the player 10 percent of all gold left at the end of the wave.
  5. Upon beating the last wave this runs the game won animation.

Set Spawn Intervals

Save the file and switch to Unity. Select Road in the Hierarchy. In the Inspector, set the Size of Waves to 4.

For now, set Enemy Prefab to Enemy for all four elements. Set the Spawn Interval and Max Enemies fields as follows:

  • Element 0: Spawn Interval: 2.5, Max Enemies: 5
  • Element 1: Spawn Interval: 2, Max Enemies: 10
  • Element 2: Spawn Interval: 2, Max Enemies: 15
  • Element 3: Spawn Interval: 1, Max Enemies: 5

The final setup should look like the screenshot below.

Waves
Of course, you can play around with those settings to increase or decrease the carnage.
Run the game. Ah-ha! The bugs are marching toward your cookie!

bugs

Optional: Add Different Types of Enemies

No tower defense game is complete with only one type of enemy. Luckily, the Prefabs folder contains another option, Enemy2.

Select Prefabs\Enemy2 in Inspector and add the MoveEnemy script to it. Set its Speed to 3 and its Tag to Enemy. You can now use this speedy bug to keep the player on his toes!

Update Player Health – Killing Me Softly

Even though hordes of bugs storm towards the cookie, the player takes no damage. But no more. The player should take a hit when he lets the enemy encroach.

LivesStolen

Open GameManagerBehavior.cs in MonoDevelop, and add the following two variables:

public Text healthLabel;
public GameObject[] healthIndicator;

You’ll use healthLabel to access the player’s health readout, and healthIndicator to access the five little green cookie-crunching monsters — they simply represent player health in a more fun way than a standard health label.

Manage Health

Next, add a property to maintain the player’s health in GameManagerBehavior:

private int health;
public int Health {
  get { return health; }
  set {
    // 1
    if (value < health) {
      Camera.main.GetComponent<CameraShake>().Shake();
    }
    // 2
    health = value;
    healthLabel.text = "HEALTH: " + health;
    // 3
    if (health <= 0 && !gameOver) {
      gameOver = true;
      GameObject gameOverText = GameObject.FindGameObjectWithTag ("GameOver");
      gameOverText.GetComponent<Animator>().SetBool("gameOver", true);
    }
    // 4 
    for (int i = 0; i < healthIndicator.Length; i++) {
      if (i < Health) {
        healthIndicator[i].SetActive(true);
      } else {
        healthIndicator[i].SetActive(false);
      }
    }
  }
}

This manages the player’s health. Once again, the bulk of the code is in the setter:

  1. If you’re reducing the player’s health, use the CameraShake component to create a nice shake effect. This script is included with the project and not covered here.
  2. Update the private variable and the health label in the top left corner of the screen.
  3. If health drops to 0 and it’s not yet game over, set gameOver to true and trigger the GameOver animation.
  4. Remove one of the monsters from the cookie. If it just disabled them, this bit could be written more simply, but it also supports re-enabling them when you add health.

Initialize Health in Start():

Health = 5;

You set Health to 5 when the scene starts playing.

With this property in place, you can now update the player’s health whenever a bug reaches the cookie. Save this file and then switch to MoveEnemy.cs, still in MonoDevelop.

Update Health

To update the player’s health, find the comment in Update() that reads // TODO: deduct health and replace it with this code:

GameManagerBehavior gameManager =
    GameObject.Find("GameManager").GetComponent<GameManagerBehavior>();
gameManager.Health -= 1;

This gets the GameManagerBehavior and subtracts one from its Health.

Save the file and switch to Unity.

Select GameManager in the Hierarchy and set its Health Label to HealthLabel.

Expand Cookie in the Hierarchy and drag and drop its five HealthIndicator children into GameManager’s Health Indicator array — the health indicators are the tiny green monsters happily eating their cookie.

Play the scene and wait for the bugs to reach the cookie. Do nothing until you lose.

cookie-attack

Monster Wars: The Revenge of the Monsters

Monsters in place? Check. Enemies advancing? Check — and they look mean! Time to mow those suckers down!

This requires several things:

  • A health bar, so the player knows which enemies are strong and weak
  • Detection of enemies within the range of a monster
  • Decision points — which enemy to fire upon
  • Lots of bullets

Enemy Health Bar

You’ll use two images to implement the health bar, one for a dark background and a slightly smaller green bar you’ll scale to match the enemy’s health.

Drag Prefabs\Enemy into the scene from the Project Browser.

Then drag Images\Objects\HealthBarBackground onto Enemy in the Hierarchy to add it as a child.

In the Inspector, set the Position for HealthBarBackground to (0, 1, -4).

Next, select Images\Objects\HealthBar in the Project Browser and ensure its Pivot is set to Left. Then, add it as a child of Enemy in the Hierarchy and set its Position to (-0.63, 1, -5). Set its X Scale to 125.

Add a new C# script named HealthBar to the HealthBar game object. Later, you’ll edit it to adjust length of the health bar.

With Enemy selected in the Hierarchy, make sure it’s position is (20, 0, 0).

Click on Apply at the top of the Inspector to save all your changes as part of the prefab. Finally, delete Enemy from the Hierarchy.

Bug with healthbar

Now, repeat those steps to add the health bar to Prefabs\Enemy2.

Adjust Health Bar Length

Open HealthBar.cs in MonoDevelop, and add the following variables:

public float maxHealth = 100;
public float currentHealth = 100;
private float originalScale;

maxHealth stores the enemy’s maximal health points, and currentHealth tracks how much health remains. Lastly, originalScale remembers the health bar’s original size.

Store the object’s originalScale in Start():

originalScale = gameObject.transform.localScale.x;

You save the localScale‘s x value.

Set the health bar’s scale by adding the following to Update():

Vector3 tmpScale = gameObject.transform.localScale;
tmpScale.x = currentHealth / maxHealth * originalScale;
gameObject.transform.localScale = tmpScale;

You copy localScale to a temporary variable because you cannot adjust only its x value. Then, calculate a new x scale based on the bug’s current health, and set the temporary variable back on localScale.

Save the file and run the game in Unity. You’ll see health bars above the enemies.

Resistance is futile! - Wait, what resistance?

While the game runs, expand one of the Enemy(Clone) objects in the Hierarchy and select its HealthBar child. Change its Current Health value and check for that health bar to change.

AdjustHealthbar

Track Enemies in Range

Now the monsters need to know which enemies to target. You have a bit of prework to do on the Monster and the Enemy before you implement.

Select Prefabs\Monster in the Project Browser and add a Circle Collider 2D component to it in the Inspector.

Set the collider’s Radius to 2.5 — this sets the monsters’ firing range.

Check Is Trigger so that objects pass through the area rather than bump into it.

Finally, at the top of the Inspector, set Monster’s Layer to Ignore Raycast. Click Yes, change children in the dialog. If you don’t ignore raycasts, the collider reacts to click events. That is a problem because the Monsters block events meant for the Openspots below them.

Bildschirmfoto 2015-06-05 um 14.47.15

To allow detection of an enemy in the trigger area, you need to add a collider and rigid body to it, because Unity only sends trigger events if one of the colliders has a rigid body attached.

In the Project Browser, select Prefabs\Enemy. Add a Rigid Body 2D component with Is Kinematic checked. This means the body shouldn’t be affected by physics.

Add a Circle Collider 2D with a Radius of 1. Repeat those steps for Prefabs\Enemy 2

The triggers are now set up, so monsters detect when an enemy is in range.

You need to prepare one more thing: A script that notifies monsters when an enemy is destroyed so they don’t cause an exception by continuing to fire.

Create a new C# script named EnemyDestructionDelegate and add it to both the Enemy and Enemy2 prefabs.

Open EnemyDestructionDelegate.cs in MonoDevelop, and add the following delegate declaration:

public delegate void EnemyDelegate (GameObject enemy);
public EnemyDelegate enemyDelegate;

Here you create a delegate, which is a container for a function that can be passed around like a variable.

Note: Use delegates when you want one game object to actively notify other game objects of changes. Learn more about delegates from the Unity documentation.

Add the following method:

void OnDestroy () {
  if (enemyDelegate != null) {
    enemyDelegate (gameObject);
  }
}

Upon destruction of a game object, Unity calls this method automatically, and it checks whether the delegate is not null. In that case, you call it with the gameObject as a parameter. This lets all listeners that are registered as delegates know the enemy was destroyed.

Save the file and go back to Unity.

Give Monsters a License to Kill

And now the monsters can detect enemies in range. Add a new C# script to the Monster prefab and name it ShootEnemies.

Open ShootEnemies.cs in MonoDevelop, and add the following using statement to get access to Generics.

using System.Collections.Generic;

Add a variable to keep track of all enemies within range:

public List<GameObject> enemiesInRange;

In enemiesInRange, you’ll store all enemies that are in range.

Initialize the field in Start().

enemiesInRange = new List<GameObject>();

In the beginning, there are no enemies in range, so you create an empty list.

Fill the enemiesInRange list! Add this code to the script:

// 1
void OnEnemyDestroy (GameObject enemy) {
  enemiesInRange.Remove (enemy);
}
 
void OnTriggerEnter2D (Collider2D other) {
// 2
  if (other.gameObject.tag.Equals("Enemy")) {
    enemiesInRange.Add(other.gameObject);
    EnemyDestructionDelegate del =
        other.gameObject.GetComponent<EnemyDestructionDelegate>();
    del.enemyDelegate += OnEnemyDestroy;
  }
}
// 3
void OnTriggerExit2D (Collider2D other) {
  if (other.gameObject.tag.Equals("Enemy")) {
    enemiesInRange.Remove(other.gameObject);
    EnemyDestructionDelegate del =
        other.gameObject.GetComponent<EnemyDestructionDelegate>();
    del.enemyDelegate -= OnEnemyDestroy;
  }
}
  1. In OnEnemyDestroy, you remove the enemy from enemiesInRange. When an enemy walks on the trigger around your monster OnTriggerEnter2D is called.
  2. You then add the enemy to the list of enemiesInRange and add OnEnemyDestroy to the EnemyDestructionDelegate. This makes sure that OnEnemyDestroy is called when the enemy is destroyed. You don’t want monsters to waste ammo on dead enemies now — do you?
  3. In OnTriggerExit2D you remove the enemy from the list and unregister your delegate. Now you know which enemies are in range.
  4. Save the file and then run the game in Unity. To test whether it works, place a monster, select it and watch the changes to the enemiesInRange list in the Inspector.

    Feels like counting sheep

    Feels like counting sheep. Fence and sheep form OpenClipArt

    Select a Target

    Now monsters know which enemy is in range. But what do they do when there are multiple in-range enemies?

    They attack the one closest to the cookie, of course!

    Open MoveEnemy.cs in MonoDevelop, and add this new method to calculates this:

    public float distanceToGoal() {
      float distance = 0;
      distance += Vector3.Distance(
          gameObject.transform.position, 
          waypoints [currentWaypoint + 1].transform.position);
      for (int i = currentWaypoint + 1; i < waypoints.Length - 1; i++) {
        Vector3 startPosition = waypoints [i].transform.position;
        Vector3 endPosition = waypoints [i + 1].transform.position;
        distance += Vector3.Distance(startPosition, endPosition);
      }
      return distance;
    }

    This code calculates the length of road not yet traveled by the enemy. It does so using Distance, which calculates the difference between two Vector3 instances.

    You’ll use this method later to figure out which target to attack. However, your monsters are unarmed and helpless, so fix that first.

    yunofire

    Save the file and go back to Unity to begin setting up your bullets.

    Give Monsters Bullets – Lots of Bullets!

    Drag and drop Images/Objects/Bullet1 from the Project Browser into the scene. Set z position to -2 — x and y positions don’t matter because you set them each time you instantiate a new bullet at run time.

    Add a new C# script named BulletBehavior, and add the following variables to it in MonoDevelop:

    public float speed = 10;
    public int damage;
    public GameObject target;
    public Vector3 startPosition;
    public Vector3 targetPosition;
     
    private float distance;
    private float startTime;
     
    private GameManagerBehavior gameManager;

    speed determines how quickly bullets fly; damage is self-explanatory.

    The target, startPosition, and targetPosition determine the bullet’s direction.

    distance and startTime track the bullet’s current position. gameManager rewards players when they crush an enemy.

    Assign values to these variables in Start():

    startTime = Time.time;
    distance = Vector3.Distance (startPosition, targetPosition);
    GameObject gm = GameObject.Find("GameManager");
    gameManager = gm.GetComponent<GameManagerBehavior>();

    You set startTime to the current time and calculate the distance between the start and target positions. You also get the GameManagerBehavior as usual.

    Add the following code to Update() to controls the bullet movement:

    // 1 
    float timeInterval = Time.time - startTime;
    gameObject.transform.position = Vector3.Lerp(startPosition, targetPosition, timeInterval * speed / distance);
     
    // 2 
    if (gameObject.transform.position.Equals(targetPosition)) {
      if (target != null) {
        // 3
        Transform healthBarTransform = target.transform.FindChild("HealthBar");
        HealthBar healthBar = 
            healthBarTransform.gameObject.GetComponent<HealthBar>();
        healthBar.currentHealth -= Mathf.Max(damage, 0);
        // 4
        if (healthBar.currentHealth <= 0) {
          Destroy(target);
          AudioSource audioSource = target.GetComponent<AudioSource>();
          AudioSource.PlayClipAtPoint(audioSource.clip, transform.position);
     
          gameManager.Gold += 50;
        }
      }
      Destroy(gameObject);
    }
    1. You calculate the new bullet position using Vector3.Lerp to interpolate between start and end positions.
    2. If the bullet reaches the targetPosition, you verify that target still exists.
    3. You retrieve the target’s HealthBar component and reduce its health by the bullet’s damage.
    4. If the health of the enemy falls to zero, you destroy it, play a sound effect and reward the player for marksmanship.

    Save the file and return to Unity.

    Get Bigger Bullets

    Wouldn’t it be cool if your monster shot bigger bullets at higher levels? – Yes, yes, it would! Fortunately, this is easy to implement.

    Drag and drop the Bullet1 game object from the Hierarchy to the Project tab to create a prefab of the bullet. Remove the original object from the scene — you don’t need it anymore.

    Duplicate the Bullet1 prefab twice. Name the copies Bullet2 and Bullet3.

    Select Bullet2. In the Inspector, set the Sprite Renderer component’s Sprite field to Images/Objects/Bullet2. This makes Bullet2 look a bit bigger than Bullet1.

    Repeat that procedure to set the Bullet3 prefab’s sprite to Images/Objects/Bullet3.

    Next, set how much damage the bullets deliver in Bullet Behavior.

    Select the Bullet1 prefab in the Project tab. In Inspector you can see the Bullet Behavior (Script), and there you set the Damage to 10 for Bullet1, 15 for Bullet2, and 20 for Bullet3 — or whatever makes you happy there.

    Note: I set the values so that at higher levels, the cost per damage is higher. This counteracts the fact that the upgrade allows the player to improve the monsters in the best spots.

    Bullet prefabs - size increases with level

    Bullet prefabs – size increases with level

    Leveling the Bullets

    Assign different bullets to different monster levels so stronger monsters shred enemies faster.

    Open MonsterData.cs in MonoDevelop, and add these variables to MonsterLevel:

    public GameObject bullet;
    public float fireRate;

    These will set the bullet prefab and fire rate for each monster level. Save the file and head back to Unity to finish setting up your monsters.

    Select the Monster prefab in the Project Browser. In the Inspector, expand Levels in the Monster Data (Script) component. Set Fire Rate to 1 for each of the elements. Then set Bullet for Elements 0, 1 and 2 to Bullet1, Bullet2 and Bullet3, respectively.

    Your monster levels should be configured as shown below:

    MonsterData with bullets

    Bullets to kill your enemies? – Check! Open fire!

    Pew Pew - lasers ! (from Gisela Giardino)

    Pew Pew – lasers ! (from Gisela Giardino)

    Open Fire

    Open the ShootEnemies.cs in MonoDevelop, and add some variables:

    private float lastShotTime;
    private MonsterData monsterData;

    As their names suggest, these variables keep track of when this monster last fired, as well the MonsterData structure that includes information about this monster’s bullet type, fire rate, etc.

    Assign values to those fields in Start():

    lastShotTime = Time.time;
    monsterData = gameObject.GetComponentInChildren<MonsterData> ();

    Here you set lastShotTime to the current time and get access to this object’s MonsterData component.

    Add the following method to implement shooting:

    void Shoot(Collider2D target) {
      GameObject bulletPrefab = monsterData.CurrentLevel.bullet;
      // 1 
      Vector3 startPosition = gameObject.transform.position;
      Vector3 targetPosition = target.transform.position;
      startPosition.z = bulletPrefab.transform.position.z;
      targetPosition.z = bulletPrefab.transform.position.z;
     
      // 2 
      GameObject newBullet = (GameObject)Instantiate (bulletPrefab);
      newBullet.transform.position = startPosition;
      BulletBehavior bulletComp = newBullet.GetComponent<BulletBehavior>();
      bulletComp.target = target.gameObject;
      bulletComp.startPosition = startPosition;
      bulletComp.targetPosition = targetPosition;
     
      // 3 
      Animator animator = 
          monsterData.CurrentLevel.visualization.GetComponent<Animator> ();
      animator.SetTrigger ("fireShot");
      AudioSource audioSource = gameObject.GetComponent<AudioSource>();
      audioSource.PlayOneShot(audioSource.clip);
    }
    1. Get the start and target positions of the bullet. Set the z-Position to that of bulletPrefab. Earlier, you set the bullet prefab’s z position value to make sure the bullet appears behind the monster firing it, but in front of the enemies.
    2. Instantiate a new bullet using the bulletPrefab for MonsterLevel. Assign the startPosition and targetPosition of the bullet.
    3. Make the game juicier: Run a shoot animation and play a laser sound whenever the monster shoots.

    Put it All Together

    Time to wire everything together. Determine the target and make your monster watch it.
    watchingYou

    Still in ShootEnemies.cs, add this code to Update():

    GameObject target = null;
    // 1
    float minimalEnemyDistance = float.MaxValue;
    foreach (GameObject enemy in enemiesInRange) {
      float distanceToGoal = enemy.GetComponent<MoveEnemy>().distanceToGoal();
      if (distanceToGoal < minimalEnemyDistance) {
        target = enemy;
        minimalEnemyDistance = distanceToGoal;
      }
    }
    // 2
    if (target != null) {
      if (Time.time - lastShotTime > monsterData.CurrentLevel.fireRate) {
        Shoot(target.GetComponent<Collider2D>());
        lastShotTime = Time.time;
      }
      // 3
      Vector3 direction = gameObject.transform.position - target.transform.position;
      gameObject.transform.rotation = Quaternion.AngleAxis(
          Mathf.Atan2 (direction.y, direction.x) * 180 / Mathf.PI,
          new Vector3 (0, 0, 1));
    }

    Go through this code step by step.

    1. Determine the target of the monster. Start with the maximum possible distance in the minimalEnemyDistance. Iterate over all enemies in range and make an enemy the new target if its distance to the cookie is smaller than the current minimum.
    2. Call Shoot if the time passed is greater than the fire rate of your monster and set lastShotTime to the current time.
    3. Calculate the rotation angle between the monster and its target. You set the rotation of the monster to this angle. Now it always faces the target.

    Save the file andplay the game in Unity. Your monsters vigorously defend your cookie. You’re totally, completely DONE!

    Where to go From Here

    You can download the finished project here.

    Wow, so you really did a lot between both tutorials and you have a cool game to show for it.
    Here are a few ideas to build on what you’ve done:

  • More enemy types and monsters
  • Multiple enemy paths
  • Different levels

Each of these ideas requires minimal changes and can make your game addictive. If you created a new game from this tutorial, we’d love to play it — so share the link and your brags in the comments.

You can find interesting thoughts on making a hit tower defense game in this interview.

Thank you for taking the time to work through these tutorials. I look forward to seeing your awesome concepts and killing lots of monsters.

The post How to Create a Tower Defense Game in Unity – Part 2 appeared first on Ray Wenderlich.

RWDevCon 2016: Last Chance for Early Bird Discount!

$
0
0

This is just a quick note to remind you that the early bird discount for RWDevCon 2016 ends in just a few hours!

As explained in the previous post, RWDevCon is something really special, due to its focus on hands-on tutorials, 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 seeing you in DC! :]

The post RWDevCon 2016: Last Chance for Early Bird Discount! appeared first on Ray Wenderlich.

How to Play, Record, and Merge Videos in iOS and Swift

$
0
0
Learn how to play, record, and merge videos on iOS!

Learn how to play, record, and merge videos on iOS!

Update note: This tutorial was updated for iOS 8 and Swift by Andy Pereira. Original post by Abdul Azeem with fixes and clarifications made by Joseph Neuman.

Recording videos (and playing around with them programmatically) is one of the coolest things you can do with your phone, but not nearly enough apps make use of it. To do this requires the AV Foundation framework that has been a part of OS X since Lion (10.7), and Apple added it to iOS 4 in 2010.

AV Foundation has grown considerably since then, with well over 100 classes now. This tutorial covers media playback and some light editing to get you started with AV Foundation. In particular, you’ll learn how to:

  • Select and play a video from the media library.
  • Record and save a video to the media library.
  • Merge multiple videos together into a combined video, complete with a custom soundtrack!

If you run the code in this tutorial on the simulator, you’ll have no way to capture video. Plus, you’ll need to figure out a way to add videos to the media library manually. In other words, you really need to test this code on a device! To do that you’ll need to be a registered Apple developer .

Are you ready? Lights, cameras, action!

Getting Started

Download the starter project. This project contains a storyboard and several view controllers with the UI for a simple video playback and recording app.

The main screen contains the three buttons below that segue to other view controllers.

  • Select and Play Video
  • Record and Save Video
  • Merge Video

Build and run the project, and test out the buttons; only the three buttons on the initial scene do anything, but you will change that soon!

Select and Play Video

The “Play Video” button on the main screen segues to PlayVideoController. In this section of the tutorial, you’ll add the code to select a video file and play it.

Start by opening PlayVideoViewController.swift, and add the following import statements at the top of the file:

import MediaPlayer
import MobileCoreServices

Importing MediaPlayer gives you access to the MediaPlayer object that plays the selected video. MobileCoreServices contains predefined constants such as kUTTypeMovie, which you’ll need to refer to when selecting videos.

Next, scroll down to the end of the file and add the following class extensions. You need to add these to the very bottom of the file, outside the curly braces of the class declaration:

// MARK: - UIImagePickerControllerDelegate
extension PlayVideoViewController: UIImagePickerControllerDelegate {
}
 
// MARK: - UINavigationControllerDelegate
extension PlayVideoViewController: UINavigationControllerDelegate {
}

These extensions set up the PlayVideoViewController to adopt the UIImagePickerControllerDelegate and UINavigationControllerDelegate protocols. You’ll be using the system-provided UIImagePickerController to allow the user to to browse videos in the photo library, and that class communicates back to your app through these delegate protocols. Although the class is named “image picker”, rest assured it works with videos too!

Next, head back to the main class definition and add the implementation for the following helper method to open the image picker:

func startMediaBrowserFromViewController(viewController: UIViewController, usingDelegate delegate: protocol<UINavigationControllerDelegate, UIImagePickerControllerDelegate>) -> Bool {
  // 1
  if UIImagePickerController.isSourceTypeAvailable(.SavedPhotosAlbum) == false {
    return false
  }
 
  // 2
  var mediaUI = UIImagePickerController()
  mediaUI.sourceType = .SavedPhotosAlbum
  mediaUI.mediaTypes = [kUTTypeMovie as NSString]
  mediaUI.allowsEditing = true
  mediaUI.delegate = delegate
 
  // 3
  presentViewController(mediaUI, animated: true, completion: nil)
  return true
}

In the above code, you do the following:

  1. Check if the .SavedPhotosAlbum source is available on the device. Other sources are the camera itself and the photo library. This check is essential whenever you use a UIImagePickerController to pick media. If you don’t do it, you might try to pick media from a non-existent media library, resulting in crashes or other unexpected issues.
  2. If the source you want is available, you create a UIImagePickerController object and set its source and media type. Notice the mediaTypes array only includes kUTTypeMovie, which will filter the results to only include video.
  3. Finally, you present the UIImagePickerController modally.

Now add the following code to playVideo(_:):

startMediaBrowserFromViewController(self, usingDelegate: self)

The above code ensures that tapping the “Play Video” button will open the UIImagePickerController, allowing the user to select a video file from the media library.

Now you’re ready to give your project another whirl! Build and run. When you tap the “Select and Play Video” button on the first screen, and then tap the “Play Video” button on the second screen, you should see your videos presented similar to the following screenshot.

vpr_swift_5

Once you see the list of videos, select one. You’ll be taken to another screen that shows the video in detail, along with buttons to cancel, play and “choose”. If you tap the play button the video will play. However, if you tap the choose button, the app just returns to the Play Video screen! This is because you haven’t implemented any delegate methods to handle choosing a video from the picker.

Back in Xcode, scroll down to the UIImagePickerControllerDelegate class extension and add the following delegate method implementation:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
  // 1
  let mediaType = info[UIImagePickerControllerMediaType] as! NSString
 
  // 2
  dismissViewControllerAnimated(true) {
    // 3
    if mediaType == kUTTypeMovie {
      let moviePlayer = MPMoviePlayerViewController(contentURL: info[UIImagePickerControllerMediaURL] as! NSURL)
      self.presentMoviePlayerViewControllerAnimated(moviePlayer)
    }
  }
}

Here’s what’s going on in this method:

  1. Get the media type of the selected media; you’ll check this just a few lines of code later.
  2. Dismiss the image picker.
  3. In the completion block, verify that the selected media is a video file. If so, get a reference to the video file URL and pass that to a new an instance of MPMoviePlayerViewController to play it.

Build and run. Press the “Select and Play Video” button, then the “Play Video” button, and finally choose a video from the list. You should be able to see the video playing in the media player.

vpr_swift_5

vpr_swift_6

Record and Save Video

Now that you have video playback working, it’s time to record a video using the device’s camera and save it to the media library.

Open RecordVideoViewController.swift, and add the following import:

import MobileCoreServices

You’ll also need to adopt the same protocols as PlayVideoViewController, by adding the following to the end of the file:

extension RecordVideoViewController: UIImagePickerControllerDelegate {
}
 
extension RecordVideoViewController: UINavigationControllerDelegate {
}

Add the following code to RecordVideoViewController:

func startCameraFromViewController(viewController: UIViewController, withDelegate delegate: protocol<UIImagePickerControllerDelegate, UINavigationControllerDelegate>) -> Bool {
  if UIImagePickerController.isSourceTypeAvailable(.Camera) == false {
    return false
  }
 
  var cameraController = UIImagePickerController()
  cameraController.sourceType = .Camera
  cameraController.mediaTypes = [kUTTypeMovie as NSString]
  cameraController.allowsEditing = false
  cameraController.delegate = delegate
 
  presentViewController(cameraController, animated: true, completion: nil)
  return true
}

This method follows the same logic is in PlayVideoViewController, but it accesses the .Camera instead to record video.

Now add the following to record(_:):

startCameraFromViewController(self, withDelegate: self)

You are again in familiar territory. The code simply calls startCameraControllerFromViewController(_:usingDelegate:) when you tap the “Record Video” button.

Build and run to see what you’ve got so far.

Go to the Record screen and press the “Record Video” button. Instead of the Photo Gallery, the camera UI opens. Start recording a video by tapping the red record button at the bottom of the screen, and tap it again when you’re done recording.

vpr_swift_8

When you get to the next screen, you can opt to use the recorded video or re-take the video. If you select “Use,” you’ll notice that nothing happens – that’s because, you guessed it, you haven’t implemented an appropriate callback method. You need the callback method to save the recorded video to the media library.

Add the following method to the UIImagePickerControllerDelegate class extension:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
  let mediaType = info[UIImagePickerControllerMediaType] as! NSString
  dismissViewControllerAnimated(true, completion: nil)
  // Handle a movie capture
  if mediaType == kUTTypeMovie {
    let path = (info[UIImagePickerControllerMediaURL] as! NSURL).path
    if UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path) {
      UISaveVideoAtPathToSavedPhotosAlbum(path, self, "video:didFinishSavingWithError:contextInfo:", nil)
    }
  }
}

As before, the delegate method gives you a URL pointing to the video. You verify that the app can save the file to the device’s photo album, and if so, save it.

UISaveVideoAtPathToSavedPhotosAlbum is the function provided by the SDK to save videos to the Photos Album. As parameters, you pass the path to the video you want to save as well as a target and action to call back, which will inform you of the status of the save operation.

Add the implementation of the callback to the main class definition next:

func video(videoPath: NSString, didFinishSavingWithError error: NSError?, contextInfo info: AnyObject) {
  var title = "Success"
  var message = "Video was saved"
 
  if let saveError = error {
    title = "Error"
    message = "Video failed to save"
  }
 
  let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
  alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
  presentViewController(alert, animated: true, completion: nil)
}

The callback method simply displays an alert to the user, telling them whether saving the video file was successful or not based on the error status.

Build and run. Record a video and select “Use” when you stop recording. If the “Video was saved” alert pops up, you just successfully saved your video to the photo library!

vpr_swift_9

Now that you can play videos and record videos, it’s time to take the next step and try some light video editing.

Merging Videos

The final piece of functionality for the app is to do a little editing. The user will select two videos and a song from the music library, and the app will combine the two videos and mix in the music.

The project already has a starter implementation in MergeVideoViewController.swift. The code here is similar to the code you wrote to play a video. The big difference is when merging, the user needs to select two videos. That part is already set up, so the user can make two selections that will be stored in firstAsset and secondAsset.

The next step is to add the functionality to select the audio file.

The UIImagePickerController only provides functionality to select video and images from the media library. To select audio files from your music library, you will use the MPMediaPickerController. It works essentially the same as UIImagePickerController, but instead of images and video, it accesses audio files in the media library.

Open MergeVideoViewController.swift and add the following code to loadAudio(_:):

let mediaPickerController = MPMediaPickerController(mediaTypes: .Any)
mediaPickerController.delegate = self
mediaPickerController.prompt = "Select Audio"
presentViewController(mediaPickerController, animated: true, completion: nil)

The above code creates a new MPMediaPickerController instance and displays it as a modal view controller.

Build and run. Now when you tap the “Load Audio” button, you can access the audio library on your device. Of course, you’ll need some audio files on your device. Otherwise, the list will be empty. The songs will also have to be physically present on the device, so make sure you’re not trying to load a song from the cloud.

vpr_swift_12

If you select a song from the list, you’ll notice that nothing happens. That’s right, MPMediaPickerController needs delegate methods! Find the MPMediaPickerControllerDelegate class extension at the bottom of the file and add the following two methods to it:

func mediaPicker(mediaPicker: MPMediaPickerController!, didPickMediaItems mediaItemCollection: MPMediaItemCollection!) {
  let selectedSongs = mediaItemCollection.items
  if selectedSongs.count > 0 {
    let song = selectedSongs[0] as! MPMediaItem
    if let url = song.valueForProperty(MPMediaItemPropertyAssetURL) as? NSURL {
      audioAsset = (AVAsset.assetWithURL(url) as! AVAsset)
      dismissViewControllerAnimated(true, completion: nil)
      let alert = UIAlertController(title: "Asset Loaded", message: "Audio Loaded", preferredStyle: .Alert)
      alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler:nil))
      presentViewController(alert, animated: true, completion: nil)
    } else {
      dismissViewControllerAnimated(true, completion: nil)
      let alert = UIAlertController(title: "Asset Not Available", message: "Audio Not Loaded", preferredStyle: .Alert)
      alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler:nil))
      presentViewController(alert, animated: true, completion: nil)
    }
  } else {
      dismissViewControllerAnimated(true, completion: nil)
  }
}
 
func mediaPickerDidCancel(mediaPicker: MPMediaPickerController!) {
  dismissViewControllerAnimated(true, completion: nil)
}

The code is very similar to the delegate methods for UIImagePickerController. You set the audio asset based on the media item selected via the MPMediaPickerController after ensuring it’s a valid media item.

Build and run, and go to the Merge Videos screen. Select an audio file and if there are no errors, you should see the “Audio Loaded” message.

vpr_swift_13

You now have all your assets loading correctly. It’s time to merge the various media files into one file.
But before you get into that code, you have to do a little bit of set up.

Export and Merge

The code to merge your assets will require a completion handler to export the final video to the photos album.
Add the code below to MergeVideoViewController.

func exportDidFinish(session: AVAssetExportSession) {
  if session.status == AVAssetExportSessionStatus.Completed {
    let outputURL = session.outputURL
    let library = ALAssetsLibrary()
    if library.videoAtPathIsCompatibleWithSavedPhotosAlbum(outputURL) {
      library.writeVideoAtPathToSavedPhotosAlbum(outputURL,
        completionBlock: { (assetURL:NSURL!, error:NSError!) -> Void in
          var title = ""
          var message = ""
          if error != nil {
            title = "Error"
            message = "Failed to save video"
          } else {
            title = "Success"
            message = "Video saved"
          }
          let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
          alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
          self.presentViewController(alert, animated: true, completion: nil)
      })
    }
  }
 
  activityMonitor.stopAnimating()
  firstAsset = nil
  secondAsset = nil
  audioAsset = nil
}

Once the export completes successfully, the above code saves the newly exported video to the photo album. You could just display the output video in an AssetBrowser, but it’s easier to copy the output video to the photo album so you can see the final output.

Now, add the following code to merge(_:):

if let firstAsset = firstAsset, secondAsset = secondAsset {
  activityMonitor.startAnimating()
 
  // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
  var mixComposition = AVMutableComposition()
 
  // 2 - Video track
  let videoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
  videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAsset.duration),
    ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack,
    atTime: kCMTimeZero,
    error: nil)
  videoTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAsset.duration),
    ofTrack: secondAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack,
    atTime: firstAsset.duration,
    error: nil)
 
  // 3 - Audio track
  if let loadedAudioAsset = audioAsset {
    let audioTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: 0)
    audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration)),
      ofTrack: loadedAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] as! AVAssetTrack,
      atTime: kCMTimeZero,
      error: nil)
  }
 
  // 4 - Get path
  let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
  var dateFormatter = NSDateFormatter()
  dateFormatter.dateStyle = .LongStyle
  dateFormatter.timeStyle = .ShortStyle
  let date = dateFormatter.stringFromDate(NSDate())
  let savePath = documentDirectory.stringByAppendingPathComponent("mergeVideo-\(date).mov")
  let url = NSURL(fileURLWithPath: savePath)
 
  // 5 - Create Exporter
  let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
  exporter.outputURL = url
  exporter.outputFileType = AVFileTypeQuickTimeMovie
  exporter.shouldOptimizeForNetworkUse = true
 
  // 6 - Perform the Export
  exporter.exportAsynchronouslyWithCompletionHandler() {
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
      self.exportDidFinish(exporter)
    })
  }
}

Here’s a step-by-step breakdown of the above code:

  1. You create an AVMutableComposition object to hold your video and audio tracks and transform effects.
  2. Next, you create an AVMutableCompositionTrack for the video and add it to your AVMutableComposition object. Then you insert your two videos to the newly created AVMutableCompositionTrack.

    Note that insertTimeRange(_:ofTrack:atTime:error:) allows you to insert a part of a video into your main composition instead of the whole video. This way, you can trim the video to a time range of your choosing.

    In this instance, you want to insert the whole video, so you create a time range from kCMTimeZero to your video asset duration. The atTime parameter allows you to place your video/audio track wherever you want it in your composition. Notice how the code inserts firstAsset at time zero, and it inserts secondAsset at the end of the first video. This tutorial assumes you want your video assets one after the other. But you can also overlap the assets by playing with the time ranges.

    For working with time ranges, you use CMTime structs. CMTime structs are non-opaque mutable structs representing times, where the time could be a timestamp or a duration.

  3. Similarly, you create a new track for your audio and add it to the main composition. This time you set the audio time range to the sum of the duration of the first and second videos, since that will be the complete length of your video.
  4. Before you can save the final video, you need a path for the saved file. So create a unique file name (based upon the current date) that points to a file in the documents folder.
  5. Finally, render and export the merged video. To do this, you create an AVAssetExportSession object that transcodes the contents of an AVAsset source object to create an output of the form described by a specified export preset.
  6. After you’ve initialized an export session with the asset that contains the source media, the export preset name (presetName), and the output file type (outputFileType), you start the export running by invoking exportAsynchronouslyWithCompletionHandler(). Because the code performs the export asynchronously, this method returns immediately. The code calls the completion handler you supply to exportAsynchronouslyWithCompletionHandler() whether the export fails, completes, or the user canceled. Upon completion, the exporter’s status property indicates whether the export has completed successfully. If it has failed, the value of the exporter’s error property supplies additional information about the reason for the failure.

An AVComposition instance combines media data from multiple file-based sources. At its top level, an AVComposition is a collection of tracks, each presenting media of a specific type such as audio or video. An instance of AVCompositionTrack represents a single track.

Similarly, AVMutableComposition and AVMutableCompositionTrack also present a higher-level interface for constructing compositions. These objects offer insertion, removal, and scaling operations that you’ve seen already and will come up again.

Go ahead, build and run your project!

Select two videos and an audio files and merge the selected files. If the merge was successful, you should see a “Video Saved” message. At this point, your new video should be present in the photo album.

vpr_swift_14

Go to the photo album, or browse using your the “Select and Play Video” screen within the app. You’ll might notice that although the app merged the videos, there are some orientation issues. Portrait video is in landscape mode, and sometimes videos are turned upside down.

vpr_swift_15

This is due to the default AVAsset orientation. All movie and image files recorded using the default iPhone camera application have the video frame set to landscape, and so the iPhone saves the media in landscape mode.

Video Orientation

AVAsset has a preferredTransform property that contains the media orientation information, and it applies this to a media file whenever you view it using the Photos app or QuickTime. In the code above, you haven’t applied a transform to your AVAsset objects, hence the orientation issue.

You can correct this easily by applying the necessary transforms to your AVAsset objects. But as your two video files can have different orientations, you’ll need to use two separate AVMutableCompositionTrack instances instead of one as you originally did.

Before you can do this, add the first of two helper methods to MergeVideoViewController:

func orientationFromTransform(transform: CGAffineTransform) -> (orientation: UIImageOrientation, isPortrait: Bool) {
  var assetOrientation = UIImageOrientation.Up
  var isPortrait = false
  if transform.a == 0 && transform.b == 1.0 && transform.c == -1.0 && transform.d == 0 {
    assetOrientation = .Right
    isPortrait = true
  } else if transform.a == 0 && transform.b == -1.0 && transform.c == 1.0 && transform.d == 0 {
    assetOrientation = .Left
    isPortrait = true
  } else if transform.a == 1.0 && transform.b == 0 && transform.c == 0 && transform.d == 1.0 {
    assetOrientation = .Up
  } else if transform.a == -1.0 && transform.b == 0 && transform.c == 0 && transform.d == -1.0 {
    assetOrientation = .Down
  }
  return (assetOrientation, isPortrait)
}

This code will construct an affine transform to get the output video looking correct based on the input video’s orientation.

Next, add one more helper method to the class:

func videoCompositionInstructionForTrack(track: AVCompositionTrack, asset: AVAsset) -> AVMutableVideoCompositionLayerInstruction {
  // 1
  let instruction = AVMutableVideoCompositionLayerInstruction(assetTrack: track)
  // 2
  let assetTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack
 
  // 3
  var transform = assetTrack.preferredTransform
  let assetInfo = orientationFromTransform(transform)
  var scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.width
 
  if assetInfo.isPortrait {
    // 4
    scaleToFitRatio = UIScreen.mainScreen().bounds.width / assetTrack.naturalSize.height
    let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
    instruction.setTransform(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor),
      atTime: kCMTimeZero)
  } else {
    // 5
    let scaleFactor = CGAffineTransformMakeScale(scaleToFitRatio, scaleToFitRatio)
    var concat = CGAffineTransformConcat(CGAffineTransformConcat(assetTrack.preferredTransform, scaleFactor), CGAffineTransformMakeTranslation(0, UIScreen.mainScreen().bounds.width / 2))
    if assetInfo.orientation == .Down {
      let fixUpsideDown = CGAffineTransformMakeRotation(CGFloat(M_PI))
      let windowBounds = UIScreen.mainScreen().bounds
      let yFix = assetTrack.naturalSize.height + windowBounds.height
      let centerFix = CGAffineTransformMakeTranslation(assetTrack.naturalSize.width, yFix)
      concat = CGAffineTransformConcat(CGAffineTransformConcat(fixUpsideDown, centerFix), scaleFactor)
    }
    instruction.setTransform(concat, atTime: kCMTimeZero)
  }
 
  return instruction
}

This method takes a track and asset, and returns a AVMutableVideoCompositionLayerInstruction which wraps the affine transform needed to get the video right side up. Here’s what’s going on, step-by-step:

  • You create an AVMutableVideoCompositionLayerInstruction and associate it with your firstTrack.
  • Next, you create an AVAssetTrack object from your AVAsset. An AVAssetTrack object provides the track-level inspection interface for all assets. You need this object in order to access the preferredTransform and dimensions of the asset.
  • Then, you save the preferred transform and the amount of scale required to fit the video to the current screen. You’ll use these values in the following steps.
  • If the video is in portrait, you need to recalculate the scale factor, since the default calculation is for videos in landscape. Then all you need to do is apply the orientation rotation and scale transforms.
  • If the video is an landscape, there are a similar set of steps to apply the scale and transform. There’s one extra check since the video could have been produced in either landscape left or landscape right. Because there are “two landscapes” the aspect ratio will match but it’s possible the video will be rotated 180 degrees. The extra check for a video orientation of .Down will handle this case.

With the helper methods set up, find merge(_:) and replace section #2 with the following so that you have two AVMutableCompositionTrack instances instead of one:

// 2 - Create two video tracks
var firstTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
  preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAsset.duration),
  ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack,
  atTime: kCMTimeZero,
  error: nil)
 
var secondTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
  preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
secondTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAsset.duration),
  ofTrack: secondAsset.tracksWithMediaType(AVMediaTypeVideo)[0] as! AVAssetTrack,
  atTime: firstAsset.duration,
  error: nil)
 
// 2.1
var mainInstruction = AVMutableVideoCompositionInstruction()
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration))
 
// 2.2
let firstInstruction = videoCompositionInstructionForTrack(firstTrack, asset: firstAsset)
firstInstruction.setOpacity(0.0, atTime: firstAsset.duration)
let secondInstruction = videoCompositionInstructionForTrack(secondTrack, asset: secondAsset)
 
// 2.3
mainInstruction.layerInstructions = [firstInstruction, secondInstruction]
let mainComposition = AVMutableVideoComposition()
mainComposition.instructions = [mainInstruction]
mainComposition.frameDuration = CMTimeMake(1, 30)
mainComposition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width,
  height: UIScreen.mainScreen().bounds.height)

First, you set up two separate AVMutableCompositionTrack instances. That means you need to apply an AVMutableVideoCompositionLayerInstruction to each track in order to fix the orientation separately.

2.1: First, you set up mainInstruction to wrap the entire set of instructions. Note that the total time here is the sum of the first asset’s duration and the second asset’s duration.

2.2: Next, you set up the two instructions – one for each asset – using the helper method you defined earlier. The instruction for the first video needs one extra addition – you set its opacity to 0 at the end so it becomes invisible when the second video starts.

2.3: Now that you have your AVMutableVideoCompositionLayerInstruction instances for the first and second tracks, you just add them to the main AVMutableVideoCompositionInstruction object. Next, you add your mainInstruction object to the instructions property of an instance of AVMutableVideoComposition. You also set the frame rate for the composition to 30 frames/second.

Now that you’ve got an AVMutableVideoComposition object configured, all you need to do is assign it your exporter. Insert the following code at the end of of section #5 (just before exportAsynchronouslyWithCompletionHandler()::

exporter.videoComposition = mainComposition

Whew – that’s it!

Build and run your project. If you create a new video by combining two videos (and optionally an audio file), you will see that the orientation issues disappear when you play back the new merged video.

vpr_swift_16

Where to Go From Here?

Here is the final project with all of the code from this tutorial.

If you followed along, you should now have a good understanding of how to play video, record video, and merge multiple videos and audio in your apps.

AV Foundation gives you a lot of flexibility when playing around with videos. You can also apply any kind of CGAffineTransform to merge, scale, or position videos.

If you haven’t already done so, I would recommend that you have a look at the WWDC videos on AV Foundation, such as WWDC 2013 session 612 Advanced Editing with AV Foundation, and session 606 Moving to AV Kit and AV Foundation (this is about the introduction of AV Kit to OS X). Also, WWDC 2014 session 503 Mastering Modern Media Playback where Apple introduced AV Kit in iOS 8. Also, be sure to check out the Apple AV Foundation Framework programming guide.

I hope this tutorial has been useful to get you started with video manipulation in iOS. If you have any questions, comments, or suggestions for improvement, please join the forum discussion below!

The post How to Play, Record, and Merge Videos in iOS and Swift appeared first on Ray Wenderlich.

tvOS SDK: An iOS Developer’s Initial Impressions

$
0
0
tvOS: what I think!

tvOS: what I think!

In one of the final chapters of “Steve Jobs” by Walter Isaacson — Steve was quoted saying “It will have the simplest user interface you could imagine. I finally cracked it.” He was, of course, referring to Apple TV.

It wasn’t long after that Steve unfortunately passed away, and since then many of us have been eagerly anticipating this product. Yesterday on September 9th, 2015 — more than four years later — we were finally presented with what may possibly be Steve’s vision, or perhaps just the beginning of it.

Yesterday’s announcement was super-exciting for us as iOS developers, because Apple announced that the new Apple TV will have an App Store that we can develop apps for – leveraging much of our existing iOS knowledge and opening many new opportunities.

I and the rest of the Tutorial Team have been digging into the tvOS SDK and are already hard at work preparing some tutorials on tvOS (stay tuned!), but to tide you over in the meantime, I wanted to share my initial impressions of tvOS from an iOS developer’s perspective.

Let’s dig in!

The Basics

The original Apple TV was a set-top box that provides users with a simplistic user interface designed primarily for navigating and viewing video content. The new Apple TV announced yesterday expands this to full-blown apps for things like shopping and even games.

Apple TV mockup

Let’s took a look at the critical info:

  • Hardware specs: Notable specs are 64-bit A8 processor, 32GB or 64GB of storage, 2GB of RAM, 1080p resolution, HDMI, and a new Siri Remote / Apple TV Remote (more on this later).
  • Price: The new Apple TV is priced at $149 and $199 for 32GB and 64GB models, respectively. This came as a surprise to many, as they had been expecting to see higher price points.
  • Release date: Apple has given a vague release timeline of “Late October” but provided developers access to the tvOS SDK immediately. This isn’t much time to prepare, so if you want to have something ready for tvOS launch I suggest you move fast!
  • Development hardware: Apple has announced a program that allows “proven” developers to request an Apple TV Developer Kit, which is an early access Apple TV to use for testing. From the sounds of it you’ll be lucky to receive one; but if you’re serious about trying to hit launch date it’s worth a shot.
Note: It was originally unclear how much the development kit would cost. Now we have confirmation from an Apple employe on the developer forums that the development kit will only cost $1.00 if you are selected. We encourage you to register only if you have full intentions to release an app or write training materials, let’s make sure those who need them get them!

Developing Apps

By this point, it should be obvious that developing apps for the new Apple TV is a thing, and it’s a great thing!

When developing for Apple TV you will be developing for tvOS — the name coined by Apple as the device’s operating system. tvOS is built upon iOS and lends many of the same frameworks that you may already be familiar with.

In order to develop for tvOS you will need to download Xcode 7.1 from the developer center. This is a beta version of Xcode that includes support for tvOS, and a tvOS Simulator. You can install the Xcode 7.1 beta alongside Xcode 7 GM if needed.

Apple has provided two methods of developing apps on tvOS:

  1. TVML Apps: The first uses an entirely new process utilizing TVML, TVJS and TVMLKit. This was a big surprise to many of us – we’ll dive into this further in a moment.
  2. Custom Apps: The second uses familiar iOS frameworks and concepts you know and love like Storyboards, UIKit, and Auto Layout.

When you develop an Apple TV app, it appears to be a separate target (which implies that tvOS apps would be a separate purchase for customers). However, in the keynote Apple said there would be support for “universal purchases” where customers could purchase an iOS and tvOS app for a single price. We’re not quite sure how that works yet – maybe some support in iTunes Connect to link the two targets is coming?

TVML Apps

As mentioned, the first method of making apps is via TVML, TVJS, and TVMLKit. If these abbreviations sound foreign to you, don’t fret because they should. Here’s what they are:

  • TVML is a form of XML and stands for “Television Markup Language”.
  • TVJS is set of JavaScript APIs which provide you with the means to display apps created with TVML.
  • TVMLKit is the glue between TVML, JavaScript, and your native tvOS application.

If you’re a native iOS developer the thought of these might make you wince a little bit. But keep an open mind, there is some great power to all of this.

Here’s a very typical use-case for apps on Apple TV. Consider the following: you have content on a server and you want to display that content to users. Your content is organized in a predictable manner and navigating it should be intuitive and familiar. You want your tvOS app to feel at home with other apps. You’re not interested in pushing the envelope on cutting edge user experiences and designs.

TVML architecture

If this sounds like you and your app’s requirements, you may want to consider TVMLKit. Apple has put a lot of work into providing reusable templates that will be familiar to the user, there are in fact 18 of them as of this writing. Many of them allow you to create stunning interfaces that feel right at home on the user’s television. You can browse the templates in the Apple TV Markup Language Reference which I would highly recommend.

TVML templates

I also recommend running the TVML Catalog sample app to view each template in action in the tvOS simulator. Be sure to check out the README.md file as you’ll be required to start a local web server to host the content for the app to access. Don’t worry, it’s a single terminal command.

There is truly a ton of content to cover on this topic and it is very much worth your while to consider TVMLKit as an option for building your app. At this point in time I would recommend it to be the first point of consideration for apps that primarily provide menus of content. However, if you’re aiming to provide a fully immersive experience in your app, where your users will be spending more time interacting with your interface than passively watching or listening to content, then it is time to move on to developing a fully custom app.

Custom Apps

When you need to get down to the nuts and bolts and provide a one-of-a-kind experience you will need to brush off your iOS skills and work your UIKit-fu.

Many of the iOS frameworks you know and love like UIKit, Core Graphics, SpriteKit, CloudKit, and more are available on tvOS – you can see the whole list of what is (and isn’t) included here. If you are an existing iOS developer, you should feel very empowered by this list!

Writing a tvOS app can be done using both Swift, Objective-C and C (I have not seen anything to say C++ is off limits either).

Although there’s definitely a lot of new material to learn about making custom apps for tvOS, you should feel right at home as an iOS developer.

Focus Engine

One concept that will be new to iOS developers is the user input method. Users will not be touching your UI with their fingers or noses (you know you’ve done it or at least thought about it!). But rather, they will be using the provided remote control or even a game controller.

tvOS introduces a system known as the focus engine. The main concept is that there is always one — and only one — item that is in focus at a given time. Users navigate your UI by using swipe gestures or a directional pad/control to move up, down, left or right.

The focus engine automatically decides which view to focus based on user input; you don’t have to do anything. For example, you just arrange your views in your Storyboard, and if one of the views is focused and the user swipes right, the focus engine will automatically find the closest view to the left of the selected view and focus it for you.

tvOS Focus

As a developer, there are some new APIs related to the focus engine you’ll want to be aware of. There are APIs for your app to get notified when the focused item updates, to programmatically trigger a focus update, and much more. For more info, check out the Supporting Focus Within Your App section of the App Programming Guide for tvOS.

TVServices

Although tvOS development relies primarily on iOS frameworks you may already be familiar with, there are a few new frameworks to be aware of, such as the new TVServices framework.

The TVServices framework is primarily used to describe content in your app so that the system can display it on the “Top Shelf”. When a user places your app in the top row of their home screen your app is considered one of the most important apps that the user has installed.

Janie shared a photo!

This is an excellent opportunity to provide extra value to your users by giving them shortcuts to content they may be interested in. For a game, it may be game saves so they can jump right back into the action. For a social media app, you may have trending content that appears on the top shelf. And a photo sharing app may show off recently shared pictures by friends and family.

Check out the TVServices Framework Reference for more information on how to implement this feature. It is very important that you take full advantage of this opportunity.

Parallax Images

One thing that may have struck you as a little odd in the Keynote was the presenter’s emphasis on parallax effects happening on images and app icons. This is a really neat visual effect, but what’s so important about it?

As you play around with the tvOS simulator you’ll begin to understand why it’s so important: to move the focus item, you need to swipe a fair bit to the left or right. But if you swipe a little bit (but not far enough) Apple will begin to rotate the focus item, in order to give you a visual cue that you are doing something (but need to continue swiping to change the focus). It’s subtle but powerful.

tvOS parallax

Apple considers the parallax effect a key component of tvOS design. It is required of your App’s icon and highly encouraged for other media such as movie poster art.

Thankfully, Apple has outlined exactly how to create these assets in the Creating Parallax Artwork section of the App Programming Guide for tvOS, and has even provided a neat previewer app.

tvOS parallax images

Controllers

Apple TV remote

Everyone who buys the new Apple TV will receive a powerful new remote control. The previous generation was very simple with a directional pad and couple other navigational buttons. The new Apple TV remote has some exciting new features, specifically:

  • A glass touch surface at the top which allows the user to perform gestures like swipes, taps and clicks.
  • A microphone which provides access to Siri (Siri is restricted to a certain subset of countries) and the ability to control volume on your TV or audio system.
  • A gyroscope and motion sensor to provide a great gaming experience. The user can tilt the remote side to side perhaps to steer a car down a street or hero running through caverns.

You can use gesture recognizers you know and love to detect swipes and taps, and there are also new pressesBegan(), pressesEnded(), pressesChanged(), and pressesCancelled() APIs to detect when various buttons on the control are selected.

The remote communicates using Bluetooth, which leaves the door wide open for Bluetooth game controllers (especially since the default remote isn’t particularly well suited to games IMHO). Apple has already announced that the Nimbus Steelseries Controller will be available for the new Apple TV. Check out the Working with Game Controllers section to learn more.

tvOS and Games

We’re willing to bet that games will be really hot on tvOS – Apple seems to be aiming squarely at Nintendo’s casual games market.

tvOS has strong game support. SpriteKit and SceneKit both work on tvOS, and in the keynote the Crossy Roads developer showed a tvOS port of their game, which is made in Unity, which implies Unity support may be coming in the future as well.

Many SceneKit games port almost seamlessly to the Apple TV. For example, Ray ported Zombie Conga from iOS Games by Tutorials to the Apple TV in less than 10 minutes, without even having to change any code:

This ease of porting games is sure to boost Apple TV’s initial games catalog!

Limitations

Perhaps two of the most puzzling aspects of tvOS are the limitations imposed on local storage and app size.

Limitation: Local Storage

Starting with local storage… there is none! If your app needs to persist any user data you must do so using iCloud, CloudKit, or your own back-end service. Any data that you store on device is not guaranteed to be available the next time your app is opened. Furthermore if you want to synchronize data across devices you will need to store it somewhere else.

All your data is belong to us!

This is important to keep in mind as you design the architecture of your tvOS apps. Here are some rules of thumb:

  • If your data storage requirements are less than 1MB, iCloud’s key-value store is a valid option; just remember that iCloud KVS access is strictly limited to the owner and cannot be shared to other users.
  • If you need to share events or data with other users, CloudKit is a good option.
  • If you are making a cross-platform app or have specialized needs, you may wish to use your own back-end service.

Limitation: App Size

Another limitation is that your app size cannot exceed 200MB.

Flip Table

But before you flip your table, think back to WWDC 2015 and the “On-Demand Resources” APIs that were introduced – it’s almost as if Apple planned this! :]

These APIs provide the ability to reduce the initial installation size of your app by downloading resources on demand. Developers can tag assets in Xcode and the App Store will automatically split tagged content into downloadable bundles upon submission. When the user needs the tagged resources you can request them to be downloaded to the device. You would ideally anticipate the content needs and download them before the user needs them so they do not notice the load times.

A simple example of this approach is a game that has 10 levels. You may opt to include only the first 2 levels when the app is installed. Once the user finishes level 1 you send a request to download the assets required for level 3 so that when the user finishes level 2, level 3 is ready to go. You’d then continue to do this as the user progresses through the game.

While this may seem annoying and painful as a developer, you can think of the user benefit. Rather than waiting for your 1GB game to download, they can perhaps download 100MB and start playing right away. A possible unfortunate outcome is that the user has a poor Internet connection and prefers to queue up downloads overnight. Downloading the next 900MB of your game as they play through may result in a terrible experience. Unfortunately as tvOS developers our hands are tied in this scenario.

Where To Go From Here?

There is a lot that can and will be done on tvOS! So prepare your couch; if you don’t have a designated “groove”, you may before year’s end :]

And remember: this is only the beginning. iOS didn’t even have cut, copy, and paste until iOS 3.0!

I believe that this platform can truly reinvent the way we use our TVs. Aside from the obvious gaming and content viewing use-cases, there are many areas for developers to innovate.

Here are some resources to learn more about tvOS:

  • tvOS Documentation: Apple’s official tvOS documentation; a bit sparse at the moment but I’m sure more is coming soon.
  • RWDevCon: If you’d like to learn about tvOS, you should come to our upcoming conference; we’ll be having a tons of hands-on tvOS tutorials there and will get you up-to-speed.

What do you think of the Apple TV and tvOS? Please join us in the forum discussion below!

The post tvOS SDK: An iOS Developer’s Initial Impressions appeared first on Ray Wenderlich.

Video Tutorial: Intermediate Core Data Part 3: Mapping Models

Viewing all 4370 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>