Using a Launcher SWF
November 17th, 2009 - filed under ProgrammingSince this blog could potentially have many SWF examples on a single page, I have to consider effect of having them load and run all at once, both on the browser and on my bandwidth. Users will not always want to see every SWF, so ideally a “click to start” intro would precede the loading of each example.
I tried this with just an image: when it was clicked, it would hide itself and embed the SWF where the image had been. Unfortunately, the SWF was not focused and would have to be clicked again, and Firefox has a flaw that does not always allow javascript to focus a SWF
. Therefore the nice and simple image idea had to give way to a whole separate SWF as a launcher for the examples. The launcher is always running, but it’s small and the frame rate is low and it doesn’t do too much. Once the launcher is clicked it loads the example SWF and bumps up the frame rate to the proper level. Of course, since this is Actionscript, what takes a sentence to write took 2 days to implement.
This is a form of preloader, and I’ve gotten confused a few times when thinking about this, so I’ll document it here. It also helped me to refer back to my post on preloaders.
preloader via separate swf
- displays “click to start” and waits – this can be bypassed via an argument to the swf
- loads the main swf while updating progress
- sets the new framerate, activates the main swf, and goes away
preloader embedded in main swf
- the preloader is on frame 1 of the timeline, and begins to execute while the rest of the timeline loads
- large assets are embedded in later frames
- the preloader passes control to the main program once the swf fully loads
For Jetpack, I’m going to attempt a combination of the 2 methods, so the user experience will be as follows:
- The game window will instantly show loading progress (preloader swf)
- The preloader will fade away, revealing a Jetpack level in demo playback (main swf preloader)
- While the demo game runs, a status bar will show progress as the rest of the assets (mp3 music) load
(At this point, an in-game ad could be shown, but the income from those is not impressive and I’d rather not clutter up the game.) - When loading is complete, the main menu will fade into view
There are some other advantages to using a launcher swf that I can think of:
- When users embed the launcher swf on their own websites, it will always load the latest version of Jetpack from JetpackHQ.
- I’ll have full stats on who is playing and where.
- Security against game reskinning is improved, by having the launcher and the main swf validate eachother.
Getting the launcher just right took some struggling with Actionscript, but the result works great. It’s only 2k, and can serve just about any swf file (on the same server). I was able to find a way to read the target framerate from the loaded swf and set that before launching it. You can also read the width & height, but I know no way of resizing the SWF at runtime without using javascript. I’ve attached the source code to this project at the bottom of this post. Here’s a sample:
function Startup()
{
// ARGS - launch='', now=0/1
var args = stage.loaderInfo.parameters;
if(args.launch!=undefined) launch_swf_path = args.launch;
if(args.now!=undefined) wait_for_click = !int(args.now);
if(!launch_swf_path) Fail("usage: launcher.swf?launch=abc.swf&now=0");
if(wait_for_click)
{
Show_WaitForClick();
stage.addEventListener(MouseEvent.CLICK, StartLaunch);
}
else StartLaunch();
}
//--------------------------------------
function Shutdown()
{
root.Shutdown();
root = null;
System.gc();
}
//------------------------------------------------------------------------------
function StartLaunch(event:MouseEvent=null)
{
if(wait_for_click)
{
stage.removeEventListener(MouseEvent.CLICK, StartLaunch);
Hide_WaitForClick();
}
Show_Preloader();
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, CheckReady_Hack);
stage.addEventListener(Event.ENTER_FRAME, CheckReady_Hack);
loader.load(new URLRequest(launch_swf_path));
}
//--------------------------------------
function CheckReady_Hack(event:Event)
{
// in certain cases when not waiting for click, complete/init fires but loaderInfo.frameRate
// is not accessible. misinformation from the official ActionScript docs: "When the loaderInfo
// object dispatches the init event, you can access all properties of the loaderInfo object"
if(event.type==Event.COMPLETE)
{
ready_hack = true;
loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, CheckReady_Hack);
}
if(event.type==Event.ENTER_FRAME)
{
if(!ready_hack) return;
stage.removeEventListener(Event.ENTER_FRAME, CheckReady_Hack);
Launch();
}
}
//--------------------------------------
function Launch()
{
Hide_Preloader();
var swf:DisplayObject = loader.content;
// frameRate, width, height are only available before unload()
stage.frameRate = swf.loaderInfo.frameRate;
loader.unload();
loader = null;
// clear the stage
while(stage.numChildren) stage.removeChildAt(0);
// launch the loaded swf
stage.addChild(swf);
Shutdown();
}

