Acquisition: Live on the App Store

So I started with (not so) grand ambitions of walking through the process of reviving Acquisition. What actually happened was a few flurries of activity which eventually got it working again across all device sizes in a way that will hopefully hold up. The only real pain point in the end was fixing the iPad issues. Since I couldn't change from a universal app to an iPhone only one (intended as a temporary fix since resolving the iPhone issues was slightly easier and would ensure that everyone has a working version) I had to get it all working in one go.

The most important thing is that it's working properly, again (and has been for a couple of months now). So far, no crashes.

You can download it from the app store.

 

Acquisition: Bringing it back to life

The first game I launched on the App Store, targeting iOS 4.3... It still sells on occasion and I've found some problems with it. This is some early code so it'll be an interesting experiment to see just how difficult it is to resurrect to a working state. Let's see what we're working with...


2016-02-29 22:16:54.449 Acquisition[27180:2115785] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Application windows are expected to have a root view controller at the end of application launch'

Uh oh... That's an auspicious start. Let's get this show on the road. I've seen this error before so I know how to fix it. Just go into the AppDelegate and add the following line:

[self.window setRootViewController:viewController];

And we're in... ok - next.

... ok then

... ok then

Hmm, didn't know it was going to be this bad. Time to do some heavy duty cleaning.

Unity: Building a keypad - Redux

One of the more popular posts has been on creating a keypad. However, I hadn't really thought of it as a tutorial and just as an example of something I'd been messing with. It's time to address that.

The full project is available on Github: https://github.com/stepheng/UnityKeycodeExample

This is what we're going to end up with...

This is what we're going to end up with...

This differs from the previous version in that the UI runs in the world space. This is based on some pictures of touch screen based keypad door locks I've seen. So, the first step is to set up the scene.

Create an Empty Object at 0,0,0.

Add a Cube to the object and scale it to 1, 4/3, 0.1. Our keypad is going to have a 3:4 aspect ratio as our button layout will be 3x4. 

Create a new, dark, material, and apply it to the cube. Just create a New Material and change the Albedo colour to something close to black. Give it a smoothness of 0.75. This isn't required but will make the lights we're going to use to show the status of the keypad more visible.

Add a Canvas to the empty object. Position it at 0, 0, -0.0501.
Set the Render Mode to World Space.
Since we're rendering the UI in world space we need to set an appropriate size and scale. The Width and Height values are used for rendering the UI whilst the Scale is used for rendering it in the world. We're maintaining a 3:4 ratio for the Canvas so the values need to be a suitably scaled up version. I picked 900 and 1200 for my Canvas. Set the X and Y scales to be 1/Width (in my case, 1/900). You'll see that the Canvas will be scaled to the size of the Cube.

CanvasSettings.JPG

Add two new point lights to the Cube Set one to red, and one to green. These will be the indicators that the keypad is working. Set the light positions at -0.125, 0.5, -1.5, and 0.125, 0.5, -1.5.

Create a Button on the Canvas. We'll be resizing it in code later so the actual values we use here don't matter too much. Set an image for the button background. I made a 256x256 circle (filled white on transparent background) to get a higher quality image. If you don't want to use that, the Knob image that is included in Unity will work for test purposes.

Set the colour to #92B2FFFF and change the normal colour to #FFFFFF00, the highlighted colour to #F5F5F540, and the pressed colour to #FFFFFFFF. This will tint the image we're using as the background of the button to a light blue. We're making it transparent when the button isn't active, partially visible when the mouse hovers over it, and fully opaque when pressed. I also increased the Fade Duration to 0.25. Play around and find something you like.

Expand the Button in the object Hierarchy window so you can see the Text object. Set the colour to the same value you used as the image background (e.g. #92B2FFFF). You can change this if you want a different effect.

Drag the Button object into the Assets window to create it as a prefab. Delete the Button object from the Hierarchy.

Time to do some scripting. I'm assuming C# for these purposes.

Create a new script called Keypad and another called KeypadHandler.

Add Keypad to the Canvas, and KeypadHandler to the Cube.

In Keypad, declare an Interface for the keyboard.

internal interface IKeypadInterface {
    void KeypadSuccess(Keypad keypad);
    void KeypadFailure(Keypad keypad);
    void KeypadUpdated(Keypad keypad);
}

public class Keypad : MonoBehaviour {
  
}

We'll use this for communicating events that occur on the Keypad.

The next step is to build the keypad.

[RequireComponent(typeof(Canvas))]
public class Keypad : MonoBehaviour {
    Canvas parent;

    [SerializeField]
    Button buttonPrefab = null;

    [SerializeField]
    int columnCount = 3;

    [SerializeField]
    string[] buttonValues = { "X", "0", "OK", "1", "2", "3", "4", "5", "6", "7", "8", "9" };

    [SerializeField]
    int submitIndex = 2;

    [SerializeField]
    int cancelIndex = 0;

    [SerializeField]
    string keycode = "1234";

    [SerializeField]
    GameObject keypadHandler;
    IKeypadInterface keypadInterface;

    string internalKeypadValue = "";
    public string KeypadValue {
        get { return internalKeypadValue; }
    }

    // Use this for initialization
    void Start() {
        parent = GetComponent<Canvas>();
        keypadInterface = keypadHandler.GetComponent<IKeypadInterface>();

        BuildKeypad();
    }
}

There's a bunch of stuff here, but to break it down.

We're declaring some variables and using [SerializeField] to tell Unity to make them available in the inspector. This allows us to configure our keypad. buttonPrefab will be the prefab we created earlier. buttonValues is an array we use to label the buttons. submitIndex and cancelIndex are the index of the buttons which submit the code, or cancel it. the Canvas parent is a reference to the Canvas object our Button is in. We get that in the Start method. keypadHandler is the GameObject we added the KeypadHandler the script to, and keypadInterface is used to get the reference to the script class itself since Unity won't recognise the interface we declared in the inspector.

Add a new method, BuildKeypad, to generate the buttons.

    private void BuildKeypad() {
        // Get canvas size and correct for scaling
        RectTransform rectTransform = parent.GetComponent<RectTransform>();
        float parentWidth = rectTransform.rect.width * parent.scaleFactor;
        float parentHeight = rectTransform.rect.height * parent.scaleFactor;

        // Calculate button size
        float buttonSize = parentWidth / columnCount;
        // Minimum x position
        float buttonXStart = -(parentWidth - buttonSize) / 2;
        // Minimum y position
        float buttonYStart = -(parentHeight - buttonSize) / 2;
        Vector3 buttonPos = new Vector3(buttonXStart, buttonYStart, 0);
        for (int i = 0; i < buttonValues.Length; i++) {
            // Create new button from prefab
            Button button = Instantiate<Button>(buttonPrefab);
            // Add button to the Canvas
            button.transform.SetParent(transform, false);
            // Set button text
            button.GetComponentInChildren<Text>().text = buttonValues[i];
            // Set position of button
            button.GetComponentInChildren<RectTransform>().anchoredPosition = buttonPos;
            // Set size of button
            button.GetComponentInChildren<RectTransform>().sizeDelta = new Vector2(buttonSize, buttonSize);
            // Create a new primitive within the loop for the button, otherwise it will use the last value of i
            int buttonIndex = i;
            // Call ButtonPress with buttonIndex when a button is clicked
            button.onClick.AddListener(delegate { ButtonPress(buttonIndex); });
            // Increment x position
            buttonPos.x += buttonSize;
            // If we're at the far column, reset x and increment y
            if (i % columnCount == columnCount - 1) {
                buttonPos.x = buttonXStart;
                buttonPos.y += buttonSize;
            }
        }
    }

Not much to add that isn't in the comments. This assumes square buttons so you could have separate values for the width and height of the buttons. 

Lastly, add methods to handle button presses and validation of the keypad value.

    void ButtonPress(int buttonIndex) {
        if (buttonIndex == cancelIndex) {
            internalKeypadValue = "";
            keypadInterface.KeypadUpdated(this);
            return;
        } else if (buttonIndex == submitIndex) {
            ValidateKeypadValue();
            return;
        }

        string buttonValue = buttonValues[buttonIndex];
        internalKeypadValue += buttonValue;
        if (keypadInterface != null) {
            keypadInterface.KeypadUpdated(this);
        }
    }

    void ValidateKeypadValue() {
        if (internalKeypadValue.Equals(keycode)) {
            keypadInterface.KeypadSuccess(this);
        } else {
            keypadInterface.KeypadFailure(this);
        }
        internalKeypadValue = "";
    }

ButtonPress(int) will be called when a button is clicked on. If buttonIndex matches cancelIndex, we reset the value and call KeypadUpdated(Keypad). ValidateKeypadValue() will be called when OK is clicked. This will fire KeypadSuccess(Keypad), or KeypadFailure(Keypad), and reset the value. If neither are matched, we get the string value of the button from our buttonValues array and append it to the internalKeypadValue string.

Validating the value is just a simple string comparison. We can set the value we use for comparison directly in the Unity inspector window so our keypad can be re-used in multiple locations with different codes without any code changes. 

Open the KeypadHandler script. This one is much simpler.

public class KeypadHandler : MonoBehaviour, IKeypadInterface {

    [SerializeField]
    Light failLight = null, passLight = null;

    void Awake() {
        failLight.enabled = false;
        passLight.enabled = false;
    }

    public void KeypadSuccess(Keypad keypad) {
        passLight.enabled = true;
    }

    public void KeypadFailure(Keypad keypad) {
        failLight.enabled = true;
    }

    public void KeypadUpdated(Keypad keypad) {
        Debug.Log(keypad.KeypadValue);
        passLight.enabled = false;
        failLight.enabled = false;
    }
}

We set IKeypadInterface as an interface on this. Then declare the point lights we created earlier. In Awake, we turn the lights off by disabling them. Then we implement the methods declared in IKeypadInterface. On success, we enable passLight. On failure, we enable failLight. On a normal update (any keypress except 'OK') we turn the lights off.

Check everything builds. Fix any errors.

Now all we need is to hook everything up. Go back to Unity and select the Cube. If the scripts are compiling successfully you'll see Fail Light and Pass Light fields in the inspector under KeypadHandler script. Drag the appropriate point lights from the Hierarchy window to the fields (you can also click on the target icon to the right of the field and assign from that window).

Now, select the Canvas. Under the Keypad (Script) section you'll see our new fields. The only ones you need to set are Button Prefab (drag in the Button prefab we created earlier) and the Keypad Handler. Drag the Cube to the Keypad Handler field and we're done. 

Try entering a pass code (1234 by default), or try entering the wrong one and trying to submit it. Check that the lights are hooked up. If everything's working you should be finished. To take it further, implement a new handler for unlocking a door. This could even be, plausibly, expanded to provide a basic UI for more complicated controls (e.g. remote controlling items in the world, basic menu/dialog selection).

The full project is available on Github: https://github.com/stepheng/UnityKeycodeExample

Swift: Image Picker

A quick overview of getting an image from the camera, or the photo library.

First, set up your view in the interface builder. For this example, I'm keeping it really simple with a UIImageView and 3 buttons.

Update the UIViewController for your view to import MobileCoreServices (contains the constants required for defining what we want from the picker). Also, add support for the protocols we will need for our view controller to serve as a delegate on the picker. If you have created a new project, this will be ViewController.swift.

import UIKit
import MobileCoreServices

class ViewController: UIViewController {
 
}

extension ViewController: UIImagePickerControllerDelegate {

}

extension ViewController: UINavigationControllerDelegate {
    
}

Note that I've taken advantage of Swift's protocol extensions to keep my delegate handling code separate from the rest of my application code. This helps keeps things logically grouped and makes it easier to keep it tidy. I'm not interlacing different contexts which will make it easier to read if I come back to it months later.

Add the user interface code. We're going to get a reference to the UIImageView so we can update it. We'll also hook up actions to the buttons so we can trigger the desired behaviour.

class CameraViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    
    @IBAction func displayCamera(sender: UIButton) {
        displayImagePicker(.Camera)
    }
    
    @IBAction func savedPhotos(sender: UIButton) {
        displayImagePicker(.SavedPhotosAlbum)
    }

    @IBAction func photosLibrary(sender: UIButton) {
        displayImagePicker(.PhotoLibrary)
    }
    
    func displayImagePicker(sourceType: UIImagePickerControllerSourceType) {
        guard UIImagePickerController.isSourceTypeAvailable(sourceType) else {
            return
        }
        
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.sourceType = sourceType
        imagePicker.allowsEditing = false
        imagePicker.mediaTypes = [kUTTypeImage as String]
        presentViewController(imagePicker, animated: true, completion: nil)
    }
    
    func handleImage(image: UIImage) {
        imageView.image = image
    }
}

A quick description of what's here:
@IBOutlet allows us to connect a component from Interface Builder - just display the source code side-by-side with the Interface Builder view and Ctrl+Drag to connect them. If you drag to an empty space in your code, Interface Builder will prompt you to create an @IBOutlet, or @IBAction.
@IBAction allows us to connect an action on a component in Interface Builder. In this case, Touch Up Inside to define a touch event ending (lift up) that occurred inside the relevant component. As with @IBOutlet, Ctrl+Drag to connect the Interface Builder view to the source code.

The UIImageView, imageView, is defined as a weak reference as the reference will be held for us by the view so we don't need a strong reference in our UIViewController under most circumstances. Doing so can, in fact, lead to memory problems. We don't need specific references for the buttons since we don't need to access, or change, their state.

The @IBAction prefixed functions will trigger when the relevant button is pressed. I've included the button as a parameter, though this isn't necessary for this application, as it can be useful in other cases and is included by default if you let Xcode create the method for you. These methods just call a helper with an appropriate parameter for the source we want to get an image from.

displayImagePicker(sourceType) is a method that creates, and displays, the image picker. This just lets us reuse code that we'd otherwise have to include in all 3 of our IBAction methods since the only change, in this example, is the sourceType. Other than the image picker, the only notable addition is the use of a guard-statement to check if the source type is available. For this I'm just returning if it's not, but a more complete application might display an error message here.

handleImage(image) takes a UIImage as a parameter and updates the imageView to display it. This is nice for a test but of minimal use otherwise.

This code will run but will not do much because we don't currently handle the image retrieval. Nothing is calling the handleImage(image) method yet. Update the UIImagePickerControllerDelegate protocol extension like so:

extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        dismissViewControllerAnimated(true, completion: nil)
        let mediaType = info[UIImagePickerControllerMediaType] as! String
        if mediaType == kUTTypeImage as String {
            let image = info[UIImagePickerControllerOriginalImage] as! UIImage
            handleImage(image)
        }
    }
}

All we're doing here is handling the UIImagePickerController being dismissed and retrieving the image, if the media type is an image. It should be since we've requested that only image types be allowed but I've included the check in case you want to extend this to handle video in the future.

Note that, whilst we do need to declare that we support the UINavigationControllerDelegate protocol to assign our view controller as the delegate of the image picker, we don't need to handle any of the callbacks so we can leave this blank for now.

Run the app. It's better on a real device since the simulator doesn't support the camera, but the photo library should be accessible on both (privacy restrictions permitting). 

Swift: Initialising a 2D Array

I have a struct called Tile, which has (for now) a position defined as a tuple:

struct Tile {
    let pos: (Int, Int)
}

And a class called Board, which has a 2D array of Tile objects:

class Board {
    let tiles: [[Tile]]
    
    init() {
        var tilesArray = [[Tile]]()
        for row in 0..<Board.rows {
            var rowTiles = [Tile]()
            for column in 0..<Board.columns {
                let tile = Tile(pos:(column, row))
                rowTiles.append(tile)
            }
            tilesArray.append(rowTiles)
        }
        
        tiles = tilesArray      
    }
}

This works, though it feels a little messy... I'll have to come back and look at this again.

Xcode 7 and Swift 2: Unit Testing (again)

Some follow up from creating a new project and adding tests.

This turned out to be important...

This turned out to be important...

I hadn't really noticed in the last one but I hadn't added the new classes to the test target, as I would under Obj-C. In Swift 2 there's a new @testable keyword. I found it blogged by Natasha the Robot when I started looking to find out why I wasn't seeing any code coverage showing up for my classes.

Then I started wondering why I was getting Undefined Symbol errors. I could resolve them by including the classes, but then I wouldn't get coverage and everything I saw on @testable assured me I didn't need to include them. Finally, I remembered I'd been getting a bit click happy earlier. I'd disabled Allow testing Host Application APIs.

One checkbox later and I'm a happy camper...

Okay, not a lot done tonight but I feel like a few pieces fell into place.

NSInvocation - Calling Blocks

Because I always forget.

    id mockView = OCMClassMock([UIView class]);

    [[[[mockView stub] ignoringNonObjectArgs] andDo:^(NSInvocation *invocation) {
        __block void (^animationBlock)(void);
        [invocation getArgument:&animationBlock atIndex:3];
        animationBlock();
        __block void (^completionBlock)(BOOL);
        [invocation getArgument:&completionBlock atIndex:4];
        completionBlock(YES);
        
    }] animateWithDuration:0 animations:OCMOCK_ANY completion:OCMOCK_ANY];

Unity - Generating Builds

Adding the below code to Assets/Editor will add an entry to the menu bar that allows me to generate two builds automatically. Since they're also placed in a folder with the day's date, I also get build histories for the work done. For GameJams this is ideal as I'll usually only get a small amount of time on an evening to work on these so I'm not doing much more (and I could always use a more precise timestamp if needed). This is basic but so easy to automate and a nice little time saver that I thought I'd share.

using UnityEditor;
using System.Diagnostics;
using System;

public class JamBuilds 
{
    [MenuItem("Build/Jam Builds")]
    public static void BuildGame () {
        // Get filename.
        string path = EditorUtility.SaveFolderPanel("Choose Location of Built Game", "", "");
        string[] levels = new string[] {"Assets/Scenes/Test.unity", "Assets/Scenes/Finale.unity"};
        string projectName = PlayerSettings.productName;

        string date = DateTime.Now.ToString("/yyyy-MM-dd");

        // Build player.
        BuildPipeline.BuildPlayer(levels, path + date + "/" + projectName + ".exe", BuildTarget.StandaloneWindows, BuildOptions.None);

        // Build player.
        BuildPipeline.BuildPlayer(levels, path + date + "/WebPlayer", BuildTarget.WebPlayer, BuildOptions.None);

    }
}