Skip to content

An asset pipeline in Flash. How we do it!

by pixelpracht on Mai 31st, 2011
Here’s a real-world example of how we handle the assets in our current flash game project at my company. It’s a rather big browser game that uses several megabytes of resources (XML meta-data, PNG & JPEG Images, Sounds and Movieclips) that we have to deploy to the serves and load into the client when needed. In such a scenario managing the dependancies between the code and the assets can be quite challenging and timeconsuming.
This post is a little advanced and you should be allready familiar with embedding and dynamically loading resources in Flash.

The Challenge

The content creators create assets file by file and save them to a folder structure. Thanks to the magics of version control systems (SVN in our case) these ever growing amount of assets is synced between all collaborators. But someone has to make sure everything is available at runtime when the application needs it.
To embedd all resources using the [Embed] tag in the game’s source code would cause several problems: The size of the SWF would be huge as all assets that are potentially needed would have to be included. Each embedded resource has to be added when you build your project so compile times would explode. And as we’re using FlashBuilder we would have to write some lines of code for each embedd asset. But who’s going to maintain that? Gamedesigners and artists change, add and delete files to the repository but they don’t have the means (and inclination) to edit source code, so who’s keeping it synced?
A contrary approach is to put all resource files on server and load them at run time. But different types of resources require different code to load, if you require many resources at once you have to open one connection for each resource (adding a lot of overhead) and you have to keep track of multiple loaders. Lastly many resource files are compressed efficiently when embedded into a SWF and it’s sad to miss out on that kind of optimization.

Our Solution

So we’ve decided to setup an asset pipeline that converts our assets into a format that is more optimized to the needs of the runtime environment. Such a system is a common thing in “real” game development but unusual for flash game development – maybe because traditionally Flash applications are authored in an IDE that has build in functionality for asset management.
Flash Builder doesn’t have anything like that but luckily it’s based on Eclipse, a software development environment with an extensible plugin system. One plugin (part of the “Eclipse Java Development Tools”) adds support for “Apache Ant” build scripts to Flash Builder. Ant is a tool for automating software build processes. What to build with it? SWF’s that contain only assets as embedded resources, get uploaded to the server alongside our game SWF and when resource are needed the appropriate resource-packs are loaded at runtime to make the embedded assets available to Flash.
But our Ant script does a lot more then just invoke a compiler to build some AS3 files. It also generates these files on the fly. So the manual work required to embedd all our assets into some dozens of resource packs reduces to clicking a button.

The Details

So, what happens when we click?
  1. The Script will go to the root directory where our assets are stored and browse the subdirectories recursively. Finally when a directory is reached that contains files a resource pack is created.
  2. To do that we first generate create a temporary AS3 source file. We just concatenate templates that contain a mix of actual source code and temporary portions of text, marked with @-symbols, that are replaced by the Ant script when it builds the source file.
    First we include the header…
    package @PACKAGE@
    {
      import flash.display.Sprite;
      public class @PACK_NAME@ extends Sprite
      {
    …then we add souce code for each asset in the folder based on it’s file extension…
    [Embed(source="@ASSET_PATH@/@ASSET_NAME@.@ASSET_EXTENSION@", mimeType="image/png", compression="true", quality="@IMAGE_COMPRESSION@")]
    public static var @ASSET_NAME@:Class;
  3. …finally we add a footer to close the class and package declartion.
  4. }
    }
  5. Now we kindly ask the mxmlc compiler to compile the generated class into a SWF. The Flex SDK contains Ant tasks for that purpose so it’s pretty easy to invoke the mxmlc compiler from an Ant script.
    <mxmlc file="${src.dir}/${src.classesDir}/${lib.classNamePrefix}.as" output="${lib.outputPath}/${lib.classNamePrefix}.swf">
    	<source-path path-element="${src.dir}"/>
    	<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
    	<source-path path-element="${FLEX_HOME}/frameworks"/>
    	<compiler.debug>false</compiler.debug>
    </mxmlc>
    1. We also copy a manifest XML that describes game objects and links them with certain embedded Resources in the ResourcePacks we generated.
      A gameobject’s definition might look like this: 

      There’s one special manifest that tells our application what other manifests to load and where to look for the resource packs. When a player starts the game this main manifest is loaded. Now that we know what resourcepacks and manifests exists on the server we can ask the ResourceManager to load them when neaded.
      <gameobject id="special_exchange" type="building">
      	<occupation>
      		<rect x="0" y="0" width="4" height="5">
      	</occupation>
      	<component id="base" type="object" skin="special_exchange" resourcepack="kingart.resources.images.park.buildings.specials"/>
      	<component id="site" compref="buildinglot_4x5" type="object" skin="buildinglot_4x5" resourcepack="kingart.resources.images.park.buildings.buildinglots"/>
      </gameobject>
    2. The manifests and the compiled SWFs are uploaded to the server.

    I can has Resources, please?

    To get the assets when you need them you have to add code to your main application that will load the resourcepacks and manifests and extract the required resources. Our ResourceManager turned out rather complex but at its core it’s pretty straight-forward. This is how you’d load a XML-based manifest file.
    private function loadManifest (url:String):void
    {
    	var xmlLoader:URLLoader = new URLLoader();
    	xmlLoader.addEventListener(Event.COMPLETE, onManifestLoaded);
    	xmlLoader.load(new URLRequest(url));
    }
     
    private function onManifestLoaded(e:Event):void
    {
    	var xml:XML = new XML(e.target.data);
    	app.processManifest(xml);
    }
    And provided you know the URL to the resource pack an asset can be retrieved like this:
    private function loadAssets(url:String):void
    {
    	var loader:Loader = new Loader();
    	loaders[url] = loader;
    	loader.contentLoaderInfo.addEventListener(Event.INIT, onLoaded);
    	resourcesToLoad[url] = loader;
    	loader.load(new URLRequest(url));
    }
    When the loader completes it contains the class that we generated and compiled with our Ant script. We can look for the embedded resources if we know their name. To access a specific image asset you’d do this:
    var resourcePack:Class = loader.contentLoaderInfo.applicationDomain.getDefinition(resourcePackClassName) as Class;
    var resource:Class = resourcePack[imageName];
    var bitmapData:BitmapData = (new resource() as Bitmap).bitmapData;

    Final Words

    I do realize that (unlike ours) many Flash applications need to be deployable as a single SWF that contains all the code and assets. Also, in smaller projects the effort of setting up system like ours might be bigger then just embedding the assets manually. But for us Ant has made deployment much easier and it allows the coders and artists to work on the same project mostly independ from each other.
    I’d be curios to learn how other developers manage the assets in their projects! Feel free to comment! :)

From → Tutorials

One Comment
  1. really appreciate this write-up. would love to see others’ comment with their own methodologies. : )

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS