External Preloader; more complex cases

In my previous post I spoke about what would be my optimal external preloader, but I really covered only simple examples. In relations to external preloaders, there are 2 cases where it gets more complex. First, when you want to time you preloader’s animation with your main content’s animation and second, when you use FlashVars (variables passed from the HMTL to the SWF).

Timing a preloader animation with the main content animation

Sometimes you don’t want to start the loaded content as soon as it’s been loaded.  You want to leave time for the preloader’s exit animation to end or you want to morph your preloader with the main content to have some sort of continuity. In those cases, the external preloader has to call a method of the main content. That sounds simple but it actually isn’t. If you try to call a method directly like we used to do in ActionScript 2 the compiler will complain because it doesn’t know if the loaded content will have such a method. In order to solve this problem you will have to use interfaces. You can get more information about interfaces on this previous post of mine. Now that the loaded content is typed to an interface you will be able to call it’s method and the synchronization between the preloader and the content will be good.

Using FlashVars

FlashVars are really useful and a lot of times you might end up using them. The problem is that contrarily to ActionScript 2, in AS3 the root variable will refer to this SWF’s root, not to the entire application’s root. So from the loaded content you don’t have access to the FlashVars. You solve this problem the same way as we solved the preceding problem: by using an interface. In the first case, we mostly would have called a method without parameters like init() or something like that, but in this case the parameters will be the FlashVars. You might want to pass the root.loaderInfo.parameters.YOUR_VAR_NAME as a parameter or you might want to do some checking as to know if the parameter was passed or not. In your interface you will have to write down all the parameters you want to pass and what type (String, int, Number, etc) they are. Here is an example of how you could do it.

Here is the interface:

package com.zedia.interfaces{
  public interface IMain{
    function init(flashvars1:String, flashvars2:Number):void;
  }
}

Here is some of the code of that the preloader could contain:

import com.zedia.interfaces.IMain;
 
var mainContent:IMain;
function onLoadComplete(event:Event):void{ // this would be the function that the loader would call when the loading is completed
  mainContent = IMain(loader.content);
  addChild(Sprite(mainContent) );
  mainContent.init( String(root.loaderInfo.parameters.flashvars1),Number(root.loaderInfo.parameters.flashvars2) )
}

Here is some code of the loaded content:

package{
  import com.zedia.interfaces.IMain;
 
  public class Main extends Sprite implements IMain{
    public function init(flashvars1:String, flashvars2:Number):void{
      //do something with the FlashVars
    }
  }
}

As you can see in the preloader’s ActionScript, in order to add the content to the stage, you first have to cast it to Sprite. You will have to do this when you will want to have access to Sprite properties like x and y. I admit this is a down side of using interfaces but at the same time it solved both the problems of timing an animation and passing FlashVars to the loaded content.

, , , ,

  1. #1 by Tyler Egeto - September 22nd, 2008 at 23:37

    Good post. It brings up one of my biggest irritations with Flash, interfaces allow us to give an object multiple data types (super powerful) but once we store it, it “forgets” that it actually belongs to both, as shown in your example where it needs to be re-type cast to access all the the methods/properties available on it. I’m sure there are low level issues with it, but I would love for that to change.

  2. #2 by zedia.net - September 23rd, 2008 at 13:09

    Ya when you use both an extends statement and an implement statement, if you cast your object as the interface, the object doesn’t know that it extends something so you have to type-cast it all the time. I don’t know how this is handled in other programming languages.

  3. #3 by sideDoor - January 23rd, 2009 at 20:18

    Hey Zedia,

    Couple of things:

    1. Questions: I’m still not clear why and how the interface functions in this example…I can get it to work no problem…but why is it necessary to use the interface in this case? Why must the Main class implement the IMain interface so that the init() method is available to be called the preloader? Why can’t we just call the init() method of the Main class directly?

    Again, I know that it won’t work to call methods of Main class from the preloader, but why?

    2. Instead of hard coding individual flashvar parameters in your call to the init() method of the Main class as illustrated above in the preloader.fla code, like this:

    mainContent.init( String(root.loaderInfo.parameters.flashvars1),Number(root.loaderInfo.parameters.flashvars2) )

    You could dynamically pass any number of flashvars by passing the parameters object like this:

    // preloader.fla MainTimeline frame 1…
    mainContent.init(Object(root.loaderInfo.parameters));

    Then, in your Main document class init() method, parse the object as an associative array, which I suppose is what the parameters object is, like this:

    // Main document class…
    public function init(flashvars:Object):void
    {
    var keyStr:String;
    var valueStr:String;
    for (keyStr in flashvars) {
    valueStr = String(flashvars[keyStr]);
    trace(“key-> ” + keyStr + ” value-> ” + valueStr);
    }
    // or however you need to use the flashvars, etc
    }

  4. #4 by zedia.net - January 26th, 2009 at 12:26

    @sideDoor
    Since the preloader doesn’t know anything about Main, it will throw you an error when you will try to use the init() method. Now, there are two ways you can give the compiler knowledge about Main; using an interface or importing the Main class directly.

    By importing the Main class you will encounter these two problems.

    1- If you used Flash to create symbols that are on the stage, or Textfield using the tools and not Actionscript, the compiler won’t be able to compile since it won’t find classes for those symbols.

    2- If you created everything with Actionscript, well importing Main in your preloader will add all the weight of Main to that of your preloader thus defeating the purpose of a preloader.

    By using an interface you tell the compiler only what it needs to know to be happy, it will only know the methods it can use without importing everything.

    Now for your second question, I prefer to pass my Main my Flashvars individually, but I guess this is a question of preferences.

  5. #5 by Randy Olson - May 22nd, 2009 at 03:09

    I’m having issues where I have a logo in my preloader that animates. Once its done preloading I want to use the logo as a screen asset in my main swf movie. I’m using a document class for my main swf (Don’t know if that makes a difference)

    I setup the interface okay and implemented it in my main class. The problem is I have a registerAsset() function that I want to register the logo in my preloader to a variable in my main swf so I can move it around the stage etc. I’m getting errors saying it can’t access properties of a null object. Is it clear what I’m trying to do? I basically want my main content to gain control of the logo in my preloader.

  6. #6 by Randy Olson - May 22nd, 2009 at 03:17

    Ahhh…nevermind now…I think I got it working.

    I learned that up in my var declaration I had
    private var myClip:MovieClip

    -instead I needed-

    private var myClip:MovieClip = new MovieClip();

    That way all my references to ‘myClip’ like tweens of properties would compile correctly. Now if I can just get the main swf to wait for my preloader to stop animating I’ll be in good shape. Thanks…this was a helpful article

  7. #7 by Randy Olson - May 22nd, 2009 at 03:27

    Okay so once I have the logo “registered” as an object my main movie can control…how do I addEventListeners to it? I have some functions setup to add and remove eventlisteners from the logo?

  8. #8 by Randy Olson - May 22nd, 2009 at 03:44

    Nevermind…got that working as well.

    Had to change myLogo.mouseChildren = false

    Man I’m on FIRE tonight :)

  9. #9 by Randy Olson - May 22nd, 2009 at 03:56

    I will say that I need help getting my preloader to play all the way out before my main movie displays.
    I’m going to bed. Suggestions are welcome! :)

  10. #10 by Pascal - July 25th, 2009 at 10:11

    Hi, thank you for the great tutorials, but I have a question. I need some clarification about how exactly to use interfaces for the exit animation of an external preloader, and what method is to be called from the loaded swf?

  11. #11 by Hadi - August 26th, 2009 at 13:18

    Zedia, Thanks. I love all your articals relating to interfaces :) you reall made me going on…

  12. #12 by Visco - September 18th, 2009 at 07:20

    Communication between 2 flash applet? Local Connection…that’s it.

  13. #13 by jvc - October 6th, 2009 at 23:50

    Also as long as the child swf has been added to the stage you can also get to the flashvars from a child swf with

    this.stage.root.loaderInfo.parameters

  14. #14 by Joni - January 20th, 2010 at 08:23

    @jvc
    It depends where you add the child object.
    If you add the child directly to the stage, like this:
    stage.addChild(child);
    child.root, or child.stage.root gives you a reference to the Stage, which doesn’t have the LoaderInfo available.

    You should add the child to the Document Class instance.
    child.stage.root will give you a Stage reference, which doesn’t have the LoaderInfo.
    But child.root will have a reference to the Document Class instance (or Main class), which does have the LoaderInfo available.

    So the correct (and only) way of getting the root.loaderInfo property is to add the child to the Main class instance (or to any child of it) and use the following: root.loaderInfo.

  15. #15 by Eelco - February 7th, 2010 at 17:46

    I am getting an error if I use this code in the preloader:

    TypeError: Error #1034 Type Coercion failed: cannot convert flash.display::MovieClip@8d56c4 to IMain.

  16. #16 by Robert Good - August 23rd, 2010 at 07:53

    Zedia,
    Thank you for this tutorial. I am having the same issue as Eelco above.

    TypeError: Error #1034: Type Coercion failed: cannot convert AppLoader_vartest__Preloader__@28a1f21 to classes.util.interfaces.IMain.

    It bugs out at mainContent=Imain(loader.content);

  17. #17 by oscar - August 10th, 2012 at 12:34

    Self error to me:

    Robert Good : Zedia,
    Thank you for this tutorial. I am having the same issue as Eelco above.
    TypeError: Error #1034: Type Coercion failed: cannot convert AppLoader_vartest__Preloader__@28a1f21 to classes.util.interfaces.IMain.
    It bugs out at mainContent=Imain(loader.content);

(will not be published)
Subscribe to comments feed