Creating a two-step Flash preloader

Sarah and two laptops
500 kbps ain't as fast as it used to be

I came up with this one in Costa Rica, while consistantly waiting three minutes for a 5 meg Flash game (Rebuild, as a matter of fact) to load. The vector graphics take up very little space so over 4 of those megs were just the music. Since I usually play Flash games muted, I figured it was foolish to make players wait until the music loaded before they could start playing. Enter the multi-part Flash preloader.

Preloaders in Flash work by putting some content (the loading animation) on Frame 1 of the base MovieClip, and the rest of the content (the game and music) on Frame 2. The first frame loads in its entirety and any actionscript on that frame executes before the second frame starts to load. This makes sense when you consider that Flash was designed for playing movies. So, can you simply move some of the content (the music) to Frame 3? Yes, it’s that easy!

Well, easy if you’re writing your game on the timeline in the Flash authoring tool. I prefer to use FlashDevelop and the Flex compiler (both free) instead, so my main class is in an AS3 file and the frame metaphor is more obscure. If you start a new project in FlashDevelop using the “AS3 Project with Preloader” template, it creates a Preloader.as class, and a Main.as class with “Always Compile” and the Frame metatag [Frame(factoryClass=”package.Preloader”)]. What this tag does is tell the compiler to put Main.as (and any of its dependancies) on the second frame, and Preloader.as (with its dependancies) on the first frame.

So, if you stack one more class on top…

Music.as with [Frame(factoryClass=”package.Main”)] (set to “Always Compile”)
Main.as with [Frame(factoryClass=”package.Preloader”)]
Preloader.as with a spinny ball animation

Flash Frames

The only catch is you can’t determine how much of Main.as has loaded using loaderInfo.bytesTotal because that will also include the bytes from Music.as. Instead you either need to look at Preloader.currentFrame, or try to instanciate Main and catch an error if it’s not ready yet. You could get fancy and use as many frames as you want to determine load order of all your assets, but if you’re dealing with one very large swf it’s still better to cut it up and stream your assets from outside.

While South Korea has plans to put 1 gigabit connections in every home, internet speeds in big countries like the US and Canada have been falling behind. Many areas of the world will be running through 3g cell connections before they even have cable or dsl lines. So go easy on them and don’t forget the preloader! :)

Here’s my example code:

Preloader.as

package loadtest
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.utils.getDefinitionByName;

	public class Preloader extends MovieClip
	{
		public function Preloader()
		{
			addEventListener(Event.ENTER_FRAME, frameEntered);

			trace("preloader starting");

			// TODO put your spinny ball here but DO NOT reference the Game or Music classes
			// directly or they will be compiled in to Preloader frame 1
		}

		private function frameEntered (...ig) :void
		{
			// the user can begin playing the game
			if (currentFrame == 2) {
				trace("frame 2 finished loading, starting game.");
				var gameClass :Class = getDefinitionByName("loadtest.Game") as Class;
				addChild(new gameClass());
				// TODO remove your spinny ball here because the game has started

			// finally, the music can also start
			} else if (currentFrame == 3) {
				trace("frame 3 finished loading, starting music.");
				var musicClass :Class = getDefinitionByName("loadtest.Music") as Class;
				addChild(new musicClass());

				// all done loading everything so ditch the preloader
				stop();
				removeEventListener(Event.ENTER_FRAME, frameEntered);
			}
		}
	}
}

 

Game.as

package loadtest
{
	import flash.display.MovieClip;
	import flash.utils.getDefinitionByName;

	[Frame(factoryClass="loadtest.Preloader")]
	public class Game extends MovieClip
	{
		public function Game () :void
		{
			trace("game starting");

			// TODO put your entire game here but DO NOT reference the Music class
			// directly, or it will be compiled in to Preloader frame 2

			try {
				// this is okay, but will throw an error if the Music isn't loaded yet
				var musicClass :Class = getDefinitionByName("loadtest.Music") as Class;
				var music :MovieClip = new musicClass();
			} catch (error :ReferenceError) {
				trace("music class isn't loaded yet");
			}
		}
	}
}

 

Music.as

package loadtest
{
	import flash.display.MovieClip;

	/**
	 * This file must be marked as "Always Compile"
	 */
	[Frame(factoryClass="loadtest.Game")]
	public class Music extends MovieClip
	{
		public function Music () :void
		{
			trace("music starting");

			// TODO reference your mp3 or wav classes here so they will be compiled in to
			// Preloader frame 3.  You can also reference Game since it's already loaded.

			// this is okay
			var game :Game;
		}
	}
}
Share

6 thoughts on “Creating a two-step Flash preloader

  1. To keep my bandwidth costs down, I only load music and soundFX on-demand – and only when the user hasn’t clicked the mute button first. I found a ton of people would load the game and quit on the main menu – or never make it to the boss sequence – so loading up that music during the preloader didn’t make sense.

    All part of my sound library!

    I store the music and SFX as MP3 files on my webserver (or, for sponsored games, on their webservers) and just use a URL request to load it up the first time I request playing it.

    1. I agree this is the way to go if you’re hosting something yourself, but I was under the impression that sponsors wanted single-file distributions. I thought they didn’t want to host the music separately because when other sites copy the un-sitelocked game to their own servers, the sponsor would still be paying to stream the music to them.

      1. The sponsored version of the game is fine to have external file dependencies, and that’s where most of your traffic will come from. The ‘Viral version’ would be a different copy of the game you can then post on other sites.

        So as an example:

        Steambirds on ArmorGames, kongregate, newgrounds – all had external files. AG was the primary sponsor.

        The viral version was submitted to Mochi and FlashGameDistribution as a single file.

  2. Aloha. I just finished rocking out your game “rebuild” and I wanted to tell you I loved it. I’m currently learning flash and hope some day soon I’ll be making a zombie game on par with this one.

    Have you played the flash game series “The Last Stand”? I swear to God if you could incorporate the player character shooting feature with the way you have your game set up to determine the number of defenders you have at your base you’d have the most epic zombie flash game ever:)

    Keep up the good work. Hope there’s a sequel on the way?

Leave a Reply

Your email address will not be published.