Writing a preloader in ActionScript 3
Note: This is a pretty technical post, if you’re not a programmer you will probably not be interested!
A preloader gives the user something to look at while the rest of your program loads. This is one of the nice things about SWF’s, they are capable of streaming - showing part of their content before fully downloaded. The way you do this is by putting all the content to be loaded later on a later frame of the SWF timeline. This does get a little complicated, because ideally you should preload not just your data, but your code as well. Any classes you don’t need for the preloader should be placed on a later frame along with any library assets.
This is where a big bug in ActionScript 3 shows up - the “Export classes in frame” setting appears to be badly broken, as discussed on actionscript.org. As you can tell, Adobe’s error is making some professionals desperate to find a workaround. Well, thanks to others in the ActionScript community, I’ve finally discovered the workaround. Unfortunately it involves abandoning Flash in favor of Flex. But, this isn’t as bad as it may sound. While I detest the Eclipse-based Flex Builder IDE, I discovered a fantastic (and free) tool called FlashDevelop that is a superior development environment to Flex Builder or Flash, and offers easier customization while lacking just a little polish (for one thing, syntax highlighting must be edited via XML file). FlashDevelop uses the command-line SWF compiler mxmlc that comes in the new (also free) Flex 3 SDK.
Actually since Adobe has all these nebulous products floating around that all pretty much do the same thing (Flash, Flex, Air, who knows what else), it’s a little confusing what language you are using for your source files. It’s ActionScript but it’s the Flex brand of ActionScript, which is a few tweaks different from Flash ActionScript. They could just merge all these tweaks into a single language and let you choose which features you want to use, but I imagine like in many other things computer, there’s less money in making things simple. Anyway, basically in Flex-ActionScript, you can embed all your library assets via source code, rather than via an IDE. Although the way you do this is a little awkward, I find it highly preferable. And you can still use advanced layouts and components by just including them via SWC
Once you get your project converted to Flex, here is the fix: instead of monkeying around with the timeline, set your preloader as your primary build class, and use the command-line option “-frame” to put your main program on frame 2 (placing the line [Frame(extraClass="Main")] in your preloader appears to be equivalent). Thanks to this German guy Sven Busse for discovering this (unfortunately the text is German, but the source code is readable). Also thanks to Lars Gerckens for his research, and BIT-101 for this alternate solution. And of course thanks to Adobe for providing such horrendously incomplete documentation that things like this have to be discovered through much trial and error. I can’t fault them too much though, since they are at least finally strangling the abomination that was Macromedia’s ActionScript 2.
After your preloading is done, you have to start the main class - but you can’t reference it because then Flex will include it, and all the classes it uses, along with the preloader on frame 1. Here’s how you instantiate it without referencing it (’Main’ is the name of the main class):
nextFrame(); // goto Main frame
var classdef:Class = getDefinitionByName("Main") as Class;
var main:DisplayObject = new classdef(); // runs itself
Now there’s another problem - your Main class won’t have a stage object until after you call addChild(main) - but how does Preloader tell Main to initialize after, when Preloader doesn’t know what class Main is? The way I do it is by storing the stage in a global variable, then letting main add itself to the stage in the constructor. I use a class called Sys that contains static variables for build type, debug mode, stage, and a few other globals. Generally globals are a bad thing, but in certain cases like this I think they are worth it.
If you have find any caveats or improvements, let me know!
=======================
One problem still exists: when loading this in a web browser, loaderInfo.bytesLoaded seems to only reflect the first frame. We need to know the total bytes for the entire SWF to accurately show load progress. From looking at the source code to mx.preloaders.DownloadProgressBar, Adobe’s own code actually has to guess at the size of the SWF it’s loading. Weak. So no “percentage loaded” indicator is going to be accurate unless you explicitly provide it with the estimated size of your SWF.

March 26th, 2008 at 10:34 pm
im sort of into programming, but i don’t like reading technical posts that are this long! ill read half…or try to.
March 26th, 2008 at 11:38 pm
“Behold! We have created a language so mysterious that even we do not know what it does!!”
April 13th, 2008 at 11:25 pm
I don’t like the bit-101 solution since it’s broken. Since his code only updates progress on Event.ENTER_FRAME, which is only called….you guessed, once when you first enter the frame, it’ll only update once.
I’m not sure what you mean when you say loaderInfo.bytesLoaded isn’t the actual size. If I modify the bit-101 solution to update on progress events, and then write loaderInfo.bytesLoaded to Firebug, it shows a continually changing value.
April 15th, 2008 at 1:41 pm
ENTER_FRAME events actually fire repeatedly, at the frame rate set by the app.
It is accurate on a local test, but if you try loading your SWF remotely, or with a slow-connection-simulator, bytesLoaded actually only reflects the size of frame 1. Yet another issue of clearly broken functionality by Adobe.. ;(
May 24th, 2008 at 12:36 am
I really miss ActionScript 2.0. I know it was horrible, but at least you could create a preloader without much hassle.
loaded=(_root.getBytesLoaded/_root.getBytesTotal)*100
that was the ActionScript 2.0 way to create a preloader. Alternatively, you could try create a separate container preloader .swf that uses ActionScript 2.0 to load the actual game (and then the game itself could run in ActionScript 3.0). I’m not entirely sure if this will help you at all though. Good luck with your project!
May 25th, 2008 at 8:05 am
Yeah it was nice when it worked, however nothing could make me miss ActionScript 2!