Skip to content

Resource Handling in Flash – Part Two

June 14, 2010

In the last post I showed two approaches to access resources such as sound or image data in Flash. To make resources available to your application you can either load resources one-by-one on demand or embed them all into the main SWF file so they are available as soon as the application has loaded. Both variants however have limitations. So in this post I’m going to show some alternatives.

Drawbacks of loading on demand

  • different types of resources require different code to load.
  • there’s a gap between a resource beeing requested and the time it actually becomes available.
  • if you require multiple resources at once (loading the next level data) you have to open one connection for each resource which means a tremendous overhead.
  • if you’re loading multiple resources you have to keep track of multiple loaders to know your overall progress
  • when a resource fails to load you have to detect and handle it.

Drawbacks of embedding

  • Code and Data are not decoupled: When the assets change you have to change and recompile your code.
  • Workflow issues: How can content creators (artists, level designers) test their work ingame?
  • Transcoding a resource into a flash compatible format is taking time and so for large applications build times explode.
  • It’s likely that more data is pre-loaded than is actually required in a users session. The long initial load time might become a barrier for users and it certainly wastes bandwidth.

Alternatives

The general approach to overcome these limitations is to decouple your data from your logic but preprocess and package the data into a Flash compatible format so it becomes trivial to join logic and data when needed.

Option #1 – Statically linked SWCs

If you don’t need loading on demand you can create a SWC file containing the resources and link it with your main application. The effect is the same as if you’d have embedded all the files directly but by splitting resources into multiple projects you keep your build times fast. Projectes are re-compiled seperately and only when needed.

It’s also nice that you can create the SWCs with more artist friendly tools like the Flash IDE. This provides additional benefits like build-in conversion of Sounds from WAV format to flash compatible MP3 encoding. I get back to that later.

To link a SWC in Flex/Flash Builder you select Project->Properties and click the “Add SWC” button in the ActionScript Build Path category to select and add the SWC containing the resources.

Now the resources are available at compile time by their class-names just like if you embedded them using the Embed-Tag.

For example in the “sounds.swc” I have  a number of embedded asset classes for sound effects. They have names like “firefly_flee” or “music_title_screen” and extend the Sound class. To play “firefly_flee” I just have to instantiate it and call the play() method:

var sound:Sound = new firefly_flee();
sound.play();

Option #2 – Dynamically load and link SWFs

In Option #1 you still have to recompile your main appliciation whenever a resource pack has changed and every linked resource will get pre-loaded whether you’ll need it or not. Alternatively you can package the resources in a SWF instead of a SWC and load it on demand. To load a SWF use a Loader class.

function load():void
{
    var loader:Loader = new Loader();
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaded);
    var urlReq:URLRequest = new URLRequest("sounds.swf");
    loader.load(urlReq);
}

When onLoaded is called the SWF has been loaded including all the embedded Resources. But how to access them? The SWF contains a specifically named class for each resource. You might know their names but since the classes weren’t present at compile time you couldn’t write any code using them. So before you can use the resource class to create an instance of the resource we have to retrieve that class by its name.

public function onLoaded(event:Event):void
{
    var info:LoaderInfo = event.currentTarget as LoaderInfo;
    var soundClass:Class = info.applicationDomain.getDefinition("firefly_flee") as Class;
    var sound:Sound = new sndClass;
    sound.play();
}

An ApplicationDomain is a container for AS3 definitions and if not specified otherwise each loader will create it’s own applicationDomain where it adds all the definitions that are part of the loaded SWF. Of course you wouldn’t want to play a sound right in an event handler. Instead just load the SWF once and then store a pointer to the applicationDomain and call getDefinition on it whenever you need a class.

Now a smart question to ask would be: Why do I have to load the classes into a new ApplicationDomain and keep a pointer to it? Can’t I just add all the definitions to where my other classes are stored?

Yes you can. Just provide a LoaderContext when requesting to load the SWF and in that LoaderContext you can specify in what AppDomain you want the definitions to end up.

loader.load(urlReq, new LoaderContext(false, ApplicationDomain.currentDomain));

Now whenever you want to reference a resource you can get the resource class  by calling getDefinition on the ApplicationDomain.currentDomain.

But a word of caution: You have to make sure that there are no naming collisions. Classes that allready exist in the currentDomain will not be replaced by a definition of the same name in the newly loaded SWF. And classes once added the main SWFs AppDomain can’t be removed. If you want to be able to unload dynamically loaded resources you have to keep them in different AppDomains.

If you want to learn more about Application Domains read this excellent post.

Options #3 – Use Flex Modules

Last option combines the benefits of both: Using Modules. The basic idea is that you know all the classes at compile time so you can code against them but then you don’t link them into your main SWF but into seperate SWFs that get loaded dynamically on demand or when you request it using the ModuleManager singleton. The drawback? This technology is part of the Flex framework and Flex applications are typically bigger then pure ActionScript applications. But if you are going with Flex anyone check it out!

Creating Resource Projects

While you can create resource projects in Flash Builder the Flash IDE is a better suited for that. Adding resources to the Library using drag & drop and getting a preview is handy.
Right click -> Linkage... and you can mark that file to be exported for ActionScript.

The class name can be edited to your liking. To generate a SWF just publish the file. If you want to generate a SWC for static linking with your main application check the Export SCW option in the Publish Settings Dialog.

The main reason for using the Flash IDE however is that it allows you to embedd files that would otherwise not be embeddable.

Most notably: Flash will encode WAV files as Mp3 for you. Details like encoding quality can be specified in the Publish Settings Dialog. But in any case Flash will create “loopable” Mp3’s that don’t suffer from the infamous gaps at the start and finish of the sound.

Another neat features: When you embedd images you can chose to JPEG-compress them and even specify the quality. Even PNGs with trancparency can have their RGB channels JPEG compressed which can reduce the memory-footprint considerably.

A completely different approach to genereating resource packs is to use some custom automated process. For example you could write a Level-Editor in a langauge like C# but export the levels as a ready-to-load SWF file by generating appropriate source files and feeding them to the Flex commandline compiler.

Advertisements

From → Tutorials

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: