views:

818

answers:

2

I'm writing a preloader:

package {
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.display.LoaderInfo;
    import flash.events.MouseEvent;
    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.system.System;

    public class Preloader extends Sprite {
            private var t:TextField = new TextField();
            private var ver:String = "1000";
            public function Preloader() {
                    t.y = 570;
                    addChild( t );
                    t.text = ver;

                    addEventListener( Event.ADDED_TO_STAGE, init );
            }

            private function init( e:Event ):void {
                    this.root.loaderInfo.addEventListener( ProgressEvent.PROGRESS, onLoadingProgress );
                    this.root.loaderInfo.addEventListener( Event.COMPLETE, onLoadingCompleted );

                    // See if it's already completed
                    var percent:int = int( root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal );
                    if ( percent == 1 )
                            onLoadingCompleted();
            }

            private function onLoadingProgress( event:Event ):void {
                    var percent:int = int(root.loaderInfo.bytesLoaded / root.loaderInfo.bytesTotal * 100);
                    t.text = "Loading.. " + percent + "%";
            }

            private function onLoadingCompleted( event:Event = null ):void {
                    root.loaderInfo.removeEventListener( ProgressEvent.PROGRESS, onLoadingProgress );
                    root.loaderInfo.removeEventListener( Event.COMPLETE, onLoadingCompleted );

                    var mainClass:Class = loaderInfo.applicationDomain.getDefinition("Main") as Class;
                    var main:DisplayObject = new mainClass() as DisplayObject;

                    parent.addChild( main );
                    parent.removeChild( this );
            }
    }
}

with this as the Main class:

package {
    import flash.display.Sprite;

    public class Main extends Sprite {

            public function Main() {
            }
    }
}

so this is close to as barebones as I could make it.

However, it greets me with a:

ReferenceError: Error #1065: Variable Main is not defined.
at flash.system::ApplicationDomain/getDefinition()
at ...

I use frames.frame to insert Main already. I am compiling using ant and the linux SDK directly (mxmlc). Am I missing anything obvious?

+1  A: 

Is it any different if you have the Game class in the default package("Game" instead of "game.Game") ?

I've never used anything like new mainClass( this.root ), new mainClass() should be fine.

Also, is there any difference if you use Event.INIT instead of Event.COMPLETE ?

George Profenza
Moving the package = same result.I'm passing in the root as a variable to the class (so I can read the flashvars)Event.INIT didn't change anything.Thanks.
Timmy
is class Game public ? Also, is this handy : http://www.kirupa.com/forum/showthread.php?t=274871 ?
George Profenza
Ya, it's public. I find that if I added a button or a timer it seems to find it. It's almost as if it fires the events before it is actually ready..
Timmy
Thanks for the link, but no go.. =(
Timmy
+2  A: 

When you're making a preloader in this "style" what really happens is that the preloader is put in the first frame of the application, and the rest in a second frame. What you're missing here is to tell the compiler that you want your Main class compiled in, so right now it doesn't even exist in the swf. That's why getDefinition won't work.

Nor can you simply refer to it in the preloader since that would make it load in the first frame before the preloader can be shown. So, you need a little custom argument magic.

Add this line to your compiler options and you should be good to go:

-frame start Main

Remember that if your Main class is in a package you need to get a full reference in there:

-frame start com.grapefrukt.examples.Main

Same goes for the getDefinition call.

EDIT:

When looking over my code that does this I see that I use a different approach from what you did, maybe this works better:

var mainClass:Class = getDefinitionByName("com.grapefrukt.examples.Main") as Class;
addChild(new mainClass() as DisplayObject);

EDIT AGAIN: If it works using a button I'd guess the complete event is fired too early for some reason. It may be so that everything is not inited properly event though all the bytes are loaderd. Try using this code to check for completion instead:

if (currentFrame == totalFrames) onLoadingCompleted()

It might also be a good idea to add a stop() command in your onLoadingCompleted() method just to make the playhead won't be screwing things up, but that's a later issue really.

grapefrukt
Cool! I didn't know that. I hope this solves Timmy's question
George Profenza
I already do this, unfortunately. I wasn't clear when I said "I use frames.frame to insert Main".
Timmy
okay, i added another suggestion, does that help?
grapefrukt
Nope, no luck. I wonder if there's some sort of timing thing involved - I added a "start" button with an onclick and it worked every time. Still trying to avoid going that route though, and the above is pretty much as simple as I can make it.
Timmy
The code also appears to work in FlashDevelop, but not when I do it straight from mxmlc. Odd.
Timmy
Ya, I was thinking the same thing. I rewrote it (as a MovieClip) and checking for frames and it seems to work okay now. Thanks!
Timmy