Flash-to-unity communication using uniTool

A recent project of mine, the OUTFLEXX-Loungeplaner, is an online planning program for outdoor-furniture, coded in Flash. It mainly consists of a 2D-floorplanner combined with a realtime 3D-visualisation of the furniture items. Initially I used Away3D within Flash for rendering the 3D part, but I also wanted to build a “premium”-version of the planner, using Unity to render the 3D-visualisation. I hit on one problem immediately: the Flash-part had to communicate with the Unity-part and vice versa. Exactly for this purpose smarter people than me have already coded an off-the-shelf solution: uniTool.

uniTool by Duncan Hall is a javascript-/actionscript-framework. Any SWF-object that is embedded into an HTML-page can use it to

  • initiate the Unity-webplayer download and install, if the plugin isn’t already available in the browser
  • embed one or more unity-objects in the HTML-page dynamically (or remove them after use)
  • exchange messages with those unity-objects, make them visible or invisible

But beware: uniTool only provides for the embedding of the Unity-objects via Flash and the communication between Flash- and Unity-objects within an HTML-page! uniTool does not incorporate the unity-content into the flash file – so still both browser-plugins have to be installed.

First of here’s a diagram showing all the components of an HTML-page that are involved in the process of embedding and communication:

Overview

Quite complex and confusing for a start, but I will try to explain these processes separately and successively.

Download and installation

The uniTool-framework can be downloaded, together with an example application, as a zip-file from Google Project Hosting:

Download code as zip-file DOWNLOAD FRAMEWORK-SOURCE

After downloading and unzipping, the files in the “src”-folder have to be moved/copied to their correct locations on the harddrive:

ActionScript file
All the ActionScript files in the subfolder “src/as3″ have to be accessible to your projects’s fla-file. The easiest way to achieve this is to copy the “net”-folder with all enclosed subfolders into the same directory that your fla-file resides in.

JavaScript file
The file “uniTool.js” within the folder “src/js” has bo be linked to the HTML page of your project that contains the swf. So you have to copy it to a location that is accessible from your final HTML page.

Additionally, I made 2 changes to the “uniTool.js”-file:

1) Webplayer version (lines 244 to 247)
Version 3 of the unity webplayer is the current one as of the time of writing of this tutorial, so I changed the “-2.x” to a “-3.x” in all of the urls:

DEFAULT_INSTALL_URL: "http://www.unity3d.com/unity-web-player-3.x",
INSTALLER_MAC_INTEL: "http://webplayer.unity3d.com/download_webplayer-3.x/webplayer-i386.dmg",
INSTALLER_MAC_PPC: "http://webplayer.unity3d.com/download_webplayer-3.x/webplayer-ppc.dmg",
INSTALLER_WINDOWS: "http://webplayer.unity3d.com/download_webplayer-3.x/UnityWebPlayer.exe",

2) Fix for the Google Chrome browser (line 650)
This line reads originally like this:

else if (navigator.appVersion.toLowerCase().indexOf("safari") != -1) return document.getElementById(this.objectID);

Here’s the changed version that enables flash-unity-communication with the Google Chrome browser:

else if (navigator.appVersion.toLowerCase().indexOf("safari") != -1 <strong>&& navigator.appVersion.toLowerCase().indexOf("chrome") == -1)</strong> return document.getElementById(this.objectID);

Setting up the HTML code

JavaScript with HTML
The JavaScript-file has to be linked to the HTML code, so that the javascript functions are available within the page to the swf. This is done with this line in the <head>-section:
<script src=”uniTool.js” type=”text/javascript”></script>
That’s all the javascript coding there is within the HTML, the uniTool functions are all called from the flash and unity objects respectively.

SWF with HTML
The swf object has to be embedded into the HTML code using the standard procedures (SWFObject, HTML code generated by Dreamweaver, Flash, …). Two of the embedding parameters are important for uniTool to work correctly:

“allowScriptAccess”:
“sameDomain” or “always”, must not be “never”

“wmode”:
if the unity object overlaps the swf area completely or partially (as it does in my project), wmode has to be set to “transparent” or else there will be display errors in some browsers.

UNITY with HTML
The unity object is embedded at runtime by the flash movie. In order for the communication between them both to work, uniTool must provide the embedding of the unity object. So in the HTML code we need only an empty <div> with an unique id:

<div id=”unity_content” class=“unity_style“ ></div>

The <div> id is passed from ActionScript to the uniTool.js, which generates and embeds the necessary HTML code there. By using the CSS class “unity_style” you can apply additional formating and positioning to the <div>.

Handling the uniTool-framework in your Flash project

First of all, you can find the complete online docs for the ActionScript-classes by Duncan Hall here.

Coding and debugging a Flash-Unity-project is not quite trivial, as all the uniTool-JavaScript-calls from Flash are executed by the ExternalInterface()-command. Those calls are only successful if the browser’s DOM-object and its JavaScript-engine are available. A simple “Test Movie”-command from within the Flash Authoring Tool does not work, the HTML page with the SWF has to be opened within a browser – either from an online test server or locally from a WAMP-/MAMP-installation.

Step 1 – Initializing UniTool

The UniTool-class takes care of handling the communication. It can even be used independently of a specific unity object, for example to check if the unity webplayer plugin is installed prior to embedding a unity object.

Before you can use any of the UniTool methods, UniTool has to be initialized once. This is done with the UniTool.init()-method. As the UniTool-class is static, its methods can (and must) be called directly on the class, without creating an object instance first (just like Flash’s built-in “Math”-class):

So this is wrong:

myUniTool:UniTool = new UniTool();
myUniTool.init();
// -> Error!

This is the right way:

UniTool.init();

Step 2 – Check if the unity webplayer is available and optionally install it

The UniTool.init()-call sets among other things its property “pluginIsInstalled” to true or false. So one line of ActionScript is enough to check if the unity webplayer ist installed:

if (UniTool.pluginIsInstalled) {...}

If the plugin is not installed, we could start the download and installation right away with a call to the UniTool.installPlugin()-method. The user is then immediately presented a “file save”-dialog. It is more user-friendly though to first show an “Install Unity Webplayer”-button to the user and only start downloading and installing when the user actually clicks on it.
Additionally to the installPlugin()-method to start the installation we use the UniToolEvent which is fired as soon as the installation is completed:

UniTool.addEventListener(UniToolEvent.PLUGIN_INSTALL_COMPLETE, onPluginInstallComplete);
UniTool.installPlugin();

In the “onPluginInstallComplete()”-function called by the event, the unity object can be initialised and embedded (steps 3 and 4).

Employing this PLUGIN_INSTALL_COMPLETE event listener has the great advantage, that the unity content is displayed immediately following the plugin installation. Neither the browser has to be closed and re-opened nor the HTML-page has to be reloaded!

Step 3 – Initializing the UObject

Now that the availability of the unity webplayer has been ensured, now is the time to initialize the unity object. This initialization does not yet load, embed or display the unity file – it just creates an ActionScript object that holds the necessary data.

var unityObject:IUObject = new UObject(src, containerID, width, height, options);

There are four parameters passed to this method:

src:String
// file name and path (relativ to the HTML-file) to the Unity-object
// for example “unity/Loungeplaner.unity3d”

containerID:String,
// the id of the <div> to be used for embedding the unity object
// for example “unity_content”

width:int
// the width of the unity object in pixels
// for example 600

height:int,
// the height of the unity object in pixels
// for example 400

options:UembedOptions
// various options that affect the loading process

The UembedOptions object optionally defines the appearance of the loading screen and the progress bar, among other things. Important for the overall loading process are these two attributes:

UembedOptions.data.autoInstall:Boolean
// If “autoInstall=true”, the download and installation of the unity webplayer starts automatically as soon as the unity object is embedded (step 4), if the webplayer is not installed. Personally I prefer a plugin-check in advance and showing some “Install Unity”-button in this case, to give the user the choice whether to install the plugin or not.

UembedOptions.data.queueEmbed:Boolean
// “queueEmbed=true” embeds the unity object automatically in the HTML code after a plugin installation is completed.

Step 4 – embedding the unity object

Having done all the preparations, it is now time to actually embed the unity object in the HTML code. This is again done with a single line of ActionScript:

// Correct:
unityObject = UniTool.embedUnity(unityObject);
// Fail!!!
UniTool.embedUnity(unityObject);

The second piece of code seems to work just fine initially (the unity object is correctly embedded and displayed), but the communication between the flash and the unity object is BROKEN! It is vital to re-assign the object reference returned by the UniTool.embedUnity()-method to the unityObject-variable, because the returned reference points to another, new unityObject, not to the original unityObject that was passed in to the method.

This step makes the unity object visible within the HTML page, the unity file is downloaded, displayed and postitioned using the <div>-CSS-attributes.

With the unity contents now loaded, made visible and positioned correctly, there’s only one more thing to do: coding the communication between the flash and the unity object. Naturally, this connection has two directions – let’s first take a look at

Step 5 – Flash talking to Unity

ommunication flash to unity

The flash part
In order to call a function or method within the unity object, this function or method has to be declared within a script that is attached as a component to an active game object of the unity scene. In my case, I named the GameObject “LogicController” and attached the C#-script “MainScript” to it. Within “MainScript” I have a method that is called “initItems”. So I want to call this method from within the flash movie and pass along a few parameters also.

The way to do it is to pass
- the name of the GameObject that the Unity-Script is attached to,
- the name of the method within this script,
- the (optional) parameter(s) that I want to send along
to the sendMessage()-function of the ActionScript unity object.

As this sendMessage()-function can only take 1 parameter for the called method (a string, int or number), two or more parameters have to be combined into a single string beforehand (in this example separated by a comma, but other delimiters also work):

var params:String = artikelNr + "," + drehung+ "," + posX + ....;
unityObject.sendMessage("LogicController", "initItems", params);

The unity part
My C#-method “initItems” looks like this:

public void initItems (string params) {
    // all parameters are encapsulated in a single string (comma delimited)
    string[] parameterArray = params.Split(',');
    // the resulting elements in the parameterArray are also strings
    // so we convert them (if needed) to numeric types:
    int artikelNr = Convert.ToInt64(parameterArray[0]);
    int drehung = Convert.ToInt32(parameterArray[1]);
    float posX = (float)Convert.ToDouble(parameterArray[2]);
    ...
}

That’s all there’s to say regarding the communication from flash to unity. The other way round is just as easy:

Step 6 – Unity talking to Flash

communication unity to flash

The unity part
From within the unity script the “Application.ExternalCall”-function is used to send messages to flash. This function takes 2 parameters: the first has to be the string “uniTool.unity_messageHandler”. That is the name of the corresponding JavaScript-function in uniTool.js. The second parameter is also a string that has two parts, separated by the pipe symbol | (press alt-7 on the Apple keyboard or AltGr-< on a Windows machine). The first part, before the pipe, contains the ActionScript-function name (in my example “rotateItem”), the second part contains the parameter(s) passed to the function. Even if the function doesn’t take any parameters, this part should not be empty – just pass a dummy parameter like “ok”.

Application.ExternalCall( "uniTool.unity_messageHandler", "rotateItem|12" );

The flash part
As soon as the message is sent to flash from uniTool.js, an event listener is triggered:

UniTool.addEventListener(UniToolMessageEvent.MESSAGE_RECEIVED, messageFromUnity);

The function called by this event listener (in my example “messageFromUnity”) has access to both parts of the message using the event.msgHeader and event-msgBody-properties to extract the contents and deal with them accordingly:

private function messageFromUnity(event:UniToolMessageEvent):void {
    trace("Message-Header " + event.msgHeader);
    // the msgHeader is the string before the pipe symbol,
    // "rotateItem" in my example
    trace("Message-Body " + event.msgBody);
    // the msgBody is the string after the pipe symbol,
    // "12" (as a string, not a number) in my example
    ...
}

So that’s it for now – uniTool enables a flawless and platform-/browser-independent flash-unity-communication. Unity did announce in February 2011 that they are working on a direct flash-export option for Unity. With that a Unity scene can be exported as a swf-file, and all the communication can take place using ActionScript. This will make the installation of the unity webplayer obsolete for projects such as mine. Looking forward to trying it…

Veröffentlicht in English, Flash, Unity | 6 Kommentare »

6 Antworten

  1. john schreibt:

    Hi, good tutorial;

    i was wondering would it be possible to have unity load up the webplayer like normal but then just have the html talk to unity. You see i don’t want to make a flash application but i do want to access the flash microphhone from there plugin to record and play sounds. Unity does not have this functionality.

    So could i get the main html talking to unitool, flash pluigin and recieving button input from Unity?

  2. jbaurgmbh schreibt:

    Hi John,

    yes, you can load/show unity content from HTML by just using the uniTool-JavaScript API like this:

    var unity = uniTool.embedUnity(“example.unity3d”, “unityContainer”, 800, 500);

    But in order to use the microphone via flash, you will need to embed a flash movie in your html also.
    You can then talk to both the unity and the flash content from html via javascript. Is this what you have in mind?

    Joachim

  3. Duncan Hall schreibt:

    Hi Joachim,

    thanks for writing such an extensive introduction to UniTool! I really should have got round to doing this myself by now but I’ve just been too busy with other things. It looks like you’re getting some good use from it and you’ve really covered a lot here, so hopefully others will too.

    I definitely need to pour some more attention into this, especially updating the example files and including the Google Chrome fix you mention above (thanks for that).

    I’ll let you know as their are any updates.

    Thanks

    Duncan

  4. Adriana schreibt:

    thanks for share!

  5. Gizem schreibt:

    I have been attending The HTML 5 Game Summits up in the Bay Area and at least for the next few years, Flash is going to be a main stay for Desktop Web Games. The HTML CSS JavaScript opiotn is really 2-4 years behind flash 10 player. But an very important point. People by far, do not play flash games on there mobile phones or pads. Its a Horrid experience (I have tried). Apple and Android have them trained to always buy or try games that are native. That means AIR or publishing Flash to the native format (Just like Unity).But I do really wonder about commercial sites and flash. Many of the larger sites have been making 2 versions of there sites for the last 2 years (Iphone/Mobile Phone) and one for home PC users. So Is this really going to change the current trend? Your company makes fantastic user experiences for both Flash and non flash sites and as you know Mobile Sites do NOT look like Desktop sites. So Is things really going to change that fast? I have android phone and Flash sites look just bad on them. I really want them to look good but there not designed for the small screen, so they just look bad.So Is it going to kill the market all at once? Do not know. But Games will stick around till someone makes a great easy to develop tool to make kick ass games in the 3 to 9 months time frame that flash can. I do not see that happening tomorrow as the browsers are fighting over what forms of CSS / HTML / JavaScript to use.Heck were going back to 2001 but no flash or shockwave this time. What a &*(^(& world.PS> I am busy studying up on Unity JQuery and CSS. With a friend like Adobe, it never hurts to buddy up with all the other people in the room.

  6. Ramiro schreibt:

    I have tested Duncan Hall´s example and it doesn´t work, but in your website I have seen that it works. I have followed your instructions and I have not been able to make it work. I just want embed a unity file (probably with a button to load or unload) but no more intercomunication. Could you help me? I have seen in the OUTFLEXX-Loungeplaner that it works.
    Thank you in advance,
    Ramiro Martinez,
    Madrid, Spain.
    Ich sollte in korrektem Deutsch den Kommentar geschrieben haben, aber mein Deutsch ist nich gut genug.

Kommentar verfassen

Achtung: Die Kommentare werden moderiert und erscheinen deshalb nicht sofort im Blog!