Filtering by Author: Paul Solt

How to fix your SKEmitterNode particle effect - Sprite Kit Tip 1

Using special effects in your game is a great way to achieve a unique style or interesting visuals. In this short post, you'll learn how to leverage special effects compositing with the and the .

Subscribe to the iPhone mailing list to learn how to build your iPhone game.

Want to watch the tutorial video? Skip to the bottom.

Out of the box the SKEmitterNode will default to an Additive blend mode (Add) – which can cause special effect glitches. Over dark backgrounds your particles will look like they did in the particle editor, but over white backgrounds they will be washed out and super white (not what you wanted!).

Look at the rocket thrusters for the difference between additive and alpha blend modes

Look at the rocket thrusters for the difference between additive and alpha blend modes

Layer hierarchy and blending control is how you can achieve any kind of special effect in your iPhone game.

I use the to represent my player, which then has two child nodes: the SKSpriteNode (image) and the SKEffectNode (the particle effect wrapper). Using this structure you can get the same benefits of creating a custom class using the SKNode hierarchy without all the code. 

Inside your didMoveToView() method in your GameScene.swift file, add the following to wrap your SKEmitterNode object in an SKEffectNode object before adding it to your game scene

// The playerNode is the top level object for the main character
//   It composites the image, particle effects, and any other graphics together as a single entity
playerNode = SKNode()
playerNode.position = CGPoint(x: 200, y: 200)
playerNode.zPosition = 5   // The depth should be above any other game objects, but less than any UI
addChild(playerNode)

// Load ship image and display it
playerShip = SKSpriteNode(imageNamed: "PlayerShip1")
playerShip.physicsBody = SKPhysicsBody(texture: playerShip.texture, size: playerShip.size)

// Afterburner - thruster
var playerThrusterPath = NSBundle.mainBundle().pathForResource("Thruster", ofType: "sks")!
var playerThruster = NSKeyedUnarchiver.unarchiveObjectWithFile(playerThrusterPath) as! SKEmitterNode

// Reduce the scale a bit after you play around with the particle effects editor
playerThruster.xScale = 0.5
playerThruster.yScale = 0.5

// Control the composition of the effect (blending) using an SKEffectNode
//  this prevents the white washout with the engine being blended (additive) to the background image
//  you'll see that different colors blend differently as the player moves around.
//  Use this code to fix that issue!
// SKEffectNode's default blend mode is Alpha, so you don't need to change anything to get this to work
//  out of the box.

var playerThrusterEffectNode = SKEffectNode()
playerThrusterEffectNode.addChild(playerThruster)
playerThrusterEffectNode.zPosition = 0  // Below the ship, you could do a flame effect on top for damage

playerThrusterEffectNode.position.y = -20  // move the effect down a bit (based on art/your tastes)

// Make sure you only add the thruster once to the scene hierarchy or you'll see a crash!
playerNode.addChild(playerThrusterEffectNode) 

Try using the code to fix your blending mode glitches – and if that doesn't work let me know.

It can be a little challenging to achieve different visual effects if you don't understand how to composite graphics together in an app or game.

Tutorial Video - How to fix your SKEmitterNode particle effect

Using special effects in your iPhone game is a great way to achieve a unique style or stylish visuals. Enroll (50% OFF): https://iPhoneDev.tv/iPhoneGame Out of the box the SKEmitterNode will default to an Add blend mode (which can cause issues). In this video, you'll learn how to wrap the SKEmitterNode into an SKEffectNode to leverage the Alpha blend mode.","source":"

Using special effects in your iPhone game is a great way to achieve a unique style or stylish visuals. Enroll (50% OFF): https://iPhoneDev.tv/iPhoneGame Out of the box the SKEmitterNode will default to an Add blend mode (which can cause issues). In this video, you'll learn how to wrap the SKEmitterNode into an SKEffectNode to leverage the Alpha blend mode.

"},"hSize":null,"floatDir":null,"html":"","url":"https://www.youtube.com/watch?v=Y0wuhvqbiEs","width":854,"height":480,"providerName":"YouTube","thumbnailUrl":"http://i.ytimg.com/vi/Y0wuhvqbiEs/hqdefault.jpg","resolvedBy":"youtube"}" data-block-type="32" id="block-yui_3_17_2_5_1425329637769_17327">

 

Want to learn more?

I've been making apps and games for a long time. After working at Apple I decided that I wanted to teach other people how to turn their ideas into apps. If you want to take the first step, but aren't sure where to go – take my iPhone game course.

Posted on March 2, 2015 .

Swift 1.2 fixes and breaks a few things: you should be excited!

Subscribe for new changes in Swift and iOS app development.

The latest version of Swift 1.2 was released today as part of the Xcode 6.3 Beta. You can start using it today, and you'll get access to some awesome new features.

Apple wrote a and also posted it's Download Xcode 6.3 Beta from Apple's Xcode page and make sure you review the changes.

In this post I wanted to comment on a few features that I'm excited about and how you can start using them. Further in the post I'll show you how to convert a small project from Swift 1.1 to 1.2 (manually), and then I'll talk about the great Swift Migrator.

Swift 1.2 breaks a few things in your code. The language changed, so you'll have to change your Xcode projects to adapt.

New Features

1. The Set data structure is available

I'm really excited about the Set data structure, as it was missing (and I missed it from Objective-C).

Set is similar to , except that it will make sure you only have a single unique item in the collection. It's great if you want to restrict duplicates for an algorithm or logic in your app. You can also use the powerful set logic, which lets you combine sets through addition or subtraction to create subsets.

Here's a short code snippet to show off creating a set using an Array as input. Alternatively you can add each element individually using the insert() method.

var cardSuits = Set(["Diamonds", "Spades", "Hearts", "Clubs"])

println("Cards: \(cardSuits)")

// Cards: ["Diamonds", "Clubs", "Spades", "Hearts"]


cardSuits.insert("Diamonds")  // no error, but no insert happens

println("Cards: \(cardSuits)")

// Cards: ["Diamonds", "Clubs", "Spades", "Hearts"]


cardSuits.insert("Rocks")  // adds new suit

println("Cards: \(cardSuits)")

// Cards: ["Rocks", "Diamonds", "Clubs", "Spades", "Hearts"]

Set documentation

There is hardly any documentation on how to use the Set collection right now, but you can get the Set methods by Command + left-clicking on the word Set in Xcode (after writing a line creating a set variable). That should take you to the Swift code, which has all the methods available and some sparse comments.

1 - Set Documentation.png

2. "if let" improvements - no more "pyramid of doom"

This one is fantastic. If you've written any kind of user input validation or JSON/XML data parsing you are going to love it.

Before I would either nest a ton of if/else statements, or I would use optionals and then test all the optional values in one if/else statement. The more values you need to test, validate, or compare the more { } curly brackets you're going to be adding. It can then become a little mind-numbing as you try to figure out what block { } you are in, and where another one ends (pro-tip: double click the { to find the corresponding }).

if let name = validateName(nameTextField.text) {

    if !name.isEmpty {

        if let age = validateAge(ageTextField.text) {

            if age > 13 {

                

                // create a new user ...

            }

        }

    }

}

In Swift 1.2  you can combine multiple "if let" values in a single if statement. Plus you get to use where!

if let name = validateName(nameTextField.text),

       age = validateAge(ageTextField.text)

    where age > 13 && !name.isEmpty {

    

    // create a new user ...

}

This change alone is worth the broken code that you'll have to update.

I always felt there was a disconnect between the if/else statements and the switch statements in Swift. Now you can combine multiple statements into a single expression, and you can use the where clause to further limit conditions into a single readable statement.

I much prefer this shorter statement because it keeps the information local, as opposed to putting it in nested if/else statements.

One Caveat - error messaging in the UI

While I do like the concise nature of the statement. Depending on the type of app you might need to provide understandable error messages to the end user.

If you are going to handle any error logic you will probably need to leverage semi-nested if/else statements, or you could do all your error checking in a separate method (i.e. validate methods). That way you can be sure to properly warn a user that they didn't add their name to a required field in your signup form.

My test driven philosophy would urge you to not make a method do multiple things, but my shipping apps philosophy would recommend doing the naive approach (just get it working and ship it to the App Store).

Your goal should be to ship your app to the App Store, not writing the most well designed code.

I'd rather see you shipping apps than obsessing over every single code design decision (and not shipping anything).

Broken code: Swift 1.2 breaks existing projects

The biggest takeaways I found when testing out my latest Swift game project were related to types, casting, and converting between Objective-C types (NSString, NSArray, and NSDictionary) to Swift types (String, Array, Dictionary).

Download my iPhone game Xcode project if you want to follow along. It's written for Swift 1.1 and Xcode 6.1. You can learn more about the game in my Swift iPhone game course.

1. NSString isn't a String anymore

You won't get automatic conversion from NSString to String anymore, but it does work in the opposite direction. Apple says it simplifies things, but I'm not sure what that means. Simplifies for them, or simplifies for the programmer using Swift?

To me it seems more complicated, since it'll be another edge case you need to keep track of where the relationship isn't bi-directional. For example in my default Game project, Apple's code unarchiving the Sprite Kit .sks file breaks. They pass a NSString to a method that takes a String.

if let path = NSBundle.mainBundle().pathForResource(file, ofType: "sks") {

Error: Apple is forcing you to add additional type information when converting between Objective-C and Swift

GameViewController.swift:14:61: 'NSString' is not convertible to 'String'; did you mean to use 'as!' to force downcast?

Warning: The auto fix didn't work because the parameter expects an optional value.

GameViewController.swift:14:58: Treating a forced downcast to 'String' as optional will never produce 'nil'

Looking at the documentation for , you can see that pathForResource() has an the optional string type: String? as it's parameter.

func pathForResource(name: String?, ofType ext: String?) -> String?

Fix: Change the as! to an as?

Using the as? operator will make it so that if the conversion fails, it'll return nil. And that is what the pathForResource() method expects.

As the Swift language changes you'll run into situations like these. Apple hasn't quite settled yet, so that some code is going to have to change to accommodate new features in the language.

if let path = NSBundle.mainBundle().pathForResource(file as? String, ofType: "sks") {

2. Down casting (i.e.: type conversions) has changed a bit.

You'll need to use the as! to convert between types, which used to work before.

let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as GameScene

Error: Apple wants you to be more explicit with optional vs. non-optional type conversions

GameViewController.swift:19:82: 'AnyObject?' is not convertible to 'GameScene'; did you mean to use 'as!' to force downcast?

Fix: Change then ending to use as! instead of as

let scene = archiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as! GameScene

3. Method signatures have been Swift'ified

With the addition of the new Set class, your touch events methods in both UIControl subclasses or in Sprite Kit SKScene subclasses will have to be updated. There are other APIs in Cocoa/Cocoa Touch that have also been updated. You'll want to look at the full list to see what changed () and ().

You'll find a lot of method names have changed with the addition of the Set collection class in Swift. Additionally many methods are also using String instead of NSString!, which is a big win for Swift!

override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {

Error: The type has changed from NSSet to Set

GameScene.swift: Overriding method with selector 'touchesBegan:withEvent:' has incompatible type '(NSSet, UIEvent) -> ()'

Fix: You'll need to update your method signature (i.e.: the entire first line) to the following:

override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

I'm not sure why it doesn't have the method signature using UITouch. I'd love it more if it used Set since that's what I'll be converting it to. Even still, it's a step in the right direction for Swift. 

Error: Set doesn't have the method anyObject()

if let touch = touches.anyObject() as UITouch? {

Now that you have a Swift Set that has typed objects you need to update your cast if you use one with the touches parameter. 

Fix: Use one of the new methods of Set like first or last, which return optional NSObject values

There's a couple gotchas with this conversion. anyObject() was a method, but first is a property. Firstly, you'll call them differently (i.e: no parenthesis).

Secondly You can't use as? UITouch and as UITouch? interchangeably anymore with Swift 1.2 (not sure if this is a bug or intended feature).

if let touch = touches.first as? UITouch {

 

Swift Migrator: Convert to Swift 1.2

Apple did provide a menu option to do the conversion for you. It works ok, but it's not going to do everything for you.

From the menu bar in Xcode > Edit > Convert > To Swift 1.2

Gotchas

1. It won't catch issues related to APIs changing types (anything that used NSSet to Set or possible NSString! to String).

2. It didn't seem to change things the way I would. Scroll up to see what I recommend as a fix to the code issues in the conversion as a starting point.

3. The recommend quick fixes are not always right, so you'll have to consult the web or .

Conclusion

It's going to be a little bit of work to convert your project. I think you'd spend at least 30-60 minutes working through your project. Any subsequent projects will get easier as you learn what you need to look out for in your older Swift 1.1 code.

From my own experience I find that I have to fiddle with the code (massage it until it works). After I figured out the different edge cases it was easier to convert.

I'm looking forward to when Xcode 6.3 comes out of beta with Swift 1.2!

Connect

  • Subscribe to my iOS mailing list if you found this interesting.
  • Let me know how your .
  • Learn more about making iPhone games.
Posted on February 9, 2015 .

Create an IBDesignable UIView subclass with code from an XIB file in Xcode 6

Many times, I find myself wanting the visual power of both design and layout from Xcode 6’s new interface builder. I’m a visual person, and sometimes I like to create custom or custom objects that can be reused.


You can create a custom UIView subclass and load the interface from an XIB file. In , you can also go a step further and provide and customization in Xcode’s Attributes Inspector.

This is a big deal if you’ve ever loaded an XIB file from code and attached it to a user interface. In the past, you could block out the colors of the UI, but you could never see the composition. You also couldn’t change any of the parameters at design time within your main Storyboard or XIB file.

Custom UIView Subclass (e.g.: CustomView)

These are the steps to making a custom UIView that is designable within Xcode:

  1. Create a View .xib file (e.g.: CustomView.xib)

  2. Design the user interface in Xcode

  3. Set up Auto Layout constraints

  4. Create a Swift code file (CustomView.swift)

  5. Set .xib file’s “File’s Owner” custom class to CustomView (it must match the class name)

  6. Implement both CustomView initializers: init(coder:) and init(frame:)

  7. Load the UIView from the .xib file using the NSBundle and UINib classes

  8. Add the view as a subview and property for the class (future modifications)

  9. Add autoresizing masks for the view to match the size of the CustomView itself

  10. Make the view’s frame leverage the design time size of the embedded CustomView’s bounds

Note

If you leverage any image assets, you’ll want to make sure they are in the same bundle as the custom view. This is especially important when trying to leverage extensions or static libraries.

Visual Guide for a custom UIView from an XIB file

In the following steps I will visually show and explain what you'll need to do to create an UIView that you can reuse in your iPhone apps. You will be able to leverage the power of design time editing in Xcode along with a better visualization of what your app will look like.

1. Create a View XIB file (e.g.: CustomView.xib)

The first thing you'll need is a new user interface file called an XIB or .xib or nib file. This is like a storyboard file, but it only holds a single UIView object.

Create a new file from the Menu bar using File > New > File or the keyboard shortcut Command + N:

Select iOS > User Interface > View; name it “CustomView” and add it to your target:

2. Setup the UIView for a custom size and disable the status bar.

The UIView will initially be setup for a full-screen iPhone view with a standard size and a status bar. You'll need to make some adjustments to use a smaller size.

Set the Size to “Freeform” and the Status Bar to “None:”

3. Design the UI for your custom control or widget

Leverage the power of Xcode to drag and drop the UI elements for your custom widget. Drag out buttons, labels, image views, and anything else that you want to display in the custom view.

4. Connect Auto Layout constraints to control layout

Depending on how your control is going to be used, you will want to setup constraints that either keeps the size fixed or make the control adaptive to larger interfaces.

You can select all of the UI elements to see if the connections are good. Blue = good, orange = missing constraints, and red = conflicts. Using constraints you need to establish the rules to set the width, height, and position of every UI element.

Auto Layout enables the relative layout of visual elements in your iOS app:

5. Create a Swift code file to drive the custom UIView or UIControl

You need to connect the XIB file to a Swift code file in order to provide the brains or logic to power the UI element. You'll be creating actions and outlets that will be used to change the visuals or respond to input.

Create a new code file using File > New > File > iOS > Source > Cocoa Touch Class:

On the next screen, subclass the UIView class and choose Swift:

6. Connect the XIB file and the Swift code file together using the “File’s Owner” attribute

The XIB user interface file will be loaded when the view is ready to display on your iPhone. In order for it to work with your code file, you'll need to make it aware of what Swift file is going to preform all the logic.

On the right panel, set the Custom Class name to the same name as your Swift code and XIB file:

7. Add code to load from a .xib file using the NSBundle and UINib classes

I wish the tutorial could end here. Unfortunately, Apple doesn't provide an easy way to connect the UI you designed to your UIView subclass. To connect the two, you are going to write some code that will load the user interface and place it inside the edges of the view in code.

Create two methods to load the .xib file from the bundle in which it’s located:

// Our custom view from the XIB file
var view: UIView!

func xibSetup() {
    view = loadViewFromNib()

    // use bounds not frame or it'll be offset
    view.frame = bounds

    // Make the view stretch with containing view
    view.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight

    // Adding custom subview on top of our view (over any custom drawing > see note below)
    addSubview(view)
}

func loadViewFromNib() -> UIView {
    let bundle = NSBundle(forClass: self.dynamicType)
    let nib = UINib(nibName: "CustomView", bundle: bundle)

    // Assumes UIView is top level and only object in CustomView.xib file
    let view = nib.instantiateWithOwner(self, options: nil)[0] as UIView
    return view
}

You need to add a property to store the view that will be loaded from the XIB file. It might seem a little odd to store a view as a property within a UIView object. A custom UIView is just a composition or hierarchy of UIView objects that use position, size, color, and images to create the final look.

You'll also add two methods that will assist with the following step.

The first method, xibSetup() will be called from the initializers in the next step, when the UI is loaded. The loadViewFromNib() method will do the complex loading work from the file system.

8. Implement the initializers and leverage the code to load from an .xib file

Leverage the common code in both initializers used in UIView creation using your xibSetup() method.

You must make sure to call the super methods so that the correct UIView initialization occurs. The init(coder:) is called when creating your view within another interface file. The init(frame:) is called when creating your view programmatically (see below).

override init(frame: CGRect) {
    // 1. setup any properties here

    // 2. call super.init(frame:)
    super.init(frame: frame)

    // 3. Setup view from .xib file
    xibSetup()
}

required init(coder aDecoder: NSCoder) {
    // 1. setup any properties here

    // 2. call super.init(coder:)
    super.init(coder: aDecoder)

    // 3. Setup view from .xib file
    xibSetup()
}

9. Add a new UIView object to your Storyboard file and set the Custom Class name

Drag a UIView object onto the Storyboard canvas for your current View Controller. Resize the UIView element to fit a smaller portion of the app screen. Note: If it’s the first object you add, it’ll be huge.

Temporarily, change the UIView color to non-white, so you can see it:

To get the Storyboard to load the correct UI element, you'll need to set this "blank" UIView to act as the placeholder for your custom class. Doing so will trigger the init(coder:) method to create your custom UIView at run-time. You can learn more about this process by reading the top description from  or the  (click "more..." to read the hidden description).

You will need to change the class name to “CustomView” in the Identity Inspector:

10. Make the CustomView.swift file IBDesignable

At the top of your Swift code file, you need to add @IBDesignable in Swift. Xcode will now compile (takes a few seconds) and embed your custom UIView inside a Storyboard file.

import UIKit

@IBDesignable class CustomView: UIView {

}

11. Click on/off Main.storyboard to get Xcode to refresh your custom UIView

You should be able to make changes to your CustomView and see the changes in the Storyboard. Sometimes this can be buggy, especially if there is an issue. To force an update you can click on/off the Storyboard file, or you can use the new menu bar option described below.

An easier option is to select the Storyboard file and click on a custom view that's breaking. In the menu bar, do the following:  

Editor > Debug Selected Views

OR

Editor > Refresh All Views

Tip: Watch a video on how this works in Xcode 6.1.1

12. Add IBOutlets and IBActions to connect code and UI together

To work with any of the UI in code you must make connections with Outlets and Actions.

Open the Assistant Editor and then you can right-click and drag from the user interface into the associated code file. Create outlets for any UITextField, UIButton, or UILabel if you need to change the text. If you have a button, you'll need to setup an action to invoke a method using  the style buttonNamePressed(sender:).

You should have a set of outlets and actions like the following:

@IBOutlet weak var label: UILabel!
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var button: UIButton!
@IBAction func buttonPressed(sender: AnyObject) {
    // do something
}

Note: If you display an image, the UIImageView will need clipToBounds set to true to prevent artifacts and overdrawing.

13. Make an IBInspectable attribute to change the image at design time

The IBInspectable property allows you to expose functionality in code that can alter the appearance of the custom UIView. You can expose properties that are either computed, which gives you a hook to update the appearance.

Add code to alter the image using a computed property around the imageView outlet:

@IBInspectable var image: UIImage? {
    get {
        return imageView.image
    }
    set(image) {
        imageView.image = image
    }
}

14. Change the image at design time using the Attribute Inspector property

You can alter the appearance or settings for your custom UIView by changing parameters in the Attribute Inspector. Any property that you tag with @IBInspectable will be visible at the very top of the list of settings.

Change the text or even a corner radius using a computed property and the view.layer.cornerRadius value.

Resources

  1. - Apple’s Objective-C Code Sample
  2. Building Custom UI Elements With IBDesignable and IBInspectable - Think and Build
  3. How to Build a Custom (and “designable”) Control in Swift - Think and Build
  4. Debugging Xcode Live Rendering - Morten Bogh
  5. Nib Designable - Xcode Live Rendering With Nibs Made Easy - Morten Bogh

Summary

You can use this technique to create your own UIControl subclasses, just like UIButton or UILabel. UIControl provides the Target/Action model of interaction that allows you to create buttons, sliders, and more.

Using @IBInspectable you can also provide computed properties that can be changed using the Attributes Inspector at design time (convenient for non-programmers).

Connect

  1. Share this post on Twitter

  2. Let me know how you use it at

  3. Checkout my Swift iPhone app courses

  4. Download the source code on github

Posted on December 16, 2014 .