Search code examples
actionscript-3flashflashdevelop

synchronous image loading action script 3 flash


I am having a problem with my flash/as3 application. I've created most of it and at the moment I'm struggling to get my external resources work.

My application consists of a Controller class, that takes control of an application flow. At the beginning it initializes AppInitializer class, that loads / generates the whole app content (it is a simple point'n'click game).

In AppInitializer I create an array of items available in a game. Item's constructor takes path as a parameter (String) to the resource (image). Then, inside the constructor I call a static method of my AssetsLoader class which looks like that:

public static function loadImage(path:String):BitmapData
    {
        completed = false;
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event){completed = true;
        trace("Loading completed");
        e.target.removeEventListener(Event.COMPLETE, check);});
        if (path == "")
            loader.load(new URLRequest("images/default.png"));
        else
            loader.load(new URLRequest("images/" + path));
        //while (!completed);
        var image:Bitmap = new Bitmap((loader.content as BitmapData));
        return image.bitmapData;
    }

Where completed is a static variable of AssetsLoader.

First problem is: I create many Item objects in a row, so the method loadImage should not be static I guess (same with completed variable), since that may cause problems when loading.

Second problem is: At the moment I'm unable to return the bitmapData (or bitmap, it does not really matter), because the return statement will always return null - because the resource is loaded asynchronously and is not loaded at the time application reaches return statement. If I uncomment the wile loop, the complete event is never called.

I would like to ask more experienced ActionScript developers to point out any solutions that would require minimal changes to the rest of my app and would solve those problems. (I think first problem can be eliminated by using some sort of queueing method for the loader, but I'm stuck with the second problem for few days so far and came up with no possible solution).

I could also consider changes in my logic, so I could preload all image resources into "somewhere" and after that just make copies of these images for my purposes. If that's easier to do.


Solution

  • So as I suggested in the comments, a minimal change resolution could simply be to pass a function to call as part of the parameters for loadImage(). This is known as a callback function, and it would look something like this:

    First create the callback function:

    public function addImage( bitmapData:BitmapData ):void {
        //do something with the bitmapData returned
    }
    

    Next adjust your loadImage() local function to use the callback with the bitmap data when the event has completed:

    public static function loadImage(path:String, callback:Function):BitmapData {
        completed = false;
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event){completed = true;
        trace("Loading completed");
        var image:Bitmap = new Bitmap((loader.content as BitmapData));
        callback( image ); //call the callback with the bitmap
        e.target.removeEventListener(Event.COMPLETE, check);});
        if (path == "")
            loader.load(new URLRequest("images/default.png"));
        else
            loader.load(new URLRequest("images/" + path));
    }
    

    Then just you make the call to loadImage() like so:

    loadImage( myPathToImage, addImage );
    

    That is a simply resolution and does exactly what you need it to.