Thursday, 17 September 2009

THE CLASS NAME MUST BE THE SAME AS THE FILE NAME

For some reason, that title doesn't seem to appear anywhere and everywhere Actionscript 3.0 document classes are discussed. Which is weird, because it should. In bright red capital letters. Believe me, if you don't know that one simple fact you can end up tearing your hair out trying to figure out what the Flash compiler's extremely specific but basically incomprehensible errors actually mean.

I've just started my first real foray into AS3, which is why that naming rule is so pertinent to me at this time. I'm not a complete pro at AS2, but I'm fairly proficient, and able to do some pretty complicated things. However, I've built up these skills over time and from familiarity with using the language, not from a natural gift of programming - which I don't have.

So upgrading to AS3 isn't proving to be very easy for me. Across the web there are always many tutorials and code snippets, none of which are ever precisely what I am looking for. In AS2, that had ceased to be a problem, as I was pretty good at working out how to make stuff work how I wanted it to. In AS3 it's not so simple, however I've successfully made my first package that does exactly what I want it to.

And what it does is pretty straightforward - it preloads an external file into a main .swf, and offers feedback to the user in the form of a loading bar and text stating the percentage loaded.

The key parts of this preloader that are different to others I've seen are: the script takes in variables specifying the file to be loaded, and its x and y positions on the stage; and it dynamically draws a rectangular loading bar. Many of the others I've seen loop through an animation instead of having a bar - of course you could adapt this code to do the same thing, if you know how (I currently don't, although I expect it's something that I'll do at some point in the future).

So without further ado, here's the code for the package:

package {

import flash.display.Loader;
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.display.LoaderInfo;
import flash.text.*;
import flash.events.*;

//Class name must be the same as the filename

public class preloader extends Sprite {

//Set variables
private var displayTxt:TextField = new TextField(); //percentage textfield
private var txtFormat:TextFormat = new TextFormat(); //formatting for textfield
private var percent:Number; //percentage variable
private var loadBar:Sprite = new Sprite; //drawing variable

/*LoadExternalSwf takes the name of a file as a parameter, then uses showProgress and loadedSwf to make the preloader */

public function loadExternalSwf(fileName:String, xPos:Number, yPos:Number) {

var loader:Loader = new Loader();
loader.x = xPos; //xPos of external file
loader.y = yPos; //yPos of external file
addChild(loader); //must addChild to add to stage
loader.load(new URLRequest(fileName)); //loads in swf or jpg

/*other functions below are used to control the progress bar and percentage*/
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadedSwf);
loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, showProgress);
}


/*ShowProgress makes and formats the text to output in the percentage box, and makes a rectangular progress bar based on percentage*/

public function showProgress(event:ProgressEvent):void {

percent = Math.round((event.bytesLoaded/event.bytesTotal) * 100);//standard percentage formula
displayTxt.text = percent + " %";

/*xPos of text is to be just to the left of the progress bar. The position is arrived at by finding the centre of the stage, then adding the 50% value of the loading bar plus 8 for a little extra spacing*/

displayTxt.x = stage.stageWidth/2 + 98;

/*yPos of text is to be more or less centred. The position is arrived at by finding the centre of the stage, then minusing the height of the text field to position the bottom of the text field at the stage's halfway point*/

displayTxt.y = stage.stageHeight/2 - displayTxt.textHeight;

//formatting for text
txtFormat.color = 0x333333;
txtFormat.font = "Arial";
txtFormat.size = 12;
displayTxt.setTextFormat(txtFormat); //add format to text field
addChild(displayTxt); //must addChild to add to stage

/*drawing rectangle - begin fill, specifying the desired colour in hex, then use function drawRect(xStartPos, yStartPos, width, height)*/

loadBar.graphics.beginFill(0xAABBCC);

/*xPos of rectangle is arrived at by finding the centre of the stage, then subtracting half the desired width of the progress bar, so that the midway point of the bar is at the midway point of the stage - in this case 180/2 = 90; yPos of rectangle is arrived at by finding the vertical centre of the stage, then subtracting the height of the bar plus 1, in this case to compensate for the difference in height between the bar (10) and the text (12). Width is arrived at by multiplying the current percentage by the multiplier. The multiplier is arrived at by dividing the desired width of the progress bar by 100 - in this case 180/100 = 1.8*/

loadBar.graphics.drawRect (stage.stageWidth/2 - 90, stage.stageHeight/2 - 11, percent * 1.8, 10);

//must always end fill when making filled shapes

loadBar.graphics.endFill();
addChild(loadBar); //must addChild to add to stage
}


/*LoadedSwf gets rid of the dynamically made text field and progress bar rectangle when the external file has finished loading*/

public function loadedSwf(event:Event):void {

removeChild(displayTxt);
removeChild(loadBar);
}
}
}

Now, of course, because (insert post title here), this file will have to be called "preloader.as", and it is an external ActionScript file.

Part Two is to add a little ActionScript to the timeline of your .fla that you want to be preloading external files into. The code to include the external AS file, and to use the class, looks like this:

import preloader;

var externalSWF:preloader = new preloader();
addChild(externalSWF);
externalSWF.loadExternalSwf("relativePath/filename.swf", 10, 10);

The "10" and "10" above are of course the x and y positions of the external .swf or .jpg, and can be set to whatever you want them to be.

Now in my .swf, I just have this code sitting in a frame, but you could easily attach it to a button or similar:

button_btn.addEventListener(MouseEvent.CLICK, loadExt);

function loadExt (event:MouseEvent) {
var externalSWF:preloader = new preloader();
addChild(externalSWF);
externalSWF.loadExternalSwf(
"relativePath/filename.swf", 10, 10);

};

Naturally, you still need to include import preloader; on your timeline somewhere if you are going to use the button code.

I hope this is useful to someone looking to make their first preloader in AS3.0 I don't pretend to be an expert and it's pretty basic, but it is probably a good starting point.