Archive for the ‘Tutorials’ Category

A Cocoa-Based Frontend For Unity iPhone Applications

Friday, January 23rd, 2009

I spent about 3 months at the end of 2008 knee-deep in Unity iPhone — first testing the beta and then working with the release version. I spent tons of time just playing with it, learning its capabilities and how to optimize for it. That’s a whole other post though, which I’ll get to sometime in the future. For now I want to talk about the Cocoa frontend that I developed for all our Unity iPhone games.

Why use a Cocoa frontend?

We wanted a way to allow players to login using their Blurst user id in our iPhone games, but Unity iPhone doesn’t yet support the iPhone keyboard. We could have simply used the device id to let users pair their account via the webpage, but I wanted a more elegant solution. Furthermore, after working on iSplume (which we coded entirely using Objective-C), I found that I could make menus much faster in Apple’s Interface Builder than in UnityGUI. Adam and I planned a fair number of menus in Rebolt, so I wanted a way to make them in Cocoa/Interface Builder.

So I set a goal: Make an easily extensible Cocoa frontend for Unity iPhone that supports Blurst logins and supports any menus we might want. It should work for any project we add it to, so we don’t have to do tons of custom code for every game. Further, it should require changing as little of ReJ’s existing Objective-C AppController code as possible, in the event that it changed in a later build. Finally, I wanted an easy way to add my additional files to the XCode project once I created a build. This is particularly important because, to maintain rapid iteration times, there must be a minimal amount we have to do in XCode between creating a build and installing that build on the phone.

Basic Architecture

The basic idea is that we write our own UIApplication delegate to replace AppController, and then forward events like applicationWillTerminate: to the existing AppController once we’ve started the Unity content. We’ll also keep a loop running in the background once the Unity content is created that checks the PlayerPrefs file. We’ll use this to get back to the menus from within the Unity content. Finally, we’ll organize the Cocoa content in such a way that we can easily add it to the XCode project that Unity iPhone spits out. We’ll use a PostprocessBuildPlayer Perl script to accomplish this.

Writing our own UIApplication delegate

Our UIApplication delegate needs to do a few different things. First, we want to handle the usual application event callbacks — applicationDidFinishLaunching:, applicationWillResignActive:, etc. Unless we’re particularly interested in some event, or we’re doing something more complex than just menus, we will just forward most of these messages to ReJ’s AppController. The notable exception is applicationDidFinishLaunching:, which we will use to launch our frontend and add a scheduled timer to the app’s run loop that will listen for menu return requests.

We’ll also want a few functions for switching between Unity and Cocoa content. We’ll create launchFrontend, cleanupFrontend, and launchUnity methods to handle switching content. We’ll also create a checkForReturnToMenu: method that our scheduled timer will call regularly. This will read the PlayerPrefs file and, if it finds a specific key, hide the Unity content and re-launch our frontend.

Here’s a zipped copy of the default Flashbang UIApplication delegate files — download it and follow along as I describe the various sections.
flashbangfrontend.zip

First, we’ll take a look at the header file. Note that we explicitly adopt the UIApplicationDelegate protocol. We also keep references to the application window and the Unity AppController.

#import "FBGameSettings.h"
#import "FBScene.h"
#import "FBSceneManager.h"
#import "FBSceneSetup.h"
#import "AppController.h"

// Integer tag that we use to distinguish the Unity view
#define UNITY_VIEW_TAG 1

@interface FBFrontendController : NSObject
{
   // A local reference to the app’s window
   UIWindow *window;
   // ReJ’s original AppController that runs Unity
   AppController *unityController;
}

- (void)checkForReturnToMenu:(NSTimer *)timer;
- (void)launchFrontend;
- (void)launchUnity;
- (void)cleanupFrontend;

@end

The specific details of the headers I’m importing are mostly unimportant. FBGameSettings.h is just some game-specific #defines (version number, etc). FBScene is a subclass of UIViewController and represents a generic menu scene. Specific scenes needed by an individual game are subclasses of this. FBSceneManager keeps a hash table of all scenes and handles transition animations between them. We’ll take a closer look at FBSceneSetup.h later.

Starting the Application

Now let’s take a look at the implementation of FBFrontendController. We’ll look at the applicationDidFinishLaunching: method first.

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
   [application setStatusBarHidden:YES animated:NO];

   // Clear keys that signal transitions back and forth from
   // Unity, just in case
   [FBPlayerPrefs deleteKey:@“_start_cocoa”];
   [FBPlayerPrefs deleteKey:@“_start_unity”];

   // reset blurst logged in status
   [FBPlayerPrefs deleteKey:@“blurst_online”];

   // Start listening for signal to return to menus
   [NSTimer scheduledTimerWithTimeInterval:1.0 target:self
      selector:@selector(checkForReturnToMenu:)
      userInfo:nil repeats:YES];
   [self launchFrontend];
}

Here, we first delete the two PlayerPrefs keys we’ll use to communicate that we want to swap between Cocoa and Unity — _start_cocoa and _start_unity. This ensures that we know their initial states. Note: Unity iPhone stores PlayerPrefs using NSUserDefaults. FBPlayerPrefs is just a wrapper for NSUserDefaults that behaves like the PlayerPrefs class in Unity. We then begin a timer that runs our checkForReturnToMenu: method once per second. A shorter delay here means faster responsiveness for opening the frontend from within Unity, while a longer delay will give better performance. Finally, we run our launchFrontend method. Here’s the checkForReturnToMenu: method.

- (void)checkForReturnToMenu:(NSTimer *)timer
{
   if([FBPlayerPrefs getInt:@“_start_cocoa” orDefault:0] == 1)
   {
      [FBPlayerPrefs deleteKey:@“_start_cocoa”];
      [self launchFrontend];
   }
}

This simply checks for the proper key in PlayerPrefs and then launches the frontend if it finds it.

Launching Our Frontend

Here’s the launchFrontend method, which we call whenever we want to display our Interface Builder-constructed menu system:

- (void)launchFrontend
{
   // re-sync the PlayerPrefs file, in case we’ve been in Unity
   [FBPlayerPrefs readPrefsFile];

   // Create the window if we don’t already have one
   if([UIApplication sharedApplication].keyWindow == nil)
   {
      window = [[UIWindow alloc] initWithFrame:[[UIScreen
         mainScreen] bounds]];
      [window makeKeyAndVisible];
   }

   // Check to see if any views are exclusive/multitouch (ie find
   // the Unity EAGLView). Temporarily disable it, and tag it
   // so we can find it later
   for(UIView *v in window.subviews)
   {
      if(v.exclusiveTouch && v.multipleTouchEnabled)
      {
         v.exclusiveTouch = NO;
         v.multipleTouchEnabled = NO;
         v.tag = UNITY_VIEW_TAG;
         v.hidden = YES;
      }
   }

   // load menu scenes
   LoadScenesInWindow(window);

   // start the first scene
   [FBSceneManager startScene:FIRST_SCENE
      withTransition:FBSceneTransitionNone];
}

Here we create the application window if it doesn’t exist, we disable interaction with the Unity view if it’s present, then we load our custom views in the window. Finally, we start our first scene using the scene manager. LoadScenesInWindow is a function defined in FBSceneSetup.h — we’ll take a quick look at that.

#define FIRST_SCENE @"Title"  // The string key for our first scene

// load in game-specific scenes and define function to load them
#import "SceneCredits.h"
#import "SceneOptions.h"
#import "SceneTitle.h"
#import "SceneGame.h"

void LoadScenesInWindow(UIWindow* window)
{
   [window addSubview:[[[SceneCredits alloc] init] view]];
   [window addSubview:[[[SceneOptions alloc] init] view]];
   [window addSubview:[[[SceneTitle alloc] init] view]];
   [window addSubview:[[[SceneGame alloc] init] view]];
}

Recall that each SceneXXXX is a subclass of FBScene, which is a subclass of UIViewController. The init method of each SceneXXXX first calls initWithNibName: with the name of each scene’s Interface Builder xib, then adds the scene to the scene manager with an appropriate string-based key. The LoadScenesInWindow function thus initializes each view controller and adds its view to the window. The idea behind this architecture is that for any given project, we only have to edit FBSceneSetup.h, and then create the appropriate SceneXXXX subclasses to manage each of our scene xibs. That is, FBSceneController will be the same for every project.

Launching Unity

Now we’ll take a look at how we launch the Unity content.

- (void)launchUnity
{
   [self cleanupFrontend];
   // Tell Unity loading scene to stop holding
   [FBPlayerPrefs setInt:1 withKey:@“_start_unity”];
   [FBPlayerPrefs saveAndUnload];

   // If we’ve not yet started the Unity content, run its startup
   if(unityController == nil)
   {
      unityController = [[AppController alloc] init];
      [unityController applicationDidFinishLaunching:
         [UIApplication sharedApplication]];

      // Set our window to the one created by ReJ’s AppController,
      // for any future use
      window = unityController->_window;
   }

   // If we’ve already got Unity content running, show it and
   // return its Exclusive/multitouch status
   else
   {
      for(UIView *v in window.subviews)
      {
         if(v.tag == UNITY_VIEW_TAG)
         {
            v.exclusiveTouch = YES;
            v.multipleTouchEnabled = YES;
            v.hidden = NO;
            [window bringSubviewToFront:v];
         }
      }
   }
}

We start out by cleaning up the frontend (which just tells the scene manager to remove its views from the window and releases them). We then set the _start_unity PlayerPrefs key, so that our loaded Unity content will know we want it to start executing. After that, there are two possible codepaths. The first time we call the method, it will call AppController’s applicationDidFinishLaunching: method, and then point our local window reference to the one created by AppController. Once the Unity content is initialized (if we’ve come back to the menu and then want to return to Unity), we find our Unity view by the tag we set in launchFrontend, return it to the front, and re-enable interaction with it.

We’ll typically want to run this method in response to a button press in some view. Here’s an example use:

- (IBAction)playButtonPressed:(id)sender
{
   [(FBFrontendController *)[UIApplication
      sharedApplication].delegate launchUnity];
}

Using the Frontend From Unity

To get back to the frontend from Unity, we just need to set the _start_cocoa PlayerPrefs key. Since the Unity content will continue running in the background, you’ll also want to pause your game and have a loop continue to check for the _start_unity PlayerPrefs key.

Putting It All Together — Project Organization and PostprocessBuildPlayer

So this frontend stuff is all well and good, but it would be a royal pain in the ass if we had to copy the files into the project manually and edit ReJ’s files every time we made a build. But, as usual, it’s Perl to the rescue!

We’ll first create a directory inside our project that will contain all of our frontend files. We’ll set it up so that we can also replace the application icon and splash screen in the same pass. First, create an “XCode” directory within the Unity project. Any files that you want overwritten in the default XCode project should be in the same locations with the same names. So for instance, we’ll add Icon.png and Default.png to the root of the XCode directory. Put anything that you’re adding to the project (all the frontend files) into a separate “Frontend” sub-directory. So your tree should end up something like this:

XCode Directory Tree

Now we’ll take a look at the PostprocessBuildPlayer script. If you aren’t familiar with it, check the Build Player Pipeline section of the Unity Manual. Here’s my script, written in Perl:

#!/usr/bin/perl

#################################################################
# Build Player postprocessor for Unity iPhone projects. Injects #
# FBS Frontend into generated XCode project                     #
#################################################################

# Path for assets that will get added to the XCode project.
# Relative to the project root directory.
$iPhoneAssetPath = “./Assets/XCode/”;
$toPath = $ARGV[0];

##########################################################
# Copy iPhone assets from Unity project to XCode project #
##########################################################

opendir(XCODEDIR, $iPhoneAssetPath) || die(“Cannot open directory $iPhoneAssetPath”);
@files = readdir(XCODEDIR);
closedir(XCODEDIR);

# copy files from Unity iPhoneAssetPath to the generated XCode project
foreach $file (@files)
{
   # kind of a lazy hack
   unless(($file eq “.”) || ($file eq “..”))
   {
      #`echo $file > log.txt`;
      $fromPath = $iPhoneAssetPath.$file;
      `cp -R \‘$fromPath\’ \’$toPath\’`;
   }
}

################################################################
# Change default UIApplicationDelegate to FBFrontendController #
################################################################

$omPath = $toPath."/Classes/main.mm";
$nmPath = $toPath."/Classes/main.mm.tmp";

open OLDMAIN, "<", $omPath or die("Cannot open main.mm");
open NEWMAIN, ">", $nmPath or die("Cannot create new main.mm");

while(<OLDMAIN>)
{
   $_ =~ s/\”AppController\”/\”FBFrontendController\”/;
   print NEWMAIN $_;
}

close OLDMAIN;
close NEWMAIN;

`mv "$nmPath" "$omPath\’`;

#################################################
# Make _window variable in AppController public #
#################################################

$oacPath = $toPath."/Classes/AppController.h";
$nacPath = $toPath."/Classes/AppController.h.tmp";

open OLDAC, "<", $oacPath or die("Cannot open AppController.h");
open NEWAC, ">", $nacPath or die("Cannot create new AppController.h");

while(<OLDAC>)
{
   if($_ =~ m/UIWindow.*window/)
   {
      print NEWAC "\t\@public\n";
   }
   print NEWAC $_;
}

close OLDAC;
close NEWAC;

`mv "$nacPath" "$oacPath"`;

As you can see, this script does three things — copy all the files from our XCode directory to the built XCode project, change the UIApplicationDelegate in main.mm to FBFrontendController, and make the _window variable of AppController public. So we’ve managed to implement our own frontend by changing only two lines of existing code!

Building the Project

I know of no way to add files to an XCode project via the command line, so you will still have to manually add the files to the project after building. However, because of the way that we’ve organized the project, this will be relatively simple. It does mean, however, that “Build and Run” will no longer work as a one-click solution.

Build the project in Unity and open the generated project in XCode. Select Project -> Add To Project… (Cmd + Option + A), and select “Frontend” directory. In the next dialog, choose to “Recursively create groups for added folders:

Add files to project dialog

That’s it! You’ll now have the references needed to run your custom frontend before the Unity content — simply build and run in XCode!

Unity Basics: An Introduction

Friday, December 26th, 2008

Unity 2.5’s release is finally on the horizon, which means Windows editor!  In addition to some great new workflow and editor features, 2.5 will also usher in a wave of Windows users.  There is a lot to learn about Unity, when you first encounter it, so we’re going to do a series of Unity Basics posts, with an introduction to some of the core concepts.  This first post answer the question:

What is Unity?

Unity’s scope makes concise definition difficult.  Unity is a lot of things, and it’s used differently by different disciplines, but here’s one breakdown. Unity is:

An Integrated Editor

Unity provides an editing environment where you organize your project assets, create game objects, add scripts to these objects, and organize objects and assets into levels.  Most importantly, Unity provides a “game” view for your content.  You can hit play and interact with your content while you watch values, change settings, and even recompile scripts.

The IDE is largely stateless, in that there is little distinction between creating your levels and playing them.  For example, the editor remains functionality identical whether your content is stopped or currently playing.  This is hugely useful, because while your content is playing you can hit pause and then move things, create new objects, add scripts, and whatever else you need to do to test gameplay or chase down bugs.

Different team members and disciplines use the editor differently.  Here at Flashbang artists use the editor to smoke test new asset imports, arrange assets into levels, and tweak textures and other visuals.  A programmer may focus more on watching values and tweaking numbers.  A unified interface helps us tremendously; we don’t have people using different tools with different interfaces and workflow conventions.

A Component Architecture Paradigm

Unity utilizes a component-based architecture.  You could ignore this in creating your game logic, but you will suffer without a clear understanding of Unity’s design.  In Unity, every object in your scene is a GameObject.  An arbitrary number of Components are attached to GameObjects to define their behavior.

For example, a physical crate might be:

  • GameObject
    (name, layer, tags)

    • Transform
      (position, rotation, scale, parent)
    • Mesh Renderer
      (actually draws the object)
    • Box Collider
      (define collision volume)
    • Rigidbody
      (movable physics object)

Here’s the key:  When you create a script, you create a component. For example, you could create a Jump.js script to make your cube jump when you press a key, like:

var strength:float = 30.0;

function Update()
{
   if(Input.GetKeyDown(“space”))
      rigidbody.AddForce(Vector3.up * strength)
}

JavaScript hides some of the details, but what’s happening here is you’ve created a new Jump Component.  Your script implicitly inherits from MonoBehaviour, which inherits from Behaviour, which inherits from Component.  You now have a new component, which you can easily add to your crate!

Note:  We use JavaScript at Flashbang, for a variety of reasons, but the steps are quite similar in C#.  The only real different, aside from syntax, is that you need to explicitly define the inheritance:

using UnityEngine;
using System.Collections;

public class Jump : MonoBehaviour
{
   public float strength = 30.0f;

   void Update ()
   {
      if(Input.GetKeyDown(“space”))
         rigidbody.AddForce(Vector3.up * strength);
   }
}

A Game Engine

Unity is a fully-featured game engine.  It includes and exposes many systems needed for game creation, such as:

  • Graphics Engine
    Unity’s graphic engine includes a shader language, ShaderLab, which wraps Cg and GLSL shaders with additional engine semantics.
  • Physics Engine
    Unity uses NVIDIA PhysX for their physics engine, with editor and API integration (you set up collision volumes, joints, and things by adding components to your GameObjectsin the editor, and script physics with things like Rigidbody.AddForce() and MonoBehaviour.OnCollisionEnter() callbacks).
  • Audio Engine
    Unity has a positional audio system.  You can play sounds in 3D space, or “2D” stereo sounds.
  • Animation System
    Unity includes an animation system, including support for animation layers, blending, additive animations and mixing, and real-time vertex/bone reassignment.

There are quite a few other out-of-the-box systems there to help you, too, like particle systems, networking, UnityGUI, and so on.

A Scripting Platform

Unity embeds Mono to power its scripting environment.  You can script in C#, JavaScript, or Boo (a Python variant).  Mono itself is an open-source version of the .NET development environment.  Note that this doesn’t mean that Unity requires .NET.  Mono is totally distinct from Microsoft’s .NET, and Unity totally embeds Mono.

It’s also worth noting that Unity’s use of Mono goes above and beyond the compiler and common language runtime.  You also get the full .NET namespace, which means a huge amount of classes are available to you out of the box:  XML parsing, cryptography, sockets, and more.

As I mentioned earlier, Flashbang uses JavaScript.  Unity’s JavaScript isn’t very similar to the JavaScript language found in web browers.  It’s about as similar to web JavaScript as Flash’s ActionScript, which is to say not very similar at all.  There are a number of advantages to using UnityScript, although there are far fewer tools available (we use a custom-created hack of FlashDevelop).  With the advant of the Windows release, I imagine many newcomers will choose C# and Visual Studio.  Lucas Meijer makes a very compelling case for C# scripting over at his Unity blog.

A Scripting API

Your Mono-powered scripts have full access to Unity’s engine through Unity’s scripting API.  They’ve exposed the entirety of the engine, which means that you can do pretty much anything.  High level stuff is quite easy and simple, but you can dig all the way down to doing mesh generation or direct OpenGL calls if you’d like (which work on DirectX, thanks to Aras’ genius).

MonoBehaviour, the parent class for your scripts, provides a number of convenience members.  Things are usually quite straightfoward.  For example:

  • transform.position = Vector3.zero;
  • rigidbody.AddForce(Vector3.up * 10);
  • renderer.enabled = false;
  • particleEmitter.Emit(10);

There are a number of callbacks provided for game logic purposes:

  • Start()
  • Update()
  • OnCollisionEnter()
  • OnMouseDown()

The scripting environment supports coroutines, which are magically useful for all kinds of things.  Want to destroy an object 3 seconds after it was hit with something?

function OnCollisionEnter()
{
   // do something
   yield WaitForSeconds(3.0);
   Destroy(gameObject);
}

In addition to scripting your game at runtime, Unity provides a powerful editor API to create custom tools, windows, and shortcuts to expedite your workflow in the editor itself.  With Unity 2.5 the entire editor itself has been rewritten with the Unity API (which means you should be able to do practically anything they have).

More to Learn!

As you can see, Unity is quite broad.  This article should provide a good starting point for its top-level features, but even this overview hasn’t covered the whole of the software.

We’ll dive into more Unity features in depth in future Unity Basics articles.  We didn’t talk much about the Inspector (and how variables are serialized in Unity), or asset importing, or any number of other features.  What would you guys like to focus on?  Use the comments below to let us know!