Posted on Oct 18, 2011

Way back in the AS2 days, you could write Actionscript preloaders that could run inside the same *.fla/swf file as your main movie/site/app/animation.  Useing frames and checking the movie size vs the bytes loaded, you could figure out when the movie was completely in memory and readyfor use.  With AS3, with class files and proper object-oriented structures, it became less clear as to how you were supposed to do this.

Generally everything in your library was being exported on frame 1, so how could you put a preloader there?  Frame 1 would need to load first before it would execute, and by then its too late for the preloader to do anything.  So it seemed like the consensus amongst the people I talked to and worked with was that you needed to a build a separate pre-loader movie which would load the main movie.

I have to make two files to do a preloader?  Ridiculous. This is something that had bugged me for years and added to my frustration with AS3 and reluctance to properly move into coding with it.

At the time, I was scouring the internet for answers to my question, but never came across a proper solution, so I gave up and went the two swf route.

Several months ago while wrestling with a particularily large banner ad, I thought I'd try again.  Turns out people who make flash games had ran into the same problem (many flash gaming websites require that your game be a single swf with no external dependancies), and while no single web page gave me the complete solution, I was able to kind of piece it together.

There are two main pieces to the solution:

Leave the Class field empty!

1) Your main movie should not have a class file. This kind of goes against standard practice - when first starting your flash project, you probably create your *.fla and the first thing you do is edit the properties and drop in a class name to match the *.as file you're going to create. You can create your project architecture and classes as you normally would, even your main class file, just don't assign it to the *.fla file.

Instead, on frame 1 of your *.fla you should create your preloader code.  Drop in the preloader graphics on the stage in frame 1 (or create them with AS3), use the loaderInfo property of your main movie to get the bytes loaded, etc.

Some simple preloader code that would go on frame 1:

import flash.display.LoaderInfo; function onProgress(e:Event) { trace("Progress.root: " + root); trace("Progress.loaderInfo: " + root.loaderInfo); trace("Progress.loaderInfo.bytesLoaded: " + root.loaderInfo.bytesLoaded); trace(root.loaderInfo.bytesLoaded + "//" + root.loaderInfo.bytesTotal); } function init(e:Event) { gotoAndPlay(2); } root.loaderInfo.addEventListener(ProgressEvent.PROGRESS, onProgress); root.loaderInfo.addEventListener(Event.COMPLETE, init); stop();

You'll see that "init()" is called when the COMPLETE event fires, and init() just goes to frame 2, which leads to...

2) Export ActionScript on Frame 2: This is an option that's kind of hidden away inside of the Flash IDE.  It allows you to export all your library items and class files on a frame other than 1.  This is good because we want our pre-loader on frame 1 to execute first, figure out how big the movie is and tell the user how long it will take to download.  With all the class files and library items loading beyond frame 1, you'll get the expected, traditional pre-loader behaviour.

Set the frame to something other than 1, so that all your classes are loaded after your preload code.

In Flash CS4 you can find this option under "File > Publish Settings > (tab) Flash > (button) ActionScript 3 settings".  You'll find a field there labeled "Export classes in frame:".  Set that to whatever you want.  (Other versions of Flash may vary on the location of this setting, as well as whether the setting is even available)

Awesome, we're done right?!  Almost.  If you were to run the movie as is, you'd probably see your preloader and then a blank window, or some other sign of something going wrong.  The problem (at least as near as I've been able to surmise) is that while all our classes are being exported on something other than 1, the main class that actually ties everything together and makes it go is not being imported and fired off.  An easy fix.  On frame 2 (or whatever you've set as your next frame after the preloader), you'd do something like this:

import MainMovieClass; addChild(new MainMovieClass()); stop();

Bring in your class, add it to the stage, and away you go as you normally would.  All your classes are loaded and firing off, and all the library graphics they need are read to be called.

Disclaimer: I know my way around flash, have built a number of complex AS2 sites and in recent years AS3 sites and even a contest app/pseudo-game.  However, I don't work in it every single day and I'm definitely not a guru.  If you're a guru and see ways to improve on this, please post a comment so people who end up on this page via Google will have best practices to follow.