Resn has just released their latest web browser and iPad experience, created with CLM BBDO for EDF, Official Partner of the 2012 London Olympics, ‘The EDF Light Games’, a series of 7 online sports games.

Accompanying the desktop browser experience  is a version of the Kayaking event created exclusively for the iPad. Using the brand new Adobe Air 3.2, Resn was able to port the unique light based visuals, built atop Flash and Stage3D, straight to the iPad – taking the game to a new stupendous level of handheld, accelerometer imbued, retina delight.


Porting Stage3D flash project to iOS
We were really excited that it was finally time for us to take our sexy 3D flash content to the iOS mobile platform utilizing raw machine power. Access to Stage3D can give a major performance boost, if you know how to use it. It’s a different architecture, it takes quite a bit of research to know which parts perform better and where the bottlenecks are.
We decided to use latest Adobe Air SDK with Away3D framework.


Away3D on iPad
The latest version of Away3D is fast, really fast; but it’s not without limitations and this is especially true on the iPad. The biggest drain on performance is largely due to the number of elements on any given scene. The best approach to reduce this load is to merge all similar elements into one unified mesh. In the case of our Kayak Light game, the water element consisted of thousands of individual 3D planes, our solution was to merge the elements into huge single chunks (instead of having 2000 single water light trails merging them into a single piece, one per wavebank section). The result was a massive performance boost.

var merge:Merge = new Merge(true, true);
var waves:Mesh = merge.applyToContainer(wavesContainer, "waves");

The main limitation to this approach is the need to use the same material for all the meshes.

You can use any type of objects and textures but they all will use the same material after the merge. A good way to go past this limitation is to put multiple materials on big texture maps and then scroll and crop object UVs. Since the UV data is stored with the geometry, it allows the use of different parts of the texture for various meshes, acting like separate materials after the merge.


At Resn we primarily use PCs for development so in planning iOS development we were a bit worried that we need to buy 15 new MacBooks. Fortunately, you can create and debug applications for iPhones, iPads and iPods purely on PC. (There is a small exception though, but more about that later.)

In order to run Away3D 4 with Stage3D make sure you’ve got the latest:

Flex SDK
IDE of your choice (we used FlashDevelop)
iTunes (for copying files over)

Most of the IDEs come with handy templates that make the setup really easy.


We’ve encountered a few problems trying to run Away3D 4 on iOS. If your application crashes,
is really slow or the 3D layer is empty, or doesn’t render anything try this.

scene3d ios error fix:

1. make sure that compile settings contain:


2. in application descriptor (application.xml) enable depthAndStencil:


3. In prefill beffer dimensions and make sure depthAndStencil is enabled as well:

private var _backBufferWidth : int = 640;
private var _backBufferHeight : int = 480;
private var _enableDepthAndStencil : Boolean = true;


Handy iTunes hack
There’s a small annoyance with iTunes test deployment. Every time you copy an *.ipa app, iTunes checks the version number assigned to it. If the version is unchanged, even though the file has been recompiled, iTunes won’t update it. You can manually remove and add the app every time but it gets boring really fast.
Here is a handy VBS script that updates the app version number during every compile, making sure that every release has it’s own version number.


Dim sFSpec : sFSpec  = ".\application.xml" 
Dim oFS    : Set oFS = CreateObject( "Scripting.FileSystemObject" ) 
Dim oRE    : Set oRE = New RegExp 
oRE.Multiline = True 
oRE.Pattern   = "^(  )([-+]?[0-9]*\.?[0-9]*)(\s*)"  
Dim sTxt 
sTxt = oFS.OpenTextFile( sFSpec ).ReadAll() 
sTxt = oRE.Replace( sTxt, GetRef( "replTims1" ) ) 
oFS.CreateTextFile( sFSpec, True ).Write sTxt 
WScript.Quit 0 
Function replTims1( sMatch, sCapture0, sDigit, sCapture2, nPos, sSource ) 
   Dim nDigit : nDigit = CByte( sDigit ) 
   nDigit = nDigit + 1 
   replTims1 = sCapture0 &amp; nDigit &amp; sCapture2 
End Function


AppStore deployment
In order to deploy to AppStore you have to use an Apple computer (or MacOS on a Virtual Machine). Even though you can create, code and debug fully working iOS app on any platform, you still have to use the XCode Application Loader to deliver it to Apple.



Our deadline was near, so we had to come up with an easy (fast) way to store the leaderboards. Adobe Air lets you store and access external content in a few ways. You can connect to a web server, and read / write data, but it works only if the user is online. You can generate a text file and store it on the device.
But then we remembered SharedObjects (“Flash Cookies”). It’s by far the simplest solution, and works perfectly on iOS.

Anyway, for the future release we’re looking into using full GameCenter functionality using NativeExtensions.


Language detection

Another small challenge was a language detection. And again, it turned out to be pretty straight forward:

var languageSettings:Array = Capabilities.languages;
var locale:String = languageSettings[0].toString().toLowerCase();

This code detects your device language. We’re using two sets of assets, if your main language is French, the game automatically uses French version, for any other language it runs in English.

One thing to remember, in the application descriptor (application.xml) make sure to specify all, and only the languages your app is using:

<supportedLanguages>en fr</supportedLanguages>

otherwise, compiled app submitted to AppStore will list all of them:


iPad gameplay

All the menus are just movieclips and buttons, porting this part was the easiest part. Since you don’t have mouse, there’s no need for rollovers. When user taps a button, rollover and click events are basically called simultaneously. In order to indicate pressed state, for buttons we used only the down frame.

We’re using the accelerometer for the game input. It’s a simple system, with all the classes integrated in the SDK. In order to test the game you can either use the emulator or write an alternative mouse test input for it. In this case, whenever accelerometer is not available mouse position is used instead. It makes testing way faster and user friendly (developer friendly?).

private function initAccelerometer():void {
   var accelerometer:Accelerometer = new Accelerometer();
   if (Accelerometer.isSupported) {
      accelerometer.addEventListener(AccelerometerEvent.UPDATE, updateHandler);
   } else {
      addEventListener(Event.ENTER_FRAME, panSceneWithMouse);
private function updateHandler(e : AccelerometerEvent) : void {
   pan(-e.accelerationX, e.accelerationY);
private function panSceneWithMouse(e : Event) : void {
   var forceX : Number = 2 * (mouseX / stage.stageWidth - .5);
   var forceY : Number = 2 * (mouseY / stage.stageHeight - .5);
   pan(forceX, -forceY);
private function pan(forceX:Number, forceY:Number):void {
   trace(forceX, forceY);


Wrap up

And that’d be all. Overall, it was a straight forward, enjoyable project, which went way smoother than expected.

And here’s that link again: