May 23 2011

FLASH PRELOADER WITH HAXE 2.07

I spent a few hours last week getting a preloader to work. All the info I could find was obsolete, so I thought I’d write up a quick how-to for the current version of HaXe. My preloader’s based on the general approach explained here: code on frame 1 of the .swf, resources on frame 2.

I’ll assume you’re using a default setup of FlashDevelop. If so, you’re currently using FlashDevelop then currently you’re using swfmill to assemble your resources and HaXe’s compiler to link the resulting resource .swf with the code. The problem is, HaXe’s compiler doesn’t currently seem to support multi-frame .swfs, even if you can get swfmill to produce them.

What we’re going to do instead is build a code-only .swf in HaXe’s compiler, then use Sam HaXe to assemble a two-frame .swf with the code from that .swf on frame 1 and the assets on frame 2.

Now, there’s one problem with using Sam HaXe. The latest version with a Windows binary, r25, doesn’t support setting the SWF header’s width, height and FPS fields. You could compile a more recent version from the repository, but to make life easier, I’ve written a simple command line tool to set the header fields after it’s built! So in this tutorial, we’ll use r25 and my utility.

1. Install Sam HaXe (a “Flash asset assembly tool”):

Go to http://mindless-labs.com/samhaxe/downloads/

Download and install samhaxe r25. On Windows 7 I found I had to run the installer as administrator or it’d fail on writing files.

2. Download SetSWFHeader.

It’s here: SetSWFHeader.

I put it in a /tools/ folder inside my project folder. Put it wherever you like, just note the path for later.

3. Set up the new build process using Sam HaXe.

Here are my custom build steps in FlashDevelop:

haxe -cp src -swf9 $(ProjectDir)\obj\Code.swf -main engine.Main -swf-header 800:600:25:000000

"C:\Program Files (x86)\SamHaXe\SamHaXe.exe" $(ProjectDir)\obj\Resources.xml $(OutputDir)\$(OutputName)

"$(ProjectDir)\tools\SetSWFHeader.exe" 600:450:25 "$(OutputDir)\$(OutputName)"

If you’re setting this up in FlashDevelop, go to Project<Properties. Check “No output, only run pre/post build commands.” in the Output tab and put something like those two lines as your pre-build and post-build command lines on the Build tab. You’ll have to go into the “Builder…” dialog to put more than one command line instruction in either of the boxes.

You may need to adjust these lines to reflect where things have installed. “Program Files (x86)” will be just “Program Files” on older machines, and SetSWFHeader of course will be wherever you put it earlier.

SetSWFHeader controls the native resolution and framerate of the SWF. The format is xres:yres:fps, and in this case – 600:450:25 – it’s setting a resolution of 600×450 and a framerate of 25fps. Adjust as required.

HaXe will build the code and output Code.swf. Note that there’s no -swf-lib parameter; we’re not linking in the resources at this point. The “-main” parameter, setting your entry point, should be whatever you had there before. Copy it from the Compiler Options tab under “Main Class” if you’re not sure what it was.

Sam HaXe will combine Code.swf and our resources to create our two frame .swf. It’s configured through its resource description file, in my case obj\Resources.xml. See the documentation. Here’s an abridged version of my file as an example. You may as well copy this and bodge it 😀

<?xml version="1.0" encoding="utf-8"?>
<shx:resources version="9" compress="false" w="800" h="600" fps="25"
	xmlns:shx="http://mindless-labs.com/samhaxe"
	xmlns:img="http://mindless-labs.com/samhaxe/modules/Image"
	xmlns:snd="http://mindless-labs.com/samhaxe/modules/Sound"
	xmlns:swf="http://mindless-labs.com/samhaxe/modules/Swf" >

	<shx:frame>
		<swf:library import="obj/Code.swf" symbols="true" />
	</shx:frame>

	<shx:frame>
		<img:image import="art/CharacterMan.png"
			class="game.data.ImgCharacterMan"
			genclass="symbolOnly" />
		<img:image import="art/CharacterPlayer.png"
			class="game.data.ImgCharacterPlayer"
			genclass="symbolOnly" />
		...
		<snd:sound import="sound/06_Punch block.mp3"
			class="game.characters.WavPunchBlock"
			genclass="symbolOnly" />
		...
		<snd:sound import="sound/music05.mp3"
			class="game.scenes.WavMusic05"
			genclass="symbolOnly" />
	</shx:frame>

</shx:resources>

As you can see, the code’s on the first frame, and the resources are all on the second. You can add resources to the first frame if you like; that means they’ll be available to the preloader, but will delay the preloader appearing.

Note the w, h and fps parameters in the shx:resources tag. Those are ignored by Sam HaXe r25 but will set the native resolution and framerate correctly (or so I’m told) in more recent versions.

4. Resource description file tweaking:

The class for each resource is the symbol it’ll be mapped to during linking. The genclass=”symbolonly” prevents Sam HaXe from automatically generating the stubs you’re probably used to putting in manually. You know? Stuff like:

class ImgFont extends BitmapData {public function new(){super(0,0);}}

If your code’s already got these, genclass=”symbolonly” will prevent Sam HaXe from declaring the symbol a second time. Alternatively, you can leave out genclass=”symbolonly” on your resources and strip out all the stubs in your code. Your call.

5. Modify your code to detect and report download progress.

Since your code starts running before your assets are loaded, you need to detect when the assets have finished loading and avoid using them until then. Here are the key variables:

flash.Lib.current.root.loaderInfo.bytesLoaded
flash.Lib.current.root.loaderInfo.bytesTotal

When bytesLoaded is equal to bytesTotal, you can begin using your assets.

Here’s how I’ve approached this. In my main class’s constructor:

m_downloadProgress = 0;
m_downloadComplete = false;

At the start of my game loop:

if ( !m_downloadComplete )
{
	if ( Lib.current.root.loaderInfo.bytesLoaded
		>= Lib.current.root.loaderInfo.bytesTotal )
	{
		// Download finished.
		m_downloadComplete = true;
		m_downloadProgress = 1.0;
		Lib.current.gotoAndStop( 2 );
	}
 	else
 	{
 		// Download still in progress.
 		m_downloadProgress = Lib.current.root.loaderInfo.bytesLoaded
 				/ Lib.current.root.loaderInfo.bytesTotal;
 	}
}

My game code elsewhere displays a progress bar based on m_downloadProgress and prevents the user from starting the game until m_downloadComplete is true.

That’s how I got my preloader working. Hope it’s helpful!

2 Comments on “FLASH PRELOADER WITH HAXE 2.07

  1. at what point did flash start looking like c++ and java had freaky interstellar sex? DAM YOU ADOBE!! DAM YOU TO HELL!!

  2. Haha. Well… technically this is HaXe code, so it’s not all Adobe’s fault… :p but HaXe is heavily based on ActionScript 2.0 and 3.0, which are based on ECMAScript, which was a formal standardisation of JavaScript, which was loosely based on Java.

    As for the C++ influence, well, HaXe has some of C++’s template syntax, even if it doesn’t support user declared templates/generics. All of these C-like languages feed off each other, really.

Comments are closed.