Blog

Pixlib – Tut 03 – How to load assets at runtime

Hello there.

As said in the title this tutorial will help you to load assets at runtime. At the same time we will see how to use FlashDevelop and MTASC to create a swf. So no need to open flash anymore…

Ok first, if you didn’t please look at the first tutorial which give you the basis of the pixlib framework.

This tutorial will use the source files of the first tutorial as a starting point. You can download those files from here

[Download id not defined]

The sources of this tutorial
[Download id not defined]

 

I. Refreshing our memory

So remember, we had a fla importing the Application.as class and then creating an instance of it to start the whole application.
[as]
import net.webbymx.projects.tutorial01.Application;
var apz : Application = new Application( this );
[/as]
The fla had the assets in it’s library so we were doing in the Application.as
[as]
// Instantiating the views
var digital : MovieClip = this.attachMovie(“mc_digital”, “mc_digital”, 0 );
var vDigital : ViewDigital = new ViewDigital ( digital );
[/as]
to instantiate a view.

 

II. SWFMILL and MTASC

Now, we don’t want to use flash anymore ( anyway for the development side ).

We will use 2 tools:

  • SWFMILL to create swfs ( empty or not, see the project page for more info please )
  • MTASC to compile our classes with and push them in the swf created by SWFMILL

If you don’t know how to use or integrate those great tools to your editor, go on their respective project page and / or on the project page of your editor.

For my case, I’m using FlashDevelop a great FREE editor ( only for window user sorry :/ ). It has MTASC and SWFMILL in it, and it’s as simple as clicking a button to compile your project.

 

III. Show me the sh*t!!!

Ok, ok…

a. Pixlib Classes used

We will use 3 classes that are part of the Pixlib framework.

  • The first one is the ConfigLoader, which helps you loading the XML setting up your application
  • The second one is the GraphicLib, which helps you loading an asset in your application.
  • The third one is the LibStack, which is a download manager

Why that?
First we need to load an xml to know where our assets are.
Then we will use the LibStack, push in it all the GraphicLib created ( one for each asset ) and start the download process.

By the way if you dunno how works the ConfigLoader class have a look here please.

b. A typical Application.as

Here is the code of a typical Application.as class. I’m now always using this as a template for all my projects ( until further improvement as usual ๐Ÿ™‚ )
It’s a bit long, but it’s just for you to have a quick look. We will go anyway in details in the code…

[as]
// Debug
import com.bourre.log.Logger;
import com.bourre.log.LogLevel;
import com.bourre.log.PixlibDebug;
import com.bourre.utils.LuminicTracer;

// Models
import com.bourre.core.Model;
import net.webbymx.projects.tutorial03.models.*;

// Views
import com.bourre.visual.MovieClipHelper;
import net.webbymx.projects.tutorial03.views.*;

// Controller
import net.webbymx.projects.tutorial03.commands.Controller;

// Personnal EventBroadcaster
import net.webbymx.projects.tutorial03.events.XEventBroadcaster;

// Events
import com.bourre.events.BasicEvent;
import com.bourre.events.IEvent;
import net.webbymx.projects.tutorial03.events.EventList;

// ConfigLoader
import com.bourre.data.libs.ConfigLoader;
import com.bourre.data.libs.XMLToObjectDeserializer;

// Libstact, GraphicLib
import com.bourre.data.libs.LibStack;
import com.bourre.data.libs.GraphicLib;
import com.bourre.data.libs.GraphicLibEvent;

// tweening
import com.mosesSupposes.fuse.*;

class net.webbymx.projects.tutorial03.Application
extends MovieClip {

/* ****************************************************************************
* PRIVATE STATIC VAR
**************************************************************************** */
private static var _oI : Application;

/* ****************************************************************************
* PRIVATE VARIABLES
**************************************************************************** */
// VAR
private var _oConf : Object;

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
private function Application(container) {
// the movieclip is transtyped as a application object
container.__proto__ = this.__proto__;
container.__constructor__ = Application;
this = container;
_oI = this;

// init the object
_init();

// load the conf
_loadConf();
}

public static function getInstance() : Application {
if ( _oI == undefined ) {
if ( arguments[ 0 ] == undefined || typeof( arguments[ 0 ] ) != “movieclip” ) PixlibDebug.FATAL( “Cannot create the Application object. You need to pass a MovieClip as a parameter” );
else var apz : Application = new Application( arguments[ 0 ] );
}
return _oI;
}

public static function main( mc : MovieClip ) : Void {
var apz : Application = Application.getInstance( mc );
}

/* ****************************************************************************
* PRIVATE FUNCTIONS
**************************************************************************** */
/**
* Init the Application
* @param Void
*/
private function _init() : Void {
Logger.LOG( “Application :: _init” );

Stage.align = “TL”;

// register the ZigoEngine
ZigoEngine.register( PennerEasing, FuseItem, FuseFMP );
ZigoEngine.EASING = “linear”;

// init the debugger
Logger.getInstance().addLogListener( LuminicTracer.getInstance() );

// create the model
var mClock : ModelClock = new ModelClock();

// init the controller with our custom EventBroadcaster class
Controller.getInstance( XEventBroadcaster.getInstance() );
}

/**
* Load the congif.xml file
* @param Void
*/
private function _loadConf( Void ) : Void {
Logger.LOG( “Application :: _loadConf” );

// Define some properties of the deserializer
XMLToObjectDeserializer.DESERIALIZE_ATTRIBUTES = true;
XMLToObjectDeserializer.PUSHINARRAY_IDENTICAL_NODE_NAMES = true;

// creating the object holding the result for a map
_oConf = new Object();

// creating the config loader
var _cfLoader : ConfigLoader = new ConfigLoader( _oConf );
// define the callback once the xml is loaded
_cfLoader.addEventListener( ConfigLoader.onLoadInitEVENT, this, loadLoader );
// load by default the “config.xml” file
_cfLoader.load();
}

public function _loadAssets () : Void {
Logger.LOG( “Application :: loadAssets” );

// total bytes loaded
var totalBytes : Number = 0;

// Loading everything
var libContainer : MovieClip = this[“__libContainer”];
var libs : LibStack = new LibStack();

// get the array of assets to load
var aAssets : Array = _oConf.assets.asset;
for( var i = 0; i < aAssets.length; ++i ) { // create the graphic lib var gl : GraphicLib = new GraphicLib( libContainer, aAssets[ i ].depth, false ); // define callbacks gl.addEventListener( GraphicLib.onLoadInitEVENT, this, onAssetLoaded ); gl.addEventListener( GraphicLib.onLoadProgressEVENT, this, onAssetProgress ); // add to the LibStack libs.enqueue( gl, aAssets[ i ].view, _oConf.paths.assets + aAssets[ i ].url ); // update the totalBytes totalBytes += aAssets[ i ].size; } // set the total bytes var vLoader : ViewPreloader = ViewPreloader( MovieClipHelper.getMovieClipHelper( ViewList.VIEW_PRELOADER ) ); vLoader.setTotalBytes( totalBytes ); // define the call back events libs.addEventListener ( LibStack.onLoadCompleteEVENT, this ); libs.addEventListener( LibStack.onTimeOutEVENT, this ); // Start the download libs.execute(); } /** * Build the Application * @param Void */ private function _build( Void ) : Void { Logger.LOG( "Application :: _build" ); // you can hide the preloader from inside a command ( like in a command StartApplication ) var vLoader : ViewPreloader = ViewPreloader( MovieClipHelper.getMovieClipHelper( ViewList.VIEW_PRELOADER ) ); vLoader.fadeout(); // create views var vDigital : ViewDigital = new ViewDigital ( ViewList.VIEW_DIGITAL ); var vAnalog : ViewAnalog = new ViewAnalog ( ViewList.VIEW_ANALOG ); var vTools : ViewTools = new ViewTools ( ViewList.VIEW_TOOLS ); // views listening to the model var mClock : ModelClock = ModelClock( Model.getModel( ModelList.MODEL_CLOCK ) ); mClock.addListener( vDigital ); mClock.addListener( vAnalog ); mClock.addListener( vTools ); // The clock start playing XEventBroadcaster.getInstance().broadcastEvent( new BasicEvent( EventList.START_CLOCK ) ); } /* **************************************************************************** * PUBLIC FUNCTIONS - CALLBACKS **************************************************************************** */ /** * load the loader ( funny :/ ) * @param e */ public function loadLoader( e : IEvent ) : Void { Logger.LOG( "Application :: loadAssets" ); // this movieclip will be the main container for all the assets loaded var libContainer = createEmptyMovieClip( "__libContainer" , this.getNextHighestDepth() ); // Creating the GraphicLib for the prelaoder var gl : GraphicLib = new GraphicLib( libContainer, _oConf.assets.preloader.depth, false ); // define the callbacks gl.addEventListener( GraphicLib.onLoadInitEVENT, this, onLoaderLoaded ); /* define the name of the library - the same as the view name * thus when we are creating the view, the view will look in all the GraphicLib will find one * with the same name and will use it */ gl.setName( _oConf.assets.preloader.view ); // load the preloader gl.load( _oConf.paths.assets + _oConf.assets.preloader.url ); } /** * call back once the graphic of the laoder is called * @param e */ public function onLoaderLoaded( e : GraphicLibEvent ) : Void { Logger.LOG( "Application :: onLoaderLoaded" ); // create the view, will link automatically to the graphic var vLoader : ViewPreloader = new ViewPreloader( e.getName() ); vLoader.show(); // start the download process _loadAssets(); } /** * Update the loader view * @param e */ public function onAssetProgress( e : GraphicLibEvent ) : Void { var vLoader : ViewPreloader = ViewPreloader( MovieClipHelper.getMovieClipHelper( ViewList.VIEW_PRELOADER ) ); vLoader.onLoadProgress( e.getLib().getBytesLoaded() ); } /** * Update the loader view * @param e */ public function onAssetLoaded ( e : GraphicLibEvent ) : Void { Logger.LOG( "Application :: onAssetLoaded : " + e.getName() ); // e.getView().stop(); var vLoader : ViewPreloader = ViewPreloader( MovieClipHelper.getMovieClipHelper( ViewList.VIEW_PRELOADER ) ); vLoader.addBytes( e.getLib().getBytesTotal() ); } /** * Once everything is loaded */ public function onLoadComplete() : Void { Logger.LOG( "Application :: onLoadComplete" ); _build(); } /* **************************************************************************** * GETTER & SETTER **************************************************************************** */ } [/as] Ok let's see the code in details now. As usual my Application.as when created is calling the _init() function, which is setting up ( here ) the fuse tween engine, the Looger, and controller using our custom EventBroadcaster ( why using a custom EventBroadcaster is explain in the first tutorial )

LOADING THE CONFIGURATION
Then following the process said above, I’m first loading the config.xml file
[as num=111]
/**
* Load the congif.xml file
* @param Void
*/
private function _loadConf( Void ) : Void {
Logger.LOG( “Application :: _loadConf” );

// Define some properties of the deserializer
XMLToObjectDeserializer.DESERIALIZE_ATTRIBUTES = true;
XMLToObjectDeserializer.PUSHINARRAY_IDENTICAL_NODE_NAMES = true;

// creating the object holding the result for a map
_oConf = new Object();

// creating the config loader
var _cfLoader : ConfigLoader = new ConfigLoader( _oConf );
// define the callback once the xml is loaded
_cfLoader.addEventListener( ConfigLoader.onLoadInitEVENT, this, loadLoader );
// load by default the “config.xml” file
_cfLoader.load();
}
[/as]
You should know this already, otherwise go look the second tutorial

LOADING THE LOADER
So when our config.xml is loaded the function loadLoader is called
[as num=200]
/**
* load the loader ( funny :/ )
* @param e
*/
public function loadLoader( e : IEvent ) : Void {
Logger.LOG( “Application :: loadAssets” );
// this movieclip will be the main container for all the assets loaded
var libContainer = createEmptyMovieClip( “__libContainer” , this.getNextHighestDepth() );

// Creating the GraphicLib for the prelaoder
var gl : GraphicLib = new GraphicLib( libContainer, _oConf.assets.preloader.depth, false );
// define the callbacks
gl.addEventListener( GraphicLib.onLoadInitEVENT, this, onLoaderLoaded );
gl.addEventListener( GraphicLib.onLoadProgressEVENT, this );
/* define the name of the library – the same as the view name
* thus when we are creating the view, the view will look in all the GraphicLib will find one
* with the same name and will use it */
gl.setName( _oConf.assets.preloader.view );
// load the preloader
gl.load( _oConf.paths.assets + _oConf.assets.preloader.url );
}
[/as]
Ok we are entering in the new stuff…

So here ( line 207 ) we are creating a container that will contain all the asset loaded.

Then we are creating our GraphicLib. GraphicLib helps you to load external assets into your application. To create a new GraphicLib you need to give 3 parameters. The first one, it’s parent MovieClip, second one the depth it will be load in, and a final ( and optional ) defining if you want your graphic to show automatically once loaded.
[as num=210]
var gl : GraphicLib = new GraphicLib( libContainer, _oConf.assets.preloader.depth, false );
[/as]

A GraphicLib is broadcasting 3 events:

  • onTimeOut: if a onLoadProgress event was not receive after a certain time ( by default 10s, but you can set it using the setTimeOut() function ) this event will be triggered
  • onLoadProgress: this event will be called everytime the application is receiving datas
  • onLoadInit: this event will be triggered when the download process of the GraphicLib will be successfully done

So here we are adding the Application object as a listener to the events sent by the GraphicLib.

Then we are setting the name of the GraphicLib. Why that?
When you are creating a MovieClipHelper you have two choices. The first one is passing a name ( used to get the MovieClipHelper using the MovieClipHelper.getMovieClipHelper() function ) and the reference of the clip that will be used ( the one going in the view property ) OR you can just pass a name. If you do so, the MovieClipHelper will look automatically in all the GraphicLib loaded for the name matching his and will use this GraphicLib as a reference to the _view property. Nice ๐Ÿ™‚
That’s why here I’m givgin the name of the preloader view ( taken from the xml file ).

Then we are starting the loading process for the preloader, giving the path of the asset to load
[as num=218]
// load the preloader
gl.load( _oConf.paths.assets + _oConf.assets.preloader.url );
[/as]

Please check the ViewPreloader.as and the view_preloader.fla ( which is only the design part ) files to see how it is working.
I will not go into this during this tutorial… The only thing you need to know is that we have 3 methods that we will use. The setTotalBytes that is setting the total bytes that will be loaded, the addBytes that add bytes to loaded bytes and onLoadProgress that update the text and the progress bar.

So ok, our preloader is loaded now. So the function onLoaderLoaded() will be triggered ( remember we’ve set this up line 212, by adding the Application object as a listener to the GraphicLib object created ).
This function is showing the loader and start loading the assets by calling _loadAssets().

LOADING ALL THE ASSETS
This is the most interesting part. Here we will use the LibStack to enqueue all the swf we want to load using the GraphicLib objects.

First we are setting up the totalBytes to 0. This variable will get the total of bytes that will be loaded.

How? In our xml file, for each swf, we have a node called size that specify the weight of the swf. So as we will read the infos for each swf we will add the size to the totalBytes variable.

Why? Why adding the size in our config.xml? Because you can’t know BEFORE starting the loading process how big the file will be. So by knowing it BEFORE ( using this way ) our preloader will be better, because it will be able to display the right % loaded out of the WHOLE. Instead of saying eg ” loading 80% of file 02 / 09″, which basically say nothing cause you dunno how big are the other files so you dunno how long you will wait, it will say “loading website 10%”. Of course you could add as well the file number ( like 02 / 09 ) if you wish.

Ok back to the code.

We are creating a reference to our __libContainer MovieClip ( as it will be used as the container for our assets )

We are creating our LibStack object ( the download manager )

Then we are looping in all our assets ( btw we are able to loop in the asset array made by the XMLTOObjectDeserializer because we have set up the XMLTOObjectDeserializer.PUSHINARRAY_IDENTICAL_NODE_NAMES static var to true ).

For each loop ( asset ) we are:

  • creating a GraphicLib ( that knows where the asset will be loaded and if it should automatically show or not )
  • setting the Application as a listener to the GraphicLib newly created
  • adding the newly created GraphicLib to the LibStack. The main difference is here. We are pushing in the LibStack the GraphicLib object, its name and the path of the asset to load.
  • adding the size of the files to the totalBytes variable

We are setting then the totalBytes of our loader ( then it will be able to get the % of the whole )
We are setting up the Application object as a listener to certain LibStack events

And finally we are starting the download process, by calling OurLibStack.execute().
This function will start downloading the first GraphicLib we have pushed. Once done, the second and so on…

Once everything is loaded the LibStack will dispatch the onLoadCompleteEVENT event. The onLoadComplete will be called, building our website. Here we are jsut creating the views, and passing them the same name we have passed to the GraphicLib ( remember that the MovieClipHelper will automatically look for a GraphicLib having the same name to use it as its _view property ).

That’s nice. But to get the % of the whole loaded it’s not over.
We’ve seen that for our GraphicLib objects created we have set up the Application object as an event listener.
We need to write some code in those to interact with the loader.

First the onAssetLoaded. This function is adding the size of the asset to the loadedBytes of the loader.

Second in the onAssetProgress, we will send to the loader the bytes loaded. The loader will display the % of the whole depending on the already loaded bytes + the one sent.

So let’s say you are loading the first asset. The loadedBytes are 0. onAssetProgress, we are getting the number of bytes loaded ( 10000 ) that we are sending to the loader using the onLoadProgress. The loader will have 0 + 10000 bytes. Now on the other onAssetProgress we are having now 20000, we are sending this value to the loader which will have 0 + 20000, and so on. Once the asset is fully loaded we are updating the loadedBytes of the preloader. Let’s say our asset was 25000 heavy. The loadedBytes of your loader will be now 25000. Then loading the next asset the loader will calculate the % on the 25000 + bytes basis.

I hope that’s clear lol ๐Ÿ™‚

If it’s not errrr… look at the source files or / and post a comment …

C ya

  • Thanks for you tut.

    I will now to try to update my website with the libstack of pixlib.

  • Thanks for you tut.

    I will now to try to update my website with the libstack of pixlib.

  • pml

    Thanks for the share, it’s really usefull to me.
    May be i’m wrong but i noticed that:
    – in Application.as, the instance does listen to any onLoadProgress from the loading of the loader (no onLoadProgress method) so the line:
    gl.addEventListener( GraphicLib.onLoadProgressEVENT, this );
    seems to need to be forgotten

    – the fuse in the loader view seems to be missing his target: no clip instance named “mc_head” in the original view_preloader.fla, i just corrected with a single element fuse…
    Thanks again

  • pml

    Thanks for the share, it’s really usefull to me.
    May be i’m wrong but i noticed that:
    – in Application.as, the instance does listen to any onLoadProgress from the loading of the loader (no onLoadProgress method) so the line:
    gl.addEventListener( GraphicLib.onLoadProgressEVENT, this );
    seems to need to be forgotten

    – the fuse in the loader view seems to be missing his target: no clip instance named “mc_head” in the original view_preloader.fla, i just corrected with a single element fuse…
    Thanks again

  • zeflasher

    Yes you are right pml.
    For the event I’ve forgot to remove it. We don’t need it as we are loading the loader ( always weird when I’m writing this:) )
    For the fuse you are right too. I’ve forgot to remove it too ( I’ve taken the code from real job and have deleted what was not needed, didn’t see this one :/ )

    Anyway, I’ve updated the files
    and the tutorial…

  • zeflasher

    Yes you are right pml.
    For the event I’ve forgot to remove it. We don’t need it as we are loading the loader ( always weird when I’m writing this:) )
    For the fuse you are right too. I’ve forgot to remove it too ( I’ve taken the code from real job and have deleted what was not needed, didn’t see this one :/ )

    Anyway, I’ve updated the files
    and the tutorial…

  • hi there,
    that was a great tutorial, thnxs for the effort and for sharing it with us!
    Canร‚ยดt wait to see more stuff!!

    regards,
    goliatone

  • hi there,
    that was a great tutorial, thnxs for the effort and for sharing it with us!
    Canร‚ยดt wait to see more stuff!!

    regards,
    goliatone

  • isambard

    I just want to say THANKS SO MUCH for both the tutorials and the template implementations; i may have got there eventually, but it looked pretty impenetrable to me before. Thank you for the effort !

  • isambard

    I just want to say THANKS SO MUCH for both the tutorials and the template implementations; i may have got there eventually, but it looked pretty impenetrable to me before. Thank you for the effort !

  • zeflasher

    Thx for the comment, I appreciate. Some other tutorials are on their way but they will deal with pixlib’s big brother: “lowRa” ( AS3 ). Stay tunned!

  • zeflasher

    Thx for the comment, I appreciate. Some other tutorials are on their way but they will deal with pixlib’s big brother: “lowRa” ( AS3 ). Stay tunned!

  • long

    hi!
    thanks for the 3 tuts!
    is there no better way to know the total size? having to hard code each kb value in the xml seems a bit weird.
    just wondering…

  • long

    hi!
    thanks for the 3 tuts!
    is there no better way to know the total size? having to hard code each kb value in the xml seems a bit weird.
    just wondering…

  • zeflasher

    Hello long,

    Thx for the feedbacks

    AS2 has no way to get the size of the file prior to it’s download.
    You can use server side scripting to retreive the filesize of the assets you want to dld though.
    I found putting the filesize in the xml the more conveniant way. But that’s my way ๐Ÿ™‚
    ++

  • zeflasher

    Hello long,

    Thx for the feedbacks

    AS2 has no way to get the size of the file prior to it’s download.
    You can use server side scripting to retreive the filesize of the assets you want to dld though.
    I found putting the filesize in the xml the more conveniant way. But that’s my way ๐Ÿ™‚
    ++