New Updated Tools/Classes For Actionscript 3

Button
Calculating Frames Per Second [and memory usage]
MultiLoader
Example and Project Source

I’ve created a number of tools for people to use in the past, most of which I update regularly. In this post I’d like to revisit some of my old classes and post new updated code for those classes, as in their current form they don’t much represent my coding style. Please note that my class hierarchy has also changed, so make sure to update your includes if you are using these in your projects.

Button
I posted code for a button class here ->here about a year ago, since then I’ve changed things and really cleaned up that class. It’s simpler than before and faster. Given one to three images this class will create a clickable button that has the option to trigger up to four functions [on roll over, mouse down, mouse up and roll out]. Here is a snippet showing its use:

        var button:Button = new Button();
       
        // bitmapData of buttons "up" state
        var bmd_up:BitmapData = new BitmapData(50, 20, true, 0xFFBDE052);
        // bitmapData of buttons "over" state
        var bmd_over:BitmapData = new BitmapData(50, 20, true, 0xFF52C4E0);
        // bitmapData of buttons "down" state
        var bmd_down:BitmapData = new BitmapData(50, 20, true, 0xFFFFAF1A);
       
        button.x = 20;
        button.y = 20;
        // we pass our bitmapData to the button, one for each state. if only one bitmapData is supplied, it will be
        // copied to each state, after which each new bitmapData supplied will replace the first for the state
        // specified.
        button.up = bmd_up;
        button.over = bmd_over;
        button.down = bmd_down;
       
        // we supply functions to the buttons function references, if no functions are supplied, no functions will be called.
        button.overFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button over");};
        button.downFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button down");};
        button.upFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button up");};
        button.outFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button out");};
       
        addChild(button);
       
        // adding a label is as simple as creating a textfield and adding it to the button.
        var label:TextField = new TextField();
            label.textColor = 0xDDD4F7;
            label.mouseEnabled = false;
            label.text = "Button";
            label.autoSize = "left";
            label.x = button.width/2 - label.width/2;
            label.y = button.height/2 - label.height/2;
           
        button.addChild(label);

Calculating Frames Per Second
The next class I’d like to revisit is my FPS counter. It’s basically a textfield that displays an instantaneous fps count, and an averaged count. I have now removed the average frames per second and included a display of used memory in MB. Before I had used a timer to calculate the fps, which wasn’t quite accurate enough. Now the class uses flash.utils.getTimer() and is very precise and accurate. The class extends TextField so custom coloring, etc is very straightforward:

        var fps:FPSBox = new FPSBox();
        addChild(fps);

MultiLoader and MultiLoaderEvent
The next entry is a class created for downloading and importing files from your server or local file system into your flash application. It is what I use in place of my Multiple Bitmap Loader and my Bitmap Resource Handler. MultiLoader extends Loader to support multiple asynchronous downloads of images/swfs. They trigger specific (read “specially named”) ProgressEvents based on the names of entries supplied by you in their load functions. Alternatively, they also trigger a MultiLoaderEvent for every ProgressEvent or complete Event dispatched. One can access the bytesLoaded and bytesTotal for each event, as well as the entry name of the event (which matches the entry name given to MultiLoader). For example, to load a gif and listen to progress and complete events, code the following:

        var multiLoader:MultiLoader = new MultiLoader();
            multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx");
                       multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");
            multiLoader.addEventListener("efnx_Progress", efnxProgress, false, 0, true);// specially named
            multiLoader.addEventListener("efnx_Complete", efnxComplete, false, 0, true);// specially named
               multiLoader.addEventListener("progress", progress, false, 0, true);// will trigger a MultiLoaderEvent with an entry member for identification
               multiLoader.addEventListener("complete", complete, false, 0, true);

    private function efnxProgress(event:ProgressEvent):void
    {
        trace("UpdatedTools::efnxProgress()", (event.bytesLoaded/event.bytesTotal*100));
    }
    private function efnxComplete(event:ProgressEvent):void
    {
        trace("UpdatedTools::efnxComplete()");
    }
    private function progress(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::progress()", event.entry, (event.bytesLoaded/event.bytesTotal*100));
    }
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()", event.entry);
    }

In this example my entry name is “efnx” and so MultiLoader triggers events of type “efnx_Progress” and “efnx_Complete”. By listening for these events, we can get updated information about our downloads. Another option is to listen for “progress” and “complete,” which will trigger an event of type MultiLoaderEvent, which extends ProgressEvent to include an “entry” member. The value of event.entry will be the name of the entry triggering the event, in this case “efnx.” Now to use our images we “get” the resource from MultiLoader, which has been storing it for us. A great feature of this class is being able to specify what the return type of your loaded object when calling the “get” function. Here I’m going to want to return a Bitmap object, so for the third parameter of the “load” function I’ll pass the string “Bitmap”. Here’s an example:

multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");

Now inside my efnxComplete function I’ll add the get function to get my Bitmap and display it.

        // if we are listening for "efnx_Complete"
    private function efnxComplete(event:Event):void
    {
        trace("UpdatedTools::efnxComplete()");
        var efnxBitmap:Bitmap = multiLoader.get("efnx");
            efnxBitmap.x = button.x + button.width + 10;
            efnxBitmap.y = button.y;
        addChild(efnxBitmap);
    }
        // or if we are listening for "complete"
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()");
        var efnxBitmap:Bitmap = multiLoader.get(event.entry);
            efnxBitmap.x = button.x + button.width + 10;
            efnxBitmap.y = button.y;
        addChild(efnxBitmap);
    }

Using the third parameter of the load() function is optional and if omitted Multiloader will by default choose an appropriate return type, here is a list of the valid strings to pass as a return type:

MovieClip
Sprite
Bitmap
BitmapData

If no third parameter is supplied, MultiLoader will return a type it thinks is appropriate, given the extension of the loaded material. For example loading a .swf will return a MovieClip, where as loading a .jpeg, .png or .gif will return a BitmapData.

Example App and Project Source
Here is a project that shows all three updated classes being used:

package {

    import flash.events.Event;
    import flash.events.ProgressEvent;
    import flash.display.Sprite;
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.text.TextField;
   
    import efnx.gui.Button;
    import efnx.time.FPSBox;
    import efnx.net.MultiLoader;
    import efnx.events.MultiLoaderEvent;
   
/**
 *  Application entry point for UpdatedTools post.
 *
 *  @langversion ActionScript 3.0
 *  @playerversion Flash 9.0
 *
 *  @author Schell Scivally
 *  @since 18.08.2008
 */

public class UpdatedTools extends Sprite {
   
    public static const testing:Boolean = false;
   
    public var button:Button = new Button();
    public var multiLoader:MultiLoader = new MultiLoader();
   
    /**
     *  @constructor
     */

    public function UpdatedTools()
    {
        super();

        stage.frameRate = 30;
        stage.scaleMode = "noScale";
        stage.align = "TL";
        stage.addEventListener("resize", resize, false, 0, true);
       
        // bitmapData of buttons "up" state
        var bmd_up:BitmapData = new BitmapData(50, 20, true, 0xFFBDE052);
        // bitmapData of buttons "over" state
        var bmd_over:BitmapData = new BitmapData(50, 20, true, 0xFF52C4E0);
        // bitmapData of buttons "down" state
        var bmd_down:BitmapData = new BitmapData(50, 20, true, 0xFFFFAF1A);
       
        button.x = 20;
        button.y = 20;
        // we pass our bitmapData to the button, one for each state. if only one bitmapData is supplied, it will be
        // copied to each state, after which each new bitmapData supplied will replace the first for the state
        // specified.
        button.up = bmd_up;
        button.over = bmd_over;
        button.down = bmd_down;
       
        // we supply functions to the buttons function references, if no functions are supplied, no functions will be called.
        button.overFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button over");};
        button.downFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button down");};
        button.upFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button up");};
        button.outFunction = function():void{trace("UpdatedTools::UpdatedTools()", "button out");};
       
        addChild(button);
       
        // adding a label is as simple as creating a textfield and adding it to the button.
        var label:TextField = new TextField();
            label.textColor = 0xDDD4F7;
            label.mouseEnabled = false;
            label.text = "Button";
            label.autoSize = "left";
            label.x = button.width/2 - label.width/2;
            label.y = button.height/2 - label.height/2;
           
        button.addChild(label);
       
        var fps:FPSBox = new FPSBox();
        addChild(fps);
       
        MultiLoader.testing = true;
        MultiLoader.usingContext = true;
       
        multiLoader.load("http://www.efnx.com/images/experiment.gif", "efnx", "Bitmap");
        multiLoader.load("http://www.efnx.com/images/808.jpg", "808", "Sprite");
        multiLoader.addEventListener("progress", progress, false, 0, true);
        multiLoader.addEventListener("complete", complete, false, 0, true);
    }
   
    private function progress(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::progress()", event.entry, ": ", (event.bytesLoaded/event.bytesTotal*100));
    }
    private function complete(event:MultiLoaderEvent):void
    {
        trace("UpdatedTools::complete()");
        switch(event.entry)
        {
            case "efnx":
                var efnxBitmap:Bitmap = multiLoader.get("efnx");
                    efnxBitmap.x = button.x + button.width + 10;
                    efnxBitmap.y = button.y;
                addChild(efnxBitmap);
                break;
            case "808":
                var sprite808:Sprite = multiLoader.get("808");
                    sprite808.x = button.x;
                    sprite808.y = button.y + button.height + 20;
                addChild(sprite808);
                break;
            default:
        }
    }
   
    /**
     *  Resize stub.
     */

    private function resize(event:Event):void
    {
        if(testing) trace( "UpdatedTools::resize()" );
    }
   
}

}

And here is the source to my classes:
Example Project and Source [includes classes]

Here is a little example:
updatedExample

And as always you can find the classes by themselves [along with all my other classes] here efnx AS3 classes, as well as some limited documentation efnx Class Documentation

Tags: , , ,

17 Responses to “New Updated Tools/Classes For Actionscript 3”

  1. [...] class has been updated and a new post has been made, click here for that [...]

  2. [...] now using a new class for this task which can be found here. That said, feel free to read on about this outdated [...]

  3. [...] A new updated class has been posted here, but feel free to keep reading about this old class. [...]

  4. Hi, nice work with the MultiLoader class. Is there a clever easy way to load an array of images without having to write separate ‘complete’ functions for each one?

  5. Hey Andy, I just edited my post after including some options for you, hope it helps, thanks!

  6. Awesome stuff, I was looking for a button class like this.

    side note: your archive contains those crazy hidden mac osx files, headache to clean for a windows user.
    http://www.sopht.jp/en/cleanarchiver/

  7. Thanks, and yes I bet that is very annoying. I know the feeling, I always find thumbs.db in files rar’d by a windows box.

  8. Thanks!
    (I was looking for a neat class to show the amount of FPS)

  9. Hi there, I can’t seem to access your updated FPS class? Am I doing something wrong or is the link to the new source missing?

  10. There’s an anchor at the top of the page that should show you the link to the source at the bottom of the post, and here it is just to make sure. Source tar gz

  11. This class is awesome great stuff. I have one question on your previous button class you seem to use an Array of images however in this new Button class you seem to use BitmapData(). How would you insert an image in place of the BitmapData() for each state?

  12. Mike – first you would have to get your images as Bitmaps, either through use of a Loader (and the ‘load’ method), or by embedding the images in your project. Then just pass the bitmaps to the button class (as in lines 55 – 57).

  13. FYI In your FPSBox class if you don’t add it to the display list right away the results are inaccurate because the enter frame has not been counting the frames up until it was added. You can compensate for this by subtracting the offset since the moment the enter frame started but if you don’t recreate it each time you need it then it will again be inaccurate. This is not a problem you’d typically run into but if you are adding and removing the FPSBox arbitrarily you will need to do all of these things to keep it accurate.

  14. Thanks Judah, I had not run into that problem yet. Good catch ;)

  15. Hello,
    Thank you very much for sharing the way you count fps’s.
    it’s definately going to help me with my bitmap rendering intensive unoptimized game !

    FPSBox.as line:73
    text = int(frame/time) + ” FPS, ” + Number(System.totalMemory/1000000).toPrecision(3) + ” MB”;
    should be
    text = int(frame/time) + ” FPS, ” + Number(System.totalMemory/1048576).toPrecision(3) + ” MB”;
    shouldn’t it?
    :D

  16. Hey gsynuh – thanks, and I think it depends on whether or not you’re measuring Megabytes or Mebibytes, right? Either way at this point these classes are very outdated.

  17. [...] 將FPSBox物件加到場景 就可以觀查fps 下載:Calculating Frames Per Second 說明:AS3 – Calculating true Frames Per [...]

Leave a Reply


Follow me on GitHub
Follow me on Google+
Follow me on Twitter
Thrilling.
EFNX is proudly powered by WordPress
Entries (RSS) and Comments (RSS).