When we are doing pure AS3 project especially game, somehow we need to put our game art asset into the game. We can achieve this using either runtime asset loading or embedding asset at compile time. If we are developing under Flash IDE, then embedding asset can be done automatically. Just import the assets to library, and it will be embedded next time you publish your SWF. Even better, Flash IDE has many options to compress the embedded images or resampling audio in the library. However, these options are some reasons why on large size FLA project, Flash IDE publish SWF so slow. Compressing image and resampling audio takes a while, plus Flash IDE compiler is not fast enough.

Some Flashers nowadays prefer to embed asset manually without Flash IDE in order to avoid frustation when publishing swf in a large project, especially when we should test our code a lot. Using Flex Builder/FDT/Flashdevelop for example will fasten compile time, debugging support, and also offer excellent code-hinting. But unfortunately, embedding asset is not as easy as using Flash IDE, now we must write more code to achieve it.

When building large application, it is often beneficial when you split up SWF into smaller pieces, and load it at runtime,  this method is called runtime asset loading, i will not discuss it now. Here i will only write about embedding asset at compile time using pure AS3, i will not discuss embedding asset using MXML tag or using CSS on Flex Framework. For references i am using Moock’s book especially chapter 28 “Loading External Display Assets” on the last part, and also some good articles on the net from fellow AS3 developers.

Basic Embedding

In first method we will use [Embed] metadata supported by mxmlc command-line compiler for embedding asset.  Before using it, i must warn you that using [Embed] will not give you any access to script on embedded SWF like on MovieClip asset. It is ideal for graphical and animated asset but not more, see Adobe Resource Center for more information. As a personal note, i discourage the use of timeline script except for really simple task such as stopping and playing MovieClip.

When using [Embed] metadata, you can assign it in instance-variable definition level or class definition level.

Instance-Variable Definition Level

[Embed (source = "path")]
var ClassWithEmbed:Class;
// compiler will create new Class as embedded asset representation at compile-time, then you can instantiate  new object
var newObject:* = new ClassWithEmbed();

replace “path” with relative path or absolute path.

You may change * datatype with specific Class, but what is the real datatype for embedded asset? AS3 reflection method will tell us:

describeType(newObject).extendsClass

the method will eventually tell you what newObject’s type is actually. If it is bitmap asset it will be a class that extends from mx.core.BitmapAsset. BitmapAsset extends FlexBitmap then extends Bitmap. There is a problem if you wish to create smallest SWF as possible because you just added mx.core Flex Classes which is overkill. You can turn on link-report mxmlc compiler option to see by yourself just how many class definition included when adding Flex Classes. See this useful blog to know more about this. Senocular has tutorial on mxmlc, if you wish to know what options mxmlc compiler has.

Class Definition Level

To avoid problem in instance-variable definition level, we can opt to class definition level. Look at code below, in other word, we extends specific Class for referencing embedded asset. Below we create GIFBitmap Class to extends Bitmap Class since we are embedding .gif image. After that we can use GIFBitmap Class to instantiate new objects.

package
{
    import flash.display.Bitmap;

    [Embed (source = "asset/some.gif")]
    public class GIFBitmap extends Bitmap{}
}

class definition level for embedding asset is a better way to do, since there is a concern on memory leak could happening if you use metadata tag directly on instance-variable level.

AS3 will automatically “know” these types of files:

  • JPG, for class definition level, extends from flash.display.Bitmap
  • GIF, for class definition level, extends from flash.display.Bitmap
  • PNG, for class definition level, extends from flash.display.Bitmap
  • SVG, for class definition level, extends from flash.display.Sprite
  • MP3, for class definition level, extends from flash.media.Sound
  • TTF, there is special case with font embedding
  • SWF, you must use variable-instance level, but for the symbol inside SWF, you can extends from Sprite or MovieClip

Embedding Bitmap

You may embed jpg, png, and gif files without so much hassle. If you use instance-variable method, the resulting class would be from mx.core.BitmapAsset.

// instance-variable level
[Embed (source = "asset/any.png")]
var AssetClass:Class;
// intantiation
var temp:* = new AssetClass(); // temp is a class of mx.core.BitmapAsset

Class-definition method is preferable if you want smallest possible SWF size. Your subclass should extends from Bitmap.

// class-definition level
package
{
    import flash.display.Bitmap;

    // extends Bitmap, not mx.core.BitmapAsset
    [Embed (source = "asset/somepng.png")]
    public class PNGBitmap extends Bitmap
    {
        public function PNGBitmap(){}
    }
}

Embedding Sound

You may embed MP3 file. If you use instance-variable method, the resulting class would be from mx.core.SoundAsset.

// instance-variable level
[Embed (source = "asset/any.mp3")]
var AssetClass:Class;
// intantiation
var temp:* = new AssetClass(); // temp is a class of mx.core.SoundAsset
temp.play(); // play the cool sound
// class-definition level
package
{
    import flash.media.Sound;
    // extends Sound
    [Embed (source = "asset/cool.mp3")]
    public class SoundTrack extends Sound
    {
        public function SoundTrack(){}
    }
}

// try to instantiate it
var sound:flash.media.sound = new SoundTrack();
sound.play();

Embedding Old Swf (targeting below Flash Player 9)

When you are developing newer swf targeting Flash Player 9 and later, it is better that you use SWC Embedding method, since IDE such as FlashDevelop or Flex/Flash builder can see through the SWC and lists all of the symbol inside that swc.

Now for embedding the SWF, if you wish to embed entire SWF, unfortunately you must use instance-variable method and for the datatype for the class will be mx.core.MovieClipLoaderAsset, meaning you must go with adding Flex Library. There is a panacea though, by using binary file method discussed later.

[Embed (source = "star.swf")]
var SWFAsset:Class;
var swf:* = new SWFAsset();
addChild(swf);

If you wish to reference MovieClip or Sprite on the swf, you can use class definition method, remember to add linkage id on the symbol you wish to be referenced.

package
{
    import flash.display.*;
    import flash.utils.describeType;

    [Embed (source="asset/star.swf", symbol="Star")]
    public class SWFAsset extends Sprite
    {
        public function SWFAsset(){}
    }
}

You can actually use SWF embedding and getDefinition() method to get the symbol reference. But it is better to use SWC embedding though.

Embedding Anything

Yes, you can embed just anything if you use binary file embedding. You can embed text files, xml, or whatever as long as you can parse it. AS3 XML class can parse ByteArray to XML for example. In fact if you loaded SWF this way, you may not use Flex Library.

package
{
    import flash.utils.ByteArray;

    [Embed (source="asset/star.swf", mimeType="application/octet-stream")]
    public class ByteAsset extends ByteArray
    {
        public function SWFAsset(){}
    }
}

// then use it on somewhere
import flash.display.Loader

var loader:Loader = new Loader();
loader.loadBytes(new ByteAsset());
addChild(loader);

If you read SWF binary, you can actually use SWF embedding and getDefinition() method to get the symbol reference too.

SWC Embedding

Actually SWC is like a compiled library file plus the class definition. For Action Script 3, it is quite common to see custom-made library developed by people to be distributed in SWC, but more than that, SWC can also be made to package asset files. Flash IDE can publish SWC instead of just SWF, and so we can add the SWC to our library path and “pull” assets from our SWC using class instantiation. This method is also preferable workflow of Flash IDE and Flex Builder/Flash Builder/FlashDevelop integration. See also Airtightinteractive blog for more information about this workflow and Geewa blog for strategy using the SWC.

For Flash IDE to generate SWC instead of just SWF, you must enable it on Publish Settings > Flash > Export SWC. Do not forget to add linkage id on flash symbol you want to instantiate on Actionscript 3. Set the base Class to MovieClip or Sprite.

Then add the SWC, it will be easier if you use Flex Builder or FlashDevelop. If you named your linkage Star that use Sprite as a base class for example, you may use it directly:

var temp:Sprite = new Star();
aDisplayContainer.addChild(temp);

For font embedding and more things including Flex SDK related embed method, you may see Grant Skinner’s Presentation and of course article on Flash Developer Center. Embedding binary file is another approach to embed arbitrary file, but maybe that is the topic for future post ;)