Archive for the ‘AS3’ Category

AS3 Bitmap Resource Manager

Saturday, December 1st, 2007

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

I’ve completely rewritten my multiple bitmap loader into a new machine. It now uses weak referenced dictionary objects to store bitmapData after it has been extracted or loaded from the web. It is meant to hold all instances of bitmapData for a class, a set of classes or a whole game even. The class, bitmapDataRsrc, takes either a bitmap, bitmapData or string path to an image or an array consisting of either bitmaps, bitmapData, string paths, or some combination thereof, along with a string identifier and loads the bitmapData into a dictionary object with it’s identifier as a key. It then pushes it’s load status [true or false] into another dictionary with the object itself as the key, so every bitmapData resource and it’s load status is accessible through the identifier. Once every resource is loaded bitmapDataRsrc dispatches an Event.COMPLETE event. For instance, let’s say I wanted to load and store all the bitmapData needed to build a GUI window:

import com.efnx.utils.bitmapDataRsrc;

var rsrc:bitmapDataRsrc = new bitmapDataRsrc();

rsrc.addEventListener(Event.COMPLETE, attachGraphicElements, false, 0, true);

//load resources///////////////////////
    rsrc.load("rsrc2/bottomBar.png", "bottomBar");
    rsrc.load("rsrc2/contentBG.png", "contentBG");
    rsrc.load("rsrc2/contentOverlay.png", "contentOverlay");
    rsrc.load("rsrc2/leftArrowDown.png", "leftArrowDown");
    rsrc.load("rsrc2/leftArrowOver.png", "leftArrowOver");
    rsrc.load("rsrc2/leftArrowUp.png", "leftArrowUp");
    rsrc.load("rsrc2/upArrowDown.png", "upArrowDown");
    rsrc.load("rsrc2/upArrowOver.png", "upArrowOver");
    rsrc.load("rsrc2/upArrowUp.png", "upArrowUp");
    rsrc.load("rsrc2/rightArrowDown.png", "rightArrowDown");
    rsrc.load("rsrc2/rightArrowOver.png", "rightArrowOver");
    rsrc.load("rsrc2/rightArrowUp.png", "rightArrowUp");
    rsrc.load("rsrc2/downArrowDown.png", "downArrowDown");
    rsrc.load("rsrc2/downArrowOver.png", "downArrowOver");
    rsrc.load("rsrc2/downArrowUp.png", "downArrowUp");
    rsrc.load("rsrc2/leftBar.png", "leftBar");
    rsrc.load("rsrc2/leftBottomCorner.png", "bottomLeftCorner");
    rsrc.load("rsrc2/MbuttonDown.png", "MbuttonDown");
    rsrc.load("rsrc2/MbuttonOver.png", "MbuttonOver");
    rsrc.load("rsrc2/MbuttonUp.png", "MbuttonUp");
    rsrc.load("rsrc2/ObuttonDown.png", "ObuttonDown");
    rsrc.load("rsrc2/ObuttonOver.png", "ObuttonOver");
    rsrc.load("rsrc2/ObuttonUp.png", "ObuttonUp");
    rsrc.load("rsrc2/resizeDown.png", "resizeDown");
    rsrc.load("rsrc2/resizeOver.png", "resizeOver");
    rsrc.load("rsrc2/resizeUp.png", "resizeUp");
    rsrc.load("rsrc2/rightBar.png", "rightBar");
    rsrc.load("rsrc2/rightBottomCorner.png", "bottomRightCorner");
    rsrc.load("rsrc2/hBarLeft.png", "hBarLeft");
    rsrc.load("rsrc2/hBarMiddle.png", "hBarMiddle");
    rsrc.load("rsrc2/hBarRight.png", "hBarRight");
    rsrc.load("rsrc2/vBarBottom.png", "vBarBottom");
    rsrc.load("rsrc2/vBarMiddle.png", "vBarMiddle");
    rsrc.load("rsrc2/vBarTop.png", "vBarTop");
    rsrc.load("rsrc2/windowBarLeft.png", "upperLeftCorner");
    rsrc.load("rsrc2/windowBarMiddle.png", "topBar");
    rsrc.load("rsrc2/windowBarRight.png", "upperRightCorner");
    rsrc.load("rsrc2/XbuttonDown.png", "XbuttonDown");
    rsrc.load("rsrc2/XbuttonUp.png", "XbuttonUp");
    rsrc.load("rsrc2/XbuttonOver.png", "XbuttonOver");

After the resources are done loading you can access the bitmapData using the get() function with the string identifier [2nd parameter] passed with the load() function. Below I’ll demonstrate accessing the last bitmapData, XbuttonOver.png.

function attachGraphicElements(event:Event):void
{
     var bitmap:Bitmap = new Bitmap();
     bitmap.bitmapData = rsrc.get("XbuttonOver");
     addChild(bitmap);
}

If you get lazy and decide not to give bitmapDataRsrc string identifiers to identify your resource, it will make one up for you. If you decide to pass an array of bitmaps, bitmapData and string paths to images as the first parameter to the load() function, and pass a string identifier as the second parameter your resources will be indexed as “string identifier + number” so that all your resources are accessible. When passing an array of resources you can identify each one yourself by first indexing the resource and string identifier in another array and then pushing that array into the parameter array. In this case a second parameter to the load function is not needed. Check it out:

import com.efnx.utils.bitmapDataRsrc;

var rsrc:bitmapDataRsrc = new bitmapDataRsrc();
var array:Array;
var string:String;

for(var i:int = 0; i<100; i++)
{
    string = "image"+i;
    array = new Array();
    array.push("rsrcPath"+string+".png", string);
}

rsrc.load(array);

I find it a lot easier to load resources one by one and name them, it’s a lot better for me, I like to get to know my bitmapData, but it’s good to have options.

The isLoaded property can be checked to find out if all resources have loaded. At any point the load status of a single resource can be found by calling the hasLoaded(“string identifier”):Boolean function. If no identifier is given bitmapDataRsrc returns it’s isLoaded property. To destroy a given resource call unload(“string identifier”) and to destroy all resources in the manager call unloadAll():

trace(rsrc.isLoaded);
trace(rsrc.hasLoaded("XbuttonOver");
rsrc.unload("XbuttonOver");
rsrc.unloadAll();

Source
bitmapDataRsrc Source

Quake for Flash (C/C++ to AS3)

Tuesday, November 27th, 2007

Scott Peterson has created a tool for porting C/C++ code to AS3. What the shit. That rocks. This demo was shown at the 2007 Adobe MAX conference, in the sneak peeks section, so keep in mind it may never see the light of day. But how cool is this? Adobe better jump on this.

AS3 Button Class

Sunday, November 25th, 2007

This class has been updated and a new post has been made, click here for that post.

Also known as “Developing a Pure AS3 GUI – Part 2 (buttons)”

Buttons are extremely important in a GUI. Buttons don’t have to be fancy to be useful, they just have to execute some function when clicked. Although, seeing as this is a button class for AS3 and AS3 is the language of Flash and Flash is by it’s namesake, “flashy,” this class is somewhat “fancy” beyond the utility of a simple button. Don’t be discouraged if you’re looking for an easy implementation, by no means is this class complicated, it just goes further than binding a Sprite to a function using a CLICK event listener…

My button class requires three images to function: an “up” image [the default resting image], an “over” image [the image shown on mouse over] and a “down” image [the image shown when clicked upon]. After creating the three images and placing them in some directory next to your .fla you can instantiate the button by giving it an array consisting of three image paths that lead to your images. Additional parameters are a function to be performed on click and whether or not the button is a toggle button.

Usage

var myButton:button = new button(new Array("image1.png", "image2.png", "image3.png"), onClick, false);
     addChild(myButton);

function onClick():void
{
     trace("button has been clicked");
}

And that’s it. If you’d like the button to run in toggle mode just pass true as the third parameter.

Source
button Class Source Code

Multiple Bitmap Loader in AS3

Sunday, November 25th, 2007

To aid in my projects I have written a simple bitmapData loading class entitled aquireResources. This class takes an array of image paths as strings and proceeds to load them one by one. A “complete” event is dispatched when loading is completed and the bitmapData of each loading instance are saved in an array in the order they were given. Calling the aquireResources.array() method returns the array of bitmapData. If you’ve already downloaded Thibault Imbert (bytearray.org)’s GIFPlayer and GIFDecoder classes you can uncomment the included properties and methods in my class and enable the aquireResources class to load multiple instances of animated GIFs into AS3 as arrays of bitmapData. In this case aquireResources.array() returns a two-dimensional array containing one array of bitmapData per animated GIF passed to it.

Usage

import com.efnx.utils.aquireResources;

var rsrc:aquireResources = new aquireResources();
     rsrc.addEventListener("complete", onComplete, false, 0, true);

var array:Array = new Array("imagePath1/image1.png", "imagePath2/image2.gif", "imagePath3/image3.jpeg");
var bitmapDataArray:Array;
function onComplete(event:Event):void
{
     bitmapDataArray = rsrc.array();
}

rsrc.aquireImages(array);

For loading animated GIFs

import com.efnx.utils.aquireResources;

var rsrc:aquireResources = new aquireResources();
     rsrc.addEventListener("complete", onComplete, false, 0, true);

var array:Array = new Array("imagePath1/image1.gif", "imagePath2/image2.gif", "imagePath3/image3.gif");

var animatedArray:Array;
function onComplete(event:Event):void
{
     animatedArray = rsrc.array();
}

rsrc.aquireGIFs(array);

Source
aquireResources Source

Simple Tiling Sprite Class in AS3

Monday, November 19th, 2007

Also known as “Developing a Pure AS3 GUI – Part 1.5 (tile)
Jump to Source
After writing last night’s class, scalingBars, I decided to make it a little easier on myself to tile bitmaps across the screen. I wrote a simple class that when given either a BitmapData object or a path to an image file (as a String), class will tile the image x pixels in width and y pixels in height. This is great for backgrounds or window bars or box sides, etc. Here’s the usage:

var bar:tile = new tile("pathToImageOrBitmapDataObject", 100, 150);
     addChild(bar);

The previous code will grab an image from “pathToImage” [either relative or absolute, but remember security!] and then tile it 100 pixels wide by 150 pixels tall. Simple. Now let’s say you wanted to resize it:

bar.resize(20, 40);

That code will re-tile the image to 20 pixels by 40 pixels. Next on my list of upgrades is to allow reloading of different images. Shouldn’t be too hard.
Example

Source
tile Class Source Code

Developing a Pure AS3 GUI – Part One (Scaling Bars)

Monday, November 19th, 2007

This class has been deprecated and phased out as of 12.7.2007

Writing your own GUI can be a daunting task, most people might find it easier to learn MXML and use Flex Builder or Flash Components than to waste their time writing GUI code and Photoshopping images. I on the other hand hate proprietary frameworks [like MXML] and really like the clean approach of creating classes of GUI elements that build on each other to make an interface. This post is the first in a series of posts designed to step through MY method of GUI design.

Example
Source

I start the process at windows. Windows hold all the content of a graphical operating system, the mother of all interfaces, so why not start there? Well, windows are super complicated, so first we’ll start by writing the components of a window. We’ll need a window bar that holds the close, minimize and optimize buttons and scales to a given size. This means we’ll need bars [vertical and horizontal] that tile. Don’t let the name Scaling Bars trick you, these bars aren’t really scaling, they’re tiling the bitmaps given to them in the constructor. Here’s the beginning code where we set up all our variables.

package com.efnx.GUI
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //  scalingBar is an object that given three images will scale to a certain size, tiling the middle image //
    //  and placing the end images on either side (overall width will be the given size) //////////////////////
    //////////////////////////////////////////////////////////////////////////////////////
   
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // usage: bar:scalingBar = new scalingBar(new Array("toporleftImage.xxx","middleImage.xxx","bottomorrightImage.xxx"), [tileDir:String: either "horizontal" or "vertical");  //
    //        addChild(bar);          ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //        bar.resize(someSize);  //
    //////////////////////////////////
   
    import com.efnx.utils.loadedSprite;
    import com.efnx.utils.aquireResources;
   
    import flash.display.BitmapData;
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.geom.Rectangle;
    import flash.geom.Point;
   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public class scalingBar extends Sprite
    {
        private var tileDirection:String;
        private var tileSize:int;
        private var minimumSize:int;
        private var side1:loadedSprite;
        private var middle:loadedSprite;
        private var side2:loadedSprite;
        private var loaded:int = 0;
        private var testing:Boolean;
       
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Okay. We’ve imported some classes that I’ve written myself that I haven’t talked about before, don’t worry, I’ve included them in the source and will post about them later. The vars are all pretty self-explanatory. The loadedSprites are a class of Sprite I’ve developed to make importing graphics a little easier on me. Given a path to an image it simply retrieves the image and sticks it inside a Sprite [itself]. On to the constructor:

public function scalingBar(imagePathArray:Array, tileDir:String = "horizontal", _testing:Boolean = false):void
        {
            testing = _testing;
            tileDirection = tileDir;
           
            if(tileDirection != "horizontal" && tileDirection != "vertical")
            {
                throw new Error("scalingBar::init: invalid tiling direction, scalingBar only accepts either \"horizontal\" or \"vertical\".");
                return;
            }
           
            side1 = new loadedSprite(imagePathArray[0], loadCycleComplete, testing); //remove testing parameter
            middle = new loadedSprite(imagePathArray[1], loadCycleComplete, testing); //to keep from tracing
            side2 = new loadedSprite(imagePathArray[2], loadCycleComplete, testing); //verbose info
           
            side1.name = imagePathArray[0];
            middle.name = imagePathArray[1];
            side2.name = imagePathArray[2];
           
            addChild(side1);
            addChild(middle);
            addChild(side2);
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

When instantiating the scalingBar class, create an array consisting of paths to the three images to be used for the bar, the left [or top], the middle, and the right [or bottom]. If left to the defaults your bar will tile and size horizontally. You can pass “vertical” as the second parameter to set the bar up to tile horizontally. Next we have the functions that take care of placement and size checks after the images are loaded. loadedSprite operates whatever function was passed to it as the second parameter in its instantiation, so no external event listeners are needed. We passed loadCycleComplete to the loadedSprites so that function will be called each time one is done loading:

        private function loadCycleComplete():void
        {
            loaded++;
            if(testing)trace("scalingBar::loadCycleComplete: has loaded " + loaded + "/3 resources. ");
            if(loaded == 3)
            {  
                if(tileDirection == "horizontal")
                {
                    tileSize = middle.width;
                }else
                {
                    tileSize = middle.height;
                }
                if(testing)trace("scalingBar::loadCycleComplete: finished loading.");
                placeParts();
                updateSize();
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        private function updateSize():void
        {
            if(tileDirection == "horizontal")
            {
                minimumSize = side1.width + side2.width + tileSize;
                if(testing)trace("scalingBar::updateSize: side1.width, side2.width, tileSize:" + side1.width, side2.width, tileSize);
            }else
            {
                minimumSize = side1.height + side2.height+ tileSize;
                if(testing)trace("scalingBar::updateSize: side1.height, side2.height, tileSize:" + side1.height, side2.height, tileSize);
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        private function placeParts():void
        {
            if(tileDirection == "horizontal")
            {
                middle.x = side1.width;
                side2.x = middle.x + middle.width;
            }else
            {
                middle.y = side1.height;
                side2.y = middle.y + middle.height;
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Almost done! The last part is the resize function, which takes an integer size and scales the entire bar either horizontally or vertically, depending on what you have specified. This is the real meat of the class. The resize function moves the bottom [or left] image to the border of the given size, then tiles the middle image over however many times needed until it reaches the bottom [or left] image:

public function resize(size:int):void
        {
           
            if(size >= minimumSize)
            {
                if(testing)trace("scalingBar::resize: valid resize value.");
                var bmd:BitmapData = middle.bitmapData.clone();
                var i:int = 0;
           
                if(tileDirection == "horizontal")
                {
                    side2.x = size - side2.width;
                    if(testing)trace("scalingBar::resize(): side1,side2 width and minimumSize:" + side1.width, side2.height, minimumSize);
                    middle.bitmap.bitmapData = new BitmapData(size - side1.width - side2.width, bmd.height, true, 0x00000000);
                    if(testing)trace("window::resize(): windowbarmiddle.bitmap.bitmapData: " + middle.bitmap.bitmapData.width, middle.bitmap.bitmapData.height);
                   
                    for(i = 0; i*bmd.width<middle.bitmap.bitmapData.width; i++)
                    {
                        middle.bitmap.bitmapData.copyPixels(bmd, new Rectangle(0, 0, bmd.width, bmd.height), new Point(i*bmd.width, 0));
                        if(testing)trace("window::resize(): copying pixels to middle.x=" + i*bmd.width);
                    }
                }else if(tileDirection == "vertical")
                {
                    side2.y = size - side2.height;
                    if(testing)trace("scalingBar::resize(): bmd dimensions:" + bmd.width, bmd.height);
                    middle.bitmap.bitmapData = new BitmapData(bmd.width, size - side1.height - side2.height, true, 0x00000000);
                    if(testing)trace("window::resize(): windowbarmiddle.bitmap.bitmapData w,h: " + middle.bitmap.bitmapData.width, middle.bitmap.bitmapData.height);
                   
                    for(i = 0; i*bmd.height<middle.bitmap.bitmapData.height; i++)
                    {
                        middle.bitmap.bitmapData.copyPixels(bmd, new Rectangle(0, 0, bmd.width, bmd.height), new Point(0, i*bmd.height));
                        if(testing)trace("window::resize(): copying pixels to middle.y = " + i*bmd.height);
                    }
                }
            }else
            {
                if(testing)trace("scalingBar::resize: invalid resize value of " + size + ", resizing at " + minimumSize);
                resize(minimumSize);
            }
        }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    }//end class
}//end package

Example
And there we go! Here is an example of the implementation:

Source
scalingBar source

AS3 – Calculating true Frames Per Second

Monday, October 22nd, 2007

I strongly recommend you look at this new version of this class.

When coding for Flash based games it’s important to know how fast your project is running [even if you're not coding games it's good to know whether or not your code is slogging down the player]. Adobe’s Stage class provides a parameter called “frameRate,” which allows you to dynamically get and set the player’s frame rate. Well, not exactly. It allows you to get and set the player’s TARGET frame rate, the fact is if the player can’t perform your code at that frame rate, it won’t! So how can you find out what the real frame rate is?

I wrote a simple class for this task to use in my project development. It’s super simple. My class, fpsBox, adds an eventListener to the stage [if you pass the stage as an argument when instantiating the class] or to itself, that triggers every frame and increments a value. A timer is started simultaneously with a repeat cycle of one second. Every second the number of counts counted each frame are displayed in the fpsBox and then averaged in an array of instantaneous values. Don’t worry, the array never gets past two values, the current average and the instantaneous FPS. Here’s some usage:

import com.efnx.fps.fpsBox;

var fps:fpsBox = new fpsBox(stage);
     addChild(fps);

That’s it!

What it looks like:

Link to SWF

Source Code
fpsBox Class Source Code

AS3 Animation class to replace MovieClip

Monday, October 15th, 2007

Okay, let me start by saying that I HATE importing resources into fla’s. When I first learned Flash [AS2] it wasn’t an issue. Now with AS3 and the necessity of classes my coding style has changed and I really, really like keeping things as separated into classes as possible.

The Problem With MovieClips
When attempting to program button classes I ran into this wall: Flash’s MovieClip is the only appropriate class object to use for animation. It’s great for placing images in your timeline to form moving pictures and placing Actionscript on certain frames makes directing the clip around really easy. But what about when you have to make MovieClips dynamically and add code to certain frames inside that clip, without using the GUI? MovieClip doesn’t support dynamically adding frames, or functions or Bitmaps to certain frames. This sucks. Why Adobe did this I do not know – so I wrote a class that DOES WHAT I WANT [and maybe you too].

Usage
Animation takes three parameters, which are all optional: numFrames:int = 1 width:int = 0, and height:int = 0. These params just initiate the object.

/*
*     blog.efnx.com:Animation Example
*/


import com.efnx.utils.Animation;     //import the class

var character:Animation = new Animation();     //object sets numFrames, width and height to 1, 0 and 0

After making the object you have to append the pictures to certain frames using the appendBitmapData function:

character.appendBitmapData(theFrame:int, bitmapData:BitmapData);

What this does is take the BitmapData and attach a function to the given frame that replaces the Animation’s default BitmapData with yours upon execution of that frame.
Doing this achieves the same effect as dragging a bitmap onto the stage in a MovieClip keyframe.

I wrote the class keeping in mind that someone may want to use it not for animation but sequential code execution, so frames can be created and functions attached to each frame without any graphics associated. The function used to add [or append] other functions to a certain frame is

     appendFrameScript(theFrame:int, theFunction:Function, [testing:Boolean = false]);

theFrame is the frame you’d like to add a function to, theFunction is the function to be added and testing tells the class whether or not to print debug info.

After adding frames and bitmaps and all that Animation can be controlled using familiar MovieClip methods like gotoAndPlay(), gotoAndStop(), go(), stop() and properties like currentFrame and totalFrames, as well as some others – bmd [the current frames BitmapData], bmdArray [an array of all frames BitmapData] and cool functions like customFps(fps:int) which set a custom playback rate denoted in number of frames per second [fps:int] and accelerateFps(desiredFps:int, numberFrames:int) which accelerates the playback delay from the current FPS to the desired FPS in numberFrames frames. accelerateFps is still a little buggy, feel free to nice it up!

Last Words
Animation doesn’t automatically loop your animation [since I usually don't need it to], so to really mimic a MovieClip you’d have to write a function incorporating gotoAndPlay(1) and then attach the function to the frame you’d like to loop your clip at:

var character:Animation = new Animation();                   //initiate object
     character.appendBitmapData(1, firstBitmapData);       //add BitmapData
     character.appendBitmapData(2, secondBitmapData);
     character.appendFrameScript(2, repeat);                   //append repeat function

function repeat():void                //repeat function
{
     character.gotoAndPlay(1);
}

Hope this class helps some of you out. Feel free to let me know what needs improving and comment if you like it!

Source
Animation Class Source Code

JPEGtoAS3 Image Converter

Saturday, October 13th, 2007

So here’s one of my first projects. It’s called JPEGtoAS3 Converter and it takes an image [JPEG, GIF, PNG or SWF] from the web [specified by an URL] and turns it into a series of BitmapData.setPixel() statements so you can place it in your AS3 class as a function. I made this so I could use graphics in my GUI classes without having to load them from external files. Instead I just place them in a function and create a new bitmap, then draw the pixels to the bitmap using the function.


JPEGtoAS3 Image Converter
[Right click and choose "Save As"]

So, I understand that the real utility of this program is marginal, but it’s still an interesting way to support graphics in classes without externally loading them, and without having to import resources to your .fla file.