Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Dooprod

LoaderMax external class structure

Recommended Posts

Hello!
Is it possible to load objects outside the "complete" events ( LoaderEvent )?

Right now, it's like this:

function initLoader():void {
  xmlLoader = new XMLLoader( "PathToXml/xml.xml", { onComplete:loadData } );
  xmlLoader.load();
}

function loadData( e:LoaderEvent ):void {
  loaderMax = LoaderMax.getLoader( "loaderID" );
  loaderMax.addEventListener( LoaderEvent.COMPLETE, completeLoader );
  loaderMax.load();
}

function completeLoader( e:LoaderMax ):void {
  texture1 = TextureFromBitmapData( LoaderMax.getLoader( "image1" ).rawContent.bitmapData );
  texture2 = TextureFromBitmapData( LoaderMax.getLoader( "image2" ).rawContent.bitmapData );
  texture3 = TextureFromBitmapData( LoaderMax.getLoader( "image3" ).rawContent.bitmapData );
(...)
}

 
And it works, but I have to write this in every class of my app, not handy if I have to change something... That's why I wanted to create a "LoaderScreen" class, that I call where I need, with some methods to help me to handle all the assets / loaders.

More or less like this:

class LoaderScreen

public function LoaderScreen( loaderId:String ) {
  xmlLoader = new XMLLoader( "xml", { onComplete:loadData } );
  xmlLoader.load();
}

private function loadData( e:LoaderEvent ):void {
  loaderMax = LoaderMax.getLoader( loaderID );
  loaderMax.addEventListener( LoaderEvent.COMPLETE, completeLoader );
  loaderMax.load();
}

private function completeLoader( e:LoaderEvent ):void {
  // nothing here
}

// HELPERS --

public function loadBitmapdata( id:String ):BitmapData {
  return mainLoader.getLoader( "texParticleMenuHome" ).rawContent.bitmapData;
}

 
And now I want to create a LoaderScreen object, and try to load stuff:

class Anywhere

public class Anywhere() {
  var loaderScreen:LoaderScreen = new LoaderScreen( "myID" );
  addChild( loaderScreen );

  texture1 = TextureFromBitmapData( loaderScreen.loadImage( "image1" ) );
  texture2 = TextureFromBitmapData( loaderScreen.loadImage( "image2" ) );
  texture3 = TextureFromBitmapData( loaderScreen.loadImage( "image3" ) );
}

But it returns "null" when I'm not in the "complete" event handler ( LoaderEvent ).
trace( mainLoader.getLoader( "xxx" ) ) in the complete event return something

trace( mainLoader.getLoader( "xxx" ) ) outside, return null

It's a kind of "AssetsManager" I guess ( based on my framework ) but I only need to know how I can load stuff outside the LoaderEvent.

 

If anyone can help me, or have a suggestion...!
Thanks!  ;-)

Link to post
Share on other sites

Hi,

 

Its absolutely possible to create your own re-usable AssetsManager class that taps into LoaderMax. Lots of folks have done it. 

 

I'm having a tough time figuring out what is real code above and what is pseudo-code, so I really don't know what to advise. 

 

For one, I see that class Anywhere is calling loaderScreen.loadImage(), but I don't see that LoaderScreen has such a method. 

 

LoaderScreen does have a loadBitmpaData method, but loadBitmapData references something called mainLoader which I don't see defined anywhere.

 

Again, its just tough to figure out what you need. 

 

The only thing I think I can sort of ascertain is that perhaps you need a way for a class like Anywhere to know when it loaderScreen is done loading. I think you may be trying to access bitmapdata of the child loaders before they are loaded (or something).

 

Even though I can't follow this code fully:

 

 var loaderScreen:LoaderScreen = new LoaderScreen( "myID" );
  addChild( loaderScreen );


  texture1 = TextureFromBitmapData( loaderScreen.loadImage( "image1" ) );
  texture2 = TextureFromBitmapData( loaderScreen.loadImage( "image2" ) );
  texture3 = TextureFromBitmapData( loaderScreen.loadImage( "image3" ) );

it looks like you shouldn't be doing that texture1, texture2 stuff until after loaderScreen is loaded. Just a guess.

 

I'm pretty sure Anywhere() should be listening for ON_COMPLETE events from loaderScreen.

Link to post
Share on other sites

Hello! And thanks for your time!

Sorry for the "pseudo code", I wrote that very quickly, and I don't even realize that I left errors!

 

So yes, the idea is to create a kind of asset manager. A class that create and display a loading screen (with a progress bar), and behind load everything we need through XML and some methods I can call to get assets on my scene.

 

Right now, I repeat the loading stuff in every class (eg: level 1, 2, 3...). You can have a look of this in this video. First I have the "Main Menu" class, when I touch "Play", the main menu fade out, and the "Select World" class, first with the loading screen (which is inside this class) and when it's complete, display the scene: http://youtu.be/yokcjv69JtY?t=38s

 

screen0.jpg

package {

 public class Level1 {

  public function Level1() {

   // Load XML --
   xmlLoader = new XMLLoader ( "PathToTheXML", { onComplete:loadStuff } );
  }

  private function loadStuff( e:LoaderEvent ):void {

   // ProgressBar --
   progressBar = new Sprite();
   addChild( progressBar );

   // LoaderMax --
   loaderMax = LoaderMax.getLoader( "loaderID" );
   loaderMax.addEventListener( LoaderEvent.PROGRESS, loaderProgress );
   loaderMax.addEventListener( LoaderEvent.COMPLETE, loaderComplete );
   loaderMax.load();
  }

  private function loaderProgress( e:LoaderEvent ):void {
   progressBar.scaleX = e.target.progress;
  }

  private function loaderComplete( e:LoaderEvent ):void {
   
   // Clean screen --
   removeChild( progressBar );
   
   // Load stuff --
   texture1 = TextureFromBitmapData( LoaderMax.getLoader( "contentID-1" ) );
   texture2 = TextureFromBitmapData( LoaderMax.getLoader( "contentID-2" ) );

   // Display object on the scene --
   sprite1 = new Sprite( texture1 );
   addChild( sprite1 );
  }
}

Not very handy because if I made a change on the loader, I have to open every class, that's why I want to create a specitif "LoaderScreen". A screen that I can add on top of the scene I want to load, then when to everything is loaded I can call what I need ( images, textures, sounds... ).

So, the main application should looks like this:

screen1.jpg

 

 

So first, I create the LoaderScreen class:

package {

 public function LoaderScreen() {
  xmlLoader = new XMLLoader ( "PathToTheXML", { onComplete:loadStuff } );
 }

 private function loadStuff( e:LoaderEvent ):void {
  
  // ProgressBar --
  progressBar = new Sprite();
  addChild( progressBar );

  // LoaderMax --
  loaderMax = LoaderMax.getLoader( "loaderID" );
  loaderMax.addEventListener( LoaderEvent.PROGRESS, loaderProgress );
  loaderMax.addEventListener( LoaderEvent.COMPLETE, loaderComplete );
  loaderMax.load();
 }

 private function loaderProgress( e:LoaderEvent ):void {
  progressBar.scaleX = e.target.progress;
 }

 private function loaderComplete( e:LoaderEvent:void {
  dispatchEvent( new Event( "LoaderComplete", true, true ) );
 }

 // HELPERS --
 // Call from everywhere to get asset

 public function getAssetIMG( idAsset:String ):BitmapData {
  // Return bitmapdata
  return LoaderMax.getLoader( idAsset ).rawContent.bitmapData;
 }

 public function getAssetATF( idAsset:String ):ByteArray {
  // Return bytearray
  return LoaderMax.getContent( idAsset );
 }
}

Now I can create scenes where I can call the LoaderScreen.
The LoaderScreen will be on top of the scene. So it will display the progress bar, and when it completes, I can remove the LoaderScreen, to see the scene behind:

package {

 public class Level1 {

  public function Level1() {
   
   // Create a LoaderScreen to on top of this scene
   loaderScreen = new LoaderScreen();
   guiLayer.addChild( loaderScreen );

   // I create an EventListener, waiting for the "Complete Event" of the LoaderScreen
   loaderScreen.addEventListener( "LoaderComplete", initScene );   
  }

  private function initScene():void {
   
   // Load stuff through the "getAsset" function --
   texture1 = TextureFromBitmapData( loaderScreen.getAssetIMG( "ID1" ) );
   texture2 = TextureFromBitmapData( loaderScreen.getAssetIMG( "ID2" ) );
   texture3 = TextureFromATF( loaderScreen.getAssetATF( "ID3" ) );

   // Display Object --
   sprite1 = new Sprite( texture1 );
   addChild( sprite1 );

   // Init scene complete --
   guiLayer.removeChild( loaderScreen );
   // Now I can see the scene --
  }
}  

I hop it's a little bit more clean now.
I have my own AssetManager, but I wanted to use GSAP to be more flexible ( can animate the loader / create a TimelineMax for fade In / Out the scene... etc... ). But right now, when I try to call object outside the function loaderProgress( e:LoaderEvent ), it returns an error / null.

Thanks again for your time!

Link to post
Share on other sites

Thank you for the detailed description. It seems like you have a lot of the loading and display of assets working well, you're just stuck on how to make your code more re-usable. 

 

Its very difficult to look at all these lines of codes and different classes and really get an understanding of how everything works together or to imagine what the problem may be. 

 

As much as I think I'm following the code now, I really don't understand what your final question is:

 

But right now, when I try to call object outside the function loaderProgress( e:LoaderEvent ), it returns an error / null.

 

 

What object are you calling and how? Which line of which class is that happening on? Did you comment it somewhere and I am missing it?

Link to post
Share on other sites

Thanks again for your time!

 

Yes, the main problem I have, it's to get content / loader outside the "Complete" event function ( based on LoaderEvent ).

// Init the XML

public function init() {
  xmlLoader = new XMLLoader( "PathToXml", { onComplete:xmlComplete } );
}

// XML Complete -> Now load a LoaderMax that is inside this XML

private function xmlComplete( e:LoaderEvent ):void {
 loaderMax = LoaderMax.getLoader( "LoaderID" );
 loaderMax.addEventListener( LoaderEvent.COMPLETE, loaderComplete );
 loaderMax.load();
}

// LoaderMax Complete -> Get content inside this Loader

private function loaderComplete( e:LoaderEvent ):void {
 dispatchEvent( new Event( "LoaderComplete", true, true );
 trace( loaderMax.getContent( "ContentID" ) ); // return an object - OK
 trace( loaderMax.getContent( "AnotherID" ) ); // return another object - OK
}

// A public function to get content inside the LoaderMax 

public function getContent( contentID:String ):void {
 trace( loaderMax.getContent( contentID ) ); // return null / error
}

So if I put this code in a new class, let say "AssetLoader.as", I can add this everywhere in my game ( assetLoader = new AssetLoader(); ), and when I want a specific content, I just call the "getContent" function ( assetLoader.getContent( "contentID" ), that should return an object I can use... But right now, this function return nothing!

 

Of course, I know that I have to wait until the loading is complete, that's why I dispatch the "LoaderComplete" event. With that I know when the content is loaded and available, but just "how I can acces this content" now from external class!

I hope it will help!
Thanks again!

Link to post
Share on other sites

Well to trouble-shoot I would start by seeing if loaderMax is valid

 

public function getContent( contentID:String ):void {
 trace( loaderMax );
}

Next I would try LoaderMax.getContent()

 

public function getContent( contentID:String ):void {
 trace( LoaderMax.getContent(contentID) );
}

Its a little confusing that you have a LoaderMax called loaderMax (lower l) and you are creating your own getContent() method when LoaderMax.getContent() should find the content of any LoaderMax loader in your app. But still I'm really not seeing exactly is wrong.

 

If you still need help, please create a very simple set of files and upload a zip. We don't need your production files, just enough to compile a swf and instantiate 1 instance of LoaderScreen and see some files load.

Link to post
Share on other sites

Hi!

Yep I think I should started with sources!

 

So here something you can download: Exemple Sources

Run it in debug mode -> everything is explain in the console ( some comments to help ).

 

Thanks again for your time and your help!

Link to post
Share on other sites

First, I must congratulate you on creating the example. Very clever and clear. 

I appreciate all the time you put into all the various traces and comments. Extremely helpful.

 

---

 

It was definitely puzzling that inside getContentFromOutside() I could

trace( "Target: " + loaderMax ); // Ok!
but if I wanted the numChildren it gave me 0!
trace("loaderMax.numChildren ", loaderMax.numChildren); //0

And as far accessing those ImageLoaders inside loaderMax, i got these results:

 

trace( "IMG-1: " + loaderMax.getLoader( "SampleIMG-1" ) ); // Will return null
trace( "IMG-2: " + LoaderMax.getLoader( "SampleIMG-2" ) ); // ImageLoader 'SampleIMG-2' (assets/img-2.jpg)

So LoaderMax.getLoader could find child loaders, but loaderMax.getLoader() could not.

 

Very odd, my next attempt was to remove the delayedCall()

TweenLite.delayedCall(1, getContentFromOutside );

and just call

 

getContentFromOutside() directly from the complete callback.... guess what? it worked!!!

 

loaderMax.getLoader() now worked perfectly as well as loaderMax.numChildren returned 4.

 

But why? delayedCall() shouldn't mess anything up. How can waiting a second cause a difference, especially when loaderMax was still accessible. 

 

Well, try not to punch anything. The problem all along was

 

loaderMax.autoDispose = true;
loaderMax.skipFailed = false;
loaderMax.load();

 

By setting autoDispose true you were getting rid of the child loaders from loaderMax and basically clearing it out and making it eligible for garbage colllection. In other words, if you want to access the loaderMax later on, from another class, don't dispose it. You need to keep it around.

 

The reason why removing the delayedCall worked was because the loader doesn't get disposed until after the onComplete runs. 

 

Hopefully this allows you to move forward with ease.

 

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×