I’ve been working with Flash on the iPhone for a few months now, and although I’ve successfully released a game on the App Store (check out The Hypnotist), I’ve spent most of my time experimenting and trying to discover ways of optimising code and working out just how to get the best performance out of the device with the Flash platform.
There are a lot of great tutorials out there specifying how to get the best performance out of Flash on mobile devices (and in general). Many of them talk about the subtlties of structuring your code, and some of these do have tremendous impact, however I’ve always found that the graphics are the true bottleneck for me (and collision detection – but that’s for another day).
The key generally comes down to blitting. For those who don’t know, blitting can be very simply described as the act of copy and pasting flat pixels, rather than relying on multilayerd movieclips with vectors and tweening etc. for your animation. The thing that I’ve discovered is that it’s faster to use a hybrid blit technique on the iphone than to go the traditional way.
To explain, traditional blitting would copy the pixels for every object and sprite directly onto a single bitmap canvas, however the best performance I’ve found comes from blitting to individual Bitmap objects on the screen. In one sense that’s quite handy as it means we can still work in the mind set of having separate display objects that we can position independently, on the other hand it worries me a bit because it feels like there’s something not quite right going on for that to be faster than using the one single bitmap canvas.
So the following results are based on this hybrid blit/display object technique. But there is one other little difference that I’ve seen increase performance considerably… and again it’s a departure from the standard blitting operation that can only be done with this hybrid technique. And that’s not to blit at all!
Let me explain – Blitting usually utilises a single sprite sheet to contain all of the frames of your animation, you then copy the pixels from that sheet for the particular frame as it’s being rendered, pasting them to the display, and so on as the animation cycle continues.
My approach is different, it splits the sprite sheet up into individual bitmapData objects, one for each frame, at the beginning of the program and stores them in an array. Then to render the animation, you don’t use copyPixels to blit, instead you set the bitmapData property of your sprite’s Bitmap to the appropriate bitmapData frame. Hence copyPixels never gets used – instead you’re swapping bitmapData objects. So I guess at the end of the day, this is a non-blit bitmap technique.
The real world results
Based on the above bitmapData Swap technique, the following results were recorded (compiling with Flex 18.104.22.16828 and Air Beta 3.0 with an app resolution of 480×320)
Sprite size: 40×40 pixels
Sprite frame count:100 frames
- 25 Sprites: 60fps
- 50 Sprites: 52 fps
- 70 Sprites: 40 fps
- 100 Sprites: 30fps
Notes about the iPhone’s memory
For these results I was actually using an iPod touch (4th gen) which is listed as having 256MB Ram and runs at 800khz. One very useful guideline I formulated whilst doing this experimentation is a rough approximation of the amount of image data that the device can hold in memory at an one time, and that is 25 mega pixels, or 25,000,000 pixels worth of data.
For instance, if you are working at a screen res of 480×320 that would equate to 153,600 pixels worth of data – so in that case you could hold around 150 frames of animation at that full screen resolution. To put it another way, the iPhone memory could cope with @ 2,500 frames of animation at 100×100 pixels.
Bare in mind that this doesn’t reflect any intimate knowledge of the device or it’s physical specs, but is just a real world observation, and should be a handy benchmark for you to use when determining how much room you have to work with. The key indicator that you’re using too much memory seems to be a black screen of death on the device that will shut down your app and return you to the springboard.
Can you do any better?
The main reason for posting this info is that I’ve been searching online to see the best performance people have been able to achieve and am really just keen to find out what’s yielding best results for everyone out there. So in the interests of pushing the limits and spreading the knowledge please post alternative approaches that might be producing faster results. At the end of the day we shouldn’t be struggling against the technology just to get suitable performance, I’d much rather be focusing on building the content and bringing ideas to life.
I’ve looked around the web for information on measurable performance specs for Corona, if there’s anyone out there that can post a comparison it would be very interensting to see. This might be the topic for a future post.