Introduction

Many people are having problems building and embedding their Unity game in a Flash Builder project. This is largely due to insufficient documentation, bugs in the unity flash compiler, and a general lack of knowledge. This document aims to fill this gap by describing in detail how to build your Unity game, embed it in a Flash Builder project and explains how to communicate between both projects. The final project can be downloaded here, it features a working sample of sending complex data from and to Unity.

The target is to implement it in an AIR application, but regular Flash-web projects should work as well.

Prequisites

Before starting you'll need the following:

Personally i use Unity Pro and Unity Flash Pro, though i dont think this is required, Unity Basic and Flash Basic will suffice. You can download a trial of Adobe Flash Builder 4.6 here. (Note: The latest version (4.7) doesnt have a way to view your design, so i choose 4.6 instead.) Also this tutorial will use C# as scripting language for Unity, and (obviously)Actionscript for Flash.

Firstly you should read the available documentation thoroughly. It covers many basic aspects of Flash development, and is a good headstart. Sadly not everything is covered as much as you'd like, and a lot of flash-specific information is not explained in a way a non-flash developer would understand. For example, the Flash Setup page explains -swf version should be set to 15, /fp should be 11.2 and wmode should be direct. What isnt explained is what those settings are or how to set them.

Note on Adobe Premium License Eventhough the manual has a section about needing an Adobe License this is not required anymore, as described in this Adobe document. The docs will be updated soon. When using a debug version of the Flash player a warning is still visible, but this should be removed in the next flash release.

You should setup debugging as per the manual. The flash log will contain vital information for when things go bad during runtime. Also all Debug.Log statements can be found in the Flash logs, and when debugging in Flash Builder it will be visible in the console window.

Another good resource are the Flash Development forums, it contains some good samples on embedding as well, although questions there mostly go unanswered.

Flash still in preview?

How Unity Flash works

Stage3D

Flash player 11 introduced Stage3D, which is a library for Flash developers to use hardware accelerated content. It grants Flash developers access to hardware accelerated graphics, shaders and all other capabilities game developers have been using for years to create awesome content.

Converting the code

Sadly the only way to use this content is via Actionscript, this is why when you build your Unity project it converts all your code to Actionscript. You can find the converted code here: Temp\StagingArea\Data\ConvertedDotNetCode\global.

Original C# code
Converted Actionscript code
The converted code looks similiar, eventhough its now Actionscript. The names are a bit mangled, and some code is rewritten to be valid Actionscript, but its all there. This conversion works suprisingly well, although some features are currently not supported. There is no exact list of supported features, but it includes "Exotic libraries" such as LINQ and Reflection. Reflection has been part of the .NET framework since release, and LINQ is 5 years old now, i wouldn't call them exotic myself anymore. But i digress.

Building the project

Building the project usually is a fairly easy task, though some changes to the code may be required. The process usually goes like this:

  1. Build the project, the build fails with a Java error
  2. Inspect the error message. It contains the filename and line number of the offending script.
  3. Check generated file out, use common sense to see whats wrong and fix it in the source (C#) code.
  4. Rinse and repeat, 'till it builds!
A list of common errors and solutions can be found here.

Manually converting the code

Most problems can be solved by editing your source script, though its also possible to convert the class by hand. This is described in the manual here, abeit not completely.

No arrays on manually converted types! Be careful though, by doing this you lose the ability to use arrays on these types! When Unity converts your class it generates some additional information used for reflection, this is missing with your own classes. You can circumvent this by first letting Unity generate your class, then copy the GetType methods and pasting it in your AS class.
We'll use the ExampleObject from the manual, and extend on it. Out of the box the sample wont work, something with packages is not right. When you place a file with the exact contents of the ExampleObject in Actionscript/ExampleObject.as the following error occurs: \Actionscript\global\ExampleObject.as(9): col: 2 Error: The public attribute can only be used inside a package. The class has to be defined in a specific package, as such: When you try to build the project currently the following error occurs: This is described in the manual as "respecting ActionScripts requirements that the path needs to match the class namespace". What that means is that the file should be in a folder with the same name of the package. For example package global should be in Actionscript/global/, package com.test.data should be in Actionscript/com/test/data/.
Correct folder structure for an Actionscript class in the package global.

Running the project

After fixing all the errors the project should build properly, and run correctly in your browser using the supplied .swf and .html files. Rejoice! This was the 'easy' part of publishing to flash, and you should now be able to submit your game to any online portal you desire.

Embedding the project

The next step of this tutorial is embedding it with a Flash Builder project. This is useful if you want to create your UI in Flash Builder, or perhaps embed the project in an existing Flash application. This proved to be most difficult for me, a non flash developer. After actually figuring it out it seems quite trivial, you just have to know some specific settings and flash-tricks. The goal for this tutorial is:

  1. Actually running a simple flash project in an AIR project, with other flash GUI elements in the canvas.
  2. Sending a message from Flash to Unity.
  3. Sending a message from Unity to Flash.
Should any errors occur, at the end there is a Common Errors section. If it isnt listed there post in the forums and i'll try to update this document with the solution!

The project we'll use is fairly simple, it has one component on a GameObject with the name "FlashManager". The scripts contents are as follows:

Testscript.cs
ExampleObject.cs
You can download the project here. The code shouldnt be too shocking, only we use the [NotRenamed] attribute to prevent name mangling in our ExampleObject. We'll first embed this in a Flash Builder project, and after that implement the ReceiveExampleObject and SendExampleObject methods in TestScript.

Setting up Flash Builder

First we'll create our Flash Builder project, open Flash Builder 4.6 and go to File > New > Flex Project. Give the project a name, and optionally change the location. This tutorial explains how to embed your unity build in an Adobe AIR project, so select AIR under Application Type. Leave the SDK version on default (4.6) and click Finish.

The first document opened is (projectname).mxml, this is an XML file where you'll define the layout and visual elements in your application. For Silverlight developers, this is your XAML file. Another file that is generated is (projectname).xml, this contains some very important settings which we'll discuss later on.

Now go back to Unity to build your project, and save it as "build". Examine the resulting files, the ones that are important are: embeddingapi.swc and build.swf. The SWC file is like a DLL, it contains some classes which you'll need in order to embed Unity. Drag that to the libs/ folder in Flash Builder. The second .swf file contains the actual player, this is loaded in the scene and renders your project. Drag this in the default package, next to the existing .mxml file.

Creating the loader

Next up is creating an Actionscript class that loads and displays our Unity SWF file. This is partially described in this part of the manual. Begin by creating a new Actionscript class in the default package (Right mouse in Package explorer, New > ActionScript Class). You can safely ignore the warning Flash Builder presents about classes in the default package. Name your new class UnityLoader and click finish.

Protip: Use Quick Fix Wizard Many code samples in the documentation are stripped of their import statements. For those unfamiliar with "import" in actionscript, they are similar to Using in C#. Use the "Quick fix wizard" (Ctrl+1) to fix these errors.

The contents of UnityLoader.as should be as follows:

UnityLoader.as (click to download)
The code is fairly straightforward. The constructor first waits until this element is added to the view, then it creates the UnityLoaderParams and actually starts loading the SWF file. Be careful, this path to "build.swf" should be correct, otherwise you'll get a URL not found error when you run the project. Then an event listener is registered, which is a method that is called when a specific event is fired. After this loadUnity() is called, which starts the loading. The method onUnityContentLoaderComplete is fired when the SWF is loaded, it then adds it to the visible elements. This causes it to actually appear in your application! When Unity is actually ready the unityInitStart is called, currently we only do a Debug.Log to see if its working.

Adding it to the scene

Now we have to add it to our view, doing this requires 2 steps: Adding the namespace and declaring the Loader. Open yor .mxml file and make sure you are in Source mode. Add this attribute to the root element (s:WindowedApplication): xmlns:local="*", this includes the namespace so you can access UnityLoader. Then add <local:UnityLoader /> to the view. Great! We've created a loader and added it to the scene, we're almost done. Right?

Running the AIR application

Debug the build by pressing the following button:

Protip: Use the debugger! The debugger in Flash Builder is quite powerful, it allows you to set breakpoints and see output in the "Console" window. When debugging Trace is your friend. Its like Debug.Log, it shows anything you put in there in the log.
If all goes well a new window should open up, and the message "Engine Started!" should appear in the Console window of Flash Builder. However, to our dissapointment, the window is completely white. Something is wrong, lets fiddle around with settings.

Fixing settings, bashing skulls

There are 2 settings to adjust in order to make your view visible, namely:

Window Mode (WMode)

Something is up with WMode when there is nothing visible at all, or the following error occurs: You can set the WMode for an AIR application in your (projectname).xml file, its under renderMode:

BackgroundAlpha

After you've set the WMode correctly you still need to alter one more thing, the BackgroundAlpha property of your WindowedApplication has to be 0. This can be found in the main MXML file.

Running, winning!

Try debugging the project again, unity should run just fine now! You can even add more GUI elements in the scene, they are all displayed nicely along Unity. Are you still having problems? Scroll all the way down for a few issues and solutions.

Communication between Flash and Unity

Its important to realise your code is translated and executed as Actionscript. Though it is not easily accessible by the Flash Builder project, because its built in the SWC file. (If this is untrue, please let me know!). It still is possible to send complex data structures to Flash, by emitting some Actionscript yourself.

Flash to Unity

Sending from Flash

We'll start by trying to send an object from Flash, to Unity. Lets add a button to the scene, and send our ExampleObject when you click on it. Add the following code to your .mxml file:

(projectname).mxml (Click to download)
As you can see we define a new Button, and add a click handler button1_clickHandler. In this method we call a function on our unityLoader, which we retrieve by its id property. The SendMessage function isnt defined yet, but its purpose is clear, the first argument is GameObject name, second method name and the third is the argument. Actionscript (and Javascript) is a weak typed language, this means we can create an object with properties on the fly. We use this to define an object that looks like our class.

UnityLoader.SendMessage is defined as follows:

UnityLoader.as (Click to download, rename to UnityLoader.as)
Simple enough, we route the call to our unityContent. Lets receive it!

Receiving in Unity

Great, now we can use our old familiar friend SendMessage. Lets go back to Unity and actually receive the object! The problem is, we cant just accept ExampleObject as parameter in our ReceiveExampleObject method, nor cast an Object to ExampleObject, the type we send and receive are not compatible. When you try that anyway you get the following error: Instead we'll do the following: Emit some ActionScript code ourself that sets all properties on our type. That sounds like a lovely little hack doesnt it! Complete the ReceiveExampleObject function in TestScript.cs with the following code: Again its actually fairly straightforward. When we are using Flash the object is first cleared, then each property is extracted. If you have a hard time understanding this you should look at the generated actionscript, it should make more sense.

Testing

Build the player and update the build.swf file, then run the project. Everything should work just fine now, whenever you press your button a new random int is displayed, and the other fields are updated as well.

Unity to Flash

Great, now we have Flash chatting to Unity, now lets try to send a message to Flash. This is a little bit more complicated. In order to communicate we'll need to get a reference to the UnityLoader object we have in Flash. Once we have that we can call any function on this object, with any argument we'd like. Extend UnityLoader.as with the following method: Simple enough, when Unity is done send our current object to the FlashManager. We'll use this reference to call any function on the loader. The second function is the actual method called by Unity. As you can see the argument has the same properties as our ExampleObject.

Lets store the responder in Unity, and call some functions on it! Open up Testscript.cs in Unity and add the following code: The first method is called when Unity is loaded to get the reference to the UnityLoader object. It stores the reference as a private variable, so we can use it later on.

Next we implement SendExampleObject, which is called in the OnGUI. This in turn calls SendFlashMessage, which calls a function on our responder object.

Make sure TestScript is still on FlashManager, build it and move the build.swf in the Flash Builder project, overwriting the old one. Debug (f11) it and behold, when you click on the flash button it sends our ExampleObject to Unity, when you click on the Unity button it sends it back. It will be visible in the console window. Click here to download the complete project if you got stuck somewhere.

Misc

Containing the mouse

By default Unity updates all the time, even when the mouse is not in the current viewport. This causes any mouse-logic to also occur when you use other controls on the canvas. Add this method to FlashManager, will check if the mouse position is within the viewport. Its quite simple, the responder object we've sent before has additional properties about the position and dimensions of the control. We extract those and then do a simple rect check. Before doing anything mouserelated you should check if its actually within the screen.

Common errors while embedding

Still having problems? These are the issues i've faced when trying to embed my project.

URL not found on startup

The path to your SWF file is invalid, open UnityLoader.as and make sure the swf file name is correct, and the SWF is copied to the output directory (bin-debug).

Error #3669: Bad input size

I've had the following problem, whenever i started the following exception occured:
Exception
This was caused because i didnt set a width and height as params. They are set in the Actionscript code "UnityLoaderParams", check to see if this is done correctly. If this doesnt work, some people suggest removing stage.Scale and stage.align from the code.

Errors using Assetbundles.

These errors pop up in the flash logs when i use Assetbundles and instantiate objects. Everything does seem to work normally afterwards though. In Firefox this causes a lot of lag, other browsers and AIR are fine. Sadly i dont know what causes them or how to fix it. Because we only use air, its not a problem at the moment.

Still having questions?

Questions or suggestions? Please post them in the forum so everyone can read them, and perhaps the solution can help a fellow coder from the future. You can also email me directly with questions. Keep in mind im not affiliated with Unity in any way, only that i have a strong love-hate relationship with their awesome products.