Preloading example with Haxe and SamHaxe
Let's see how can we create a preloaded swf for our flash game, widget or website using pure Haxe. For embedding the assets, we will use SamHaxe, our new flash asset tool.
Our goal is to have heavy assets in our swf, but would like to show a progress bar until all these assets have loaded.
Assembling the asset library using SamHaxe
Let's see the resource.xml asset descriptor that we will feed for SamHaxe:
<?xml version="1.0" encoding="utf-8"?>
<shx:resources version="9" compress="false" package="resources.classes"
xmlns:shx="http://mindless-labs.com/samhaxe"
xmlns:snd="http://mindless-labs.com/samhaxe/modules/Sound">
<!--
Empty first frame. You may put resources
required in preloader animation here.
-->
<shx:frame/>
<!-- Frame with heavy assets -->
<shx:frame>
<snd:sound class="Music" import="path/to/a/large.mp3"/>
</shx:frame>
</shx:resources>
The package attribute of the shx:resources tag is prepended to all classnames, so we will be able to access our sound asset from flash now as resources.classes.Music. Feel free to substitute your own asset package name.
Now we assemble the asset lib with SamHaxe by executing SamHaXe --config /path/to/samhaxe.conf.xml resources.xml resources.swf
Embedding the asset library in flash with Haxe
Here is the Haxe code which draw a progress bar until the whole flash file is loaded:
class PreloadingDemo {
// progress bar
var progress: flash.display.Shape;
var fully_loaded: Bool;
public function new() {
// background for the progress bar
var progressBg = new flash.display.Shape();
var g = progressBg.graphics;
g.beginFill(0x002288);
g.drawRect(-2, -2, 104, 14);
flash.Lib.current.addChild(progressBg);
progressBg.x = 10;
progressBg.y = 10;
// the progress bar itself
progress = new flash.display.Shape();
g = progress.graphics;
g.beginFill(0x00ff88);
g.drawRect(0, 0, 100, 10);
flash.Lib.current.addChild(progress);
progress.x = 10;
progress.y = 10;
fully_loaded = false;
flash.Lib.current.addEventListener(flash.events.Event.ENTER_FRAME,
onEnterFrame);
}
function onEnterFrame(e: flash.events.Event) {
var totalBytes = flash.Lib.current.loaderInfo.bytesTotal;
var actBytes = flash.Lib.current.loaderInfo.bytesLoaded;
if (!fully_loaded && actBytes <= totalBytes) {
// animate progress bar
progress.scaleX = 1.0 * actBytes / totalBytes;
}
if (!fully_loaded && actBytes == totalBytes) {
fully_loaded = true;
var music: flash.media.Sound = Type.createInstance(
Type.resolveClass("resources.classes.Music"), []
);
music.play();
}
}
public static function main() {
new PreloadingDemo();
}
}
Now we can build this by issuing:
haxe -swf preloadingDemo.swf -swf-header 100:100:20:ffffff -swf-version 9 -swf-lib resources.swf --flash-strict -main PreloadingDemo
Discussion
This example can be found in the demos directory of the SamHaxe distribution. This is a minimal example, there is plenty of space for implementing fancier preloader animation, or splitting the resources over more frames, if certain resources may only be needed later in the game.Note that all program code still resides in the first frame - a possible workaround for this is to compile a preloder-less fully functional swf, and embed it into a small preloader shell on the second frame as a binary object using shx:binary, and using flash.display.Loader.loadBytes() to load and execute it.
Have fun coding :)
Comments
Comment by Dobos Bence, () (URL) on 09.09.20. 16:09
Cool. I want to try it now.
Comment by [yfan], on 09.09.21. 14:25
thanks a lot, great work.
i am using flashdevelop, which is very convinient, but as far as i know i cannot acces the underhood resource magic, that is being brandished using swfmill.
at the end of the article you seem to say that there is a way to attach a preloader to an already working swf? this code would be very useful for the flashdevelop+haxe crowd, including me.
Thanks for all quick answers and all the great work :).
Comment by [ron], (URL) on 09.09.21. 19:16
Glad you like it. Yes, it is possible to attach a preloader to an already built swf. You have to create an asset lib with samhaxe, where you put the swf to wrap on the second frame with the <binary> import module. Then use this asset lib with -swf-lib in your preloader:
1) wait and animate until everything is loaded.
2) create an instance of the embedded binary object, and load it into a MovieClip using Loader.loadBytes (don’t forget to create a new ApplicationDomain). Put the loaded MC on the display list and that’s it.
However, care must be taken if you would like to load third party API’s from inside the wrapped swf, as these API’s tend to parse flash vars and think that they are loaded into the swf at the outermost "shell".
This may be circumvented by indeed loading these API’s into the outermost shell. Maybe a separate article would be needed to clarify this.
Good luck!
