Lighter Than AIR: Making Better Games with Adobe AIR*

By Amos Laber

For developers of mobile games, these are exciting times. The arrival of new mobile hardware platforms and the rise of social gaming attract a lot of business and create new opportunities for independent and small developers as budgets increase and funds are flowing into the games sector.

Download Article

Download Lighter Than AIR: Making Better Games with Adobe AIR* [PDF 605KB]


Considering Adobe AIR* as a Game Development Platform

Netbooks, with their smaller form factor, are a good starting point for targeting mobile games: You want to choose a development platform that is easy to pick up or one that you're already familiar with. You want to be able to easily port the game to other mobile platforms, like smart phones, tablet computers, and touch devices.

Adobe AIR*, with its cross-platform deployment, is exactly that. It is based on the familiar Adobe Flash* platform and uses Adobe ActionScript* 3 (Adobe* AS3) as its programming language. The AS3 language has a standardized ECMAScript syntax that is similar to Java* and Microsoft* C#. With its familiar concepts, it is easy to pick up.

Building on the success of Flash animation in Web games, AIR brings Flash into native operating systems like Microsoft Windows*, Mac OS* X, and Google Android* and adds features like networking and file system access. AIR 2.0 and Adobe Flash Player* 10.1 offer good performance on mobile devices and provide added support for multitouch, gestures, and local microphone. Consistent delivery means that the game will run the same way on every platform and require only minimal modifications, like screen resolution. AIR shapes up as the ideal software platform when targeting netbooks for a mobile game.

Getting Started

Before you start coding, you need to decide on the overall architecture of your game-which libraries you'll use and, most important, which framework to choose. A good framework should give you the freedom to work on the heart of your game logic while taking care of most of the boilerplate code. It can also provide structure to the game modules and supply common patterns. A framework isn't a game engine, though: It only deals with limited functionality. You still need to write most of the code.

Several different types of frameworks are out there, including user interface (UI) frameworks like Adobe Flex* and Model-View-Controller-Services (MVCS) frameworks such as Swiz and Robotlegs. But I prefer to build my own framework based on a previous game or from open source examples. At a minimum, a game framework should have:

  • state and screen management;
  • an initialize phase;
  • a start level;
  • game loop/update;
  • game over (an end level); and
  • a keyboard listener (optional).

With these elements, you'll be able to set up an empty shell with a minimal game menu and a few screens. That should be a good starting point and a base on which to build.


Game Engines and Libraries
Using a game engine for a game project has its advantages, but it's certainly not required. That said, it's a good idea to familiarize yourself with few of the popular game engines. There is a lot to learn from the source code, and you can use parts as a reference when writing your own code.

Several AS3 open source engines are available, and choosing one of them really comes down to personal preference. The engine should speed up development and be flexible and easy to use while at the same time allowing you to extend its features. Popular engines include:

Some engines offer a complete framework and features, while others are simply a collection of utility classes. Typically, engines fall into one of several categories: 2D, ISO, 3D, physics, social, or any combination of these. Check out the list of game engines on FlashRealtime.com.

In addition, a few libraries offer some utility classes or a single functionality:

  • AS3DS. Data structures for games, with high-performance implantations for different data structures
  • Greensock TweenLite* and TweenMax*. Motion tweeners for effects and pre-scripted motion
  • Box2D and QuickBox2D. A fast and powerful physics engine

Project Setup

With your choices for form factor and framework made, you can start setting up your project.


Environment
Adobe provides two commercial integrated development environments (IDEs) that you can use to develop AIR applications. Adobe Flash* Pro (in Adobe Creative Suite* 4 and Adobe Creative Suite* 5) is the classic designer's tool. Adobe Flash Builder* 4 is aimed at hard-core coders. Some good third-party IDEs are also available and gaining in popularity, including:

It is also possible to use a text editor and a command line-the old fashioned way. However, doing so requires more time and effort.

For the sake of simplicity, I focus on Flash Builder 4. If you use any of the other tools, please consult the documentation for your specific environment. Regardless of the environment, however, you need to install the AIR 2 software development kit (SDK). Because it is included in the Flex SDK distribution, I recommend downloading the latest Flex SDK (Flex 4.1 and later).


Create an Adobe AIR* Project
In Adobe Flash Builder 4, first make sure Flex 4.1 is installed as the default SDK by clicking Windows > Preferences, and then expanding Flash Builder\Installed Flex SDKs, as Figure 1 shows.

Figure 1. Setting Adobe Flex* 4.1 as your default SDK


Next, create a Pure AS3 project for AIR. There is no template for that, so perform the following steps:

  1. Click New Flex project.
  2. Choose the application type Desktop - runs in AIR. Give project a name, and then click Next.
  3. Leave the output folder as is, and then click Next.
  4. In the Main application file text field, change the file extension from .mxml file to .as.
  5. Click Finish.


Build and Deploy

A successful build results in an SWF file and an XML descriptor in the bin folder. Deployment packages all the files in the bin folder into a single downloadable file. AIR 2.0 lets you choose between AIR format and native: Native creates an .exe file for Windows, a .dmg file for Mac OS X, and an .apk file for Android (AIR 2.5 only).

Click File > Export > Release build, and then choose the format. Doing so generates the packaged file, which is now ready to be deployed on the target machine.

Writing Efficient High-performance Code

When you're developing a game for a mobile platform, you want it to be efficient so that it looks as good as possible. After all-the more efficient your game, the more features you can enable.


Simpler Is Better
As in all development platforms, any coding you do in AIR and ActionScript should be done with design and architecture in mind. The goal should be creating high-quality, reusable code that is both robust and clear. All the methodologies from other languages like C++ or Java are applicable here-object-oriented design, design patterns, performance, and memory considerations.

One fundamental rule that applies here is to keep it simple. Simple and clean design translates to solid code that is manageable and easy to understand. I have seen many projects drowned to death by bugs, mainly because of poor-quality code that made them nearly impossible to maintain. Typically, there was no reason for the over-complicated design (or sometimes no design at all) other than bad judgment and lack of oversight.


Understanding Adobe Flash* Player
Adobe AIR is basically an extension of Adobe Flash Player. AIR 2.0 uses the Flash Player 10.1 code to load and execute SWF byte code, with the help of Adobe Virtual Machine* version 2 (AVM2). Although the specifics of the AVM2 are out of scope of this article, it is important to keep in mind that your game code is executed in a VM and converted to native platform code using a just-in-time compiler.

Flash Player uses a familiar model of frame cycles: a loop in which each frame is processed, and then rendered to the screen in sequence (see Figure 2). Running on a single thread, the frame execution model divides the frame time slice into two distinct sections, one for user code execution and one for rendering content to screen (I ignore the green part for simplicity). The player tries to balance the two in a model that is often referred to as the elastic racetrack.

Figure 2. The Adobe Flash* Player frame cycle model



Resource Management

Developers sometimes overlook management of resources like RAM and CPU, but when targeting mobile devices, this management becomes essential. Badly written games can hog the CPU, leak memory, and eventually cause the operating system to crash. This is certainly true with any development environment, but in Flash and AIR, it is particularly apparent. Be very careful with your use of system resources.

Objects in memory are garbage collected. Pre-AIR 2.0 versions suffered from severe fragmentation, so be aware that AIR 2.0 has improved and more efficient memory handling. All common coding practices apply here: Don't leave any objects behind (especially class members). Because classes don't have destructors, create a dispose function in any of your classes that would null out all references and release allocated objects. Any loaded media assets like bitmaps or video should be released by the same entity that loaded them.

Display objects consume most of the memory, so use a profiler or system tools to monitor your memory usage during development. Just because you can't see it doesn't mean it's not there: Removing display objects from the display list, hiding them, or setting alpha to 0 does not release them from memory. Like any other object, they will only be collected (and deleted) if not referenced by other objects.


Timers and Frame Operations
The timer class (flash.util.Timer) lets you execute any code repeatedly over specific time intervals. In games, this kind of functionality is often needed. Sometimes, you need to make a delayed call to sequence some specific event. Flash coders often ask, what's the best way to use timers? My answer is simple: Don't use them-ever.

Besides the fact that timers are inaccurate and not terribly easy to use, they have a certain overhead that can add up and slow down performance. Timers are resource hogs: The more timer instances linger in the system, the more you can expect slow and choppy gameplay. Timers eat up memory and clog the processor, crippling the performance of your game.

As an alternative, simply use the game loop for frame-based operations. Simply register a function to ENTER_FRAME event on the stage so it is triggered on every frame. One word of warning, however: ENTER_FRAME is a system event, so to minimize impact, use it sparsely. Although you can register listeners for the ENTER_FRAME event with multiple display objects, it's best to use it just for one object (your main game class) and have a single, centralized enter frame handler make all the subsequent calls to game objects.

Regarding sequencing or delayed calls, it's best to use a utility like a tweener. I use TweenMax and its delayedCall() method to make delayed calls with ease and zero overhead.


Rethinking Events
The AS3 event model is based on a concept of object dispatching. Although this model is suitable for static Web apps, this is not the case when targeting netbooks to run a game fast and smoothly. From the viewpoint of a mobile developer, the Flash event/listener model is a weak point in the runtime environment. Most Flash coders tolerate it, but you don't have to. I'll show a few good alternatives.

So, why not use native Flash events? Every time dispatchEvent() is called, it makes a copy (or a clone) of the event object. When this happens inside the game loop, you get lots of small memory allocations every frame-a sure way to cause choppy run. From my days writing console games in C++, I was taught to avoid this scenario. This caution applies in magnitudes in a garbage-collected environment like AIR or Flash Player.

Here's a partial list of problems in the Flash event model:

  • Custom events require new classes.
  • Event objects must be created and allocated in memory-a costly operation that causes a performance slowdown.
  • Registering for an event via addEventListener leaves a reference to the listener object that is not automatically released.
  • It does not compare well to modern event models, such as C# events.

Because your game needs to run on mobile devices with high performance and efficient memory usage, I strongly suggest considering an alternative. This is only true for custom events: On display objects, you may still need to use Flash events for mouse, keyboard, or enter frame, but you can keep these to a minimum.


Signals
AS3 Signals is a new library, written by Robert Penner, that is gaining popularity among Flash and Flex developers. Signals are made to be lightweight, so they are much faster and easier to use than native Flash events. For a mobile game, they offer a convenient and low-impact alternative to events.


Callbacks
An even simpler way to go is to use callback functions. Most games rarely need real events (or the overhead associated with them). Callbacks may not be very elegant in terms of design pattern, but they are the fastest in execution and very light.

For example, a simple one-to-one callback can be a public member in an object of type Function, so a single listener can be assigned. If object A needs to receive an event for object B in the native model, it would use the following:

B:

A.addEventListener(Event.COMPLETE, onCompleteHandler);
...
private function onCompleteHandler(e:Event) 
{
    // handle the event
}

A:

dispatchEvent(new Event( Event.COMPLETE) );



With a callback, it would use:

B:

A.onComplete = this.onCompleteHandler; // set the callback

A:

public var  onComplete:Function;
...
If (onComplete != null) {
     onComplete();  // fire the event
}

Providing a clear advantage for a game targeted at mobile devices, callbacks use zero memory allocations at the time of dispatch and are easy to clean up. Just be sure to use normal functions as handlers and avoid passing anonymous functions (a.k.a., closures), as they are slow.


Memory and Garbage Collection
A good way to optimize memory usage is to reuse objects and avoid reallocating them within the game loop. Allocating a new object is a slow operation on any platform; however, on a netbook, the impact would be most noticeable.

AIR is a garbage-collected environment. The garbage collector uses a mark-and-sweep method. When an object is no longer in use, it will be collected, and then deleted, with its memory released to the main pool. This is done behind the scenes and typically cannot be controlled. However, this caveat has recently changed, and in AIR, you can invoke garbage collection directly using the System.gc() function.

The decision of when and where to allocate and release memory (with the garbage collector) should take into account that allocation is one of the more costly operations. Removing a large number of collected objects can be CPU intensive and slow down the player, so avoid massive cleanups if possible, or at least try to divide them between multiple frames. On a platform like a netbook, the game would benefit from timing the garbage collector to work during non-gameplay activity (e.g., pause, main menu, or between levels) so that the lapse will not be noticeable.

Conclusion

Adobe AIR 2.0 offers an ideal solution for creating mobile games for a netbook or mobile device. Because of the nature of the hardware, a mobile platform is much more sensitive to memory and CPU usage, so to ensure that these elements are used effectively, the game code should be robust and efficient. Sticking with common best practices is essential for achieving high performance for your game.

Getting to know the Flash platform and avoid its pitfalls is an important step in writing efficient code. Proper handling of memory, events, assets, and display objects helps create a solid foundation for any game code.

Resources

About the Author

Amos Laber is an experienced game programmer and architect. He specializes in cross platform development and performance optimization for games, and has a background in 3D rendering, character animation and visual simulations. Over the last decade he was involved in several game projects, ranging from AAA console titles like Activision's "Marvel: Ultimate Alliance 2" to the casual space with online social games.

For more complete information about compiler optimizations, see our Optimization Notice.