This website uses cookies to improve user experience. By using our website you consent to all cookies in accordance with our Cookie Policy. X

Sending data from preloader to loaded SWF [basic]

Continuing the topic on interfaces from the previous post, I’ve mentioned that their usefulness is sometimes irreplaceable and one good example of this is when trying to establish a communication channel with loaded SWF file, most frequently seen in preloaders.
Lets start with a basic preloader:
var loadLoader:Loader = new Loader();
loadLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
loadLoader.load(new URLRequest("MyAnimation.swf"));
		
function onLoaded(e:Event):void {
	addChild(loadLoader.content);
}
In this case the MyAnimation.swf file and its content will be put on the stage when preloader finishes loading it. This is without a doubt the simplest solution, giving us pretty much no control over who and how can open this animation, which is why lets, for example, make it only viewable when preloader passes a correct keyword. To do this, we need to go back the the animation file and make it a document class:

In such way that external no external user will be able to start it neither automatically, nor manually:
public class MyAnimation extends MovieClip {
	public function MyAnimation() {
		super.gotoAndStop(1);
	}
public override function gotoAndStop(frame:Object,scene:String=null):void {
		return;
	}
	public override function gotoAndPlay(frame:Object,scene:String=null):void {
		return;
	}
	public override function play():void {
		return;
	}

}
Now even we won’t be able to start it, which is why we will make a backdoor entrance available only to us, by using an Interface of course. Lets make it look like this:
public interface IMyInterface {
	function playUsingPassword(pass:String):void;
}
And then implemented in our MyAnimation class:
public class MyAnimation extends MovieClip implements IMyInterface {
	public function MyAnimation() {
		super.gotoAndStop(1);
	}
	public function playUsingPassword(pass:String):void {
		if(pass == "MyPassword") super.play();
	}
public override function gotoAndStop(frame:Object,scene:String=null):void {
		return;
	}
	public override function gotoAndPlay(frame:Object,scene:String=null):void {
		return;
	}
	public override function play():void {
		return;
	}

}
(Don’t forget to add the implements!)
By writing super.play() we bypass our overwrites of play() from the MovieClip class. One last thing to do is to test it out:
var loadLoader:Loader = new Loader();
loadLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
loadLoader.load(new URLRequest("MyAnimation.swf"));
		
function onLoaded(e:Event):void {
	addChild(loadLoader.content);

	var main:IMyInterface = loadLoader.content as IMyInterface;
	if(main != null) main.playUsingPassword("MyPassword");
}
Resulting in something like this:
(Animation file is located here: MyAnimation.swf - anyone who wants a challenge can try loading it themselves)
Source: PreloaderInterface.zip

Preloaders in Flash [basic]

"Preloading" is simple idea that dates back to the beginnings of the Internet - perhaps even further than that. It is a process of moving all of the applications data or multimedia into a computer's memory, so it can be accessed smoothly without breaks for additional reading. Same goes for Flash, with preloading we will be certain our animations and whatnot won't turn into a slide-show.
It sound simple enough, but implementation of a preloader into Flash can sometimes be quite tricky. Generally speaking, it all comes down to 3 solutions depending on what we need:

1. For animations.
Movies done in Flash that use almost no ActionScript are the easiest target to include a preloader (since there will be nothing to interfere with it), just copy and paste a ready example.
One of the simplest requires a single MovieClip in the very first frame of the main timeline with instance name set to "preloader" (in properties tab) along with this code pasted in to the same frame:

import flash.events.Event;
import flash.events.ProgressEvent;

stop();
loaderInfo.addEventListener(ProgressEvent.PROGRESS,onProgress);
loaderInfo.addEventListener(Event.COMPLETE,onLoaded);

function onProgress(e:ProgressEvent):void {
	var percent:Number = loaderInfo.bytesLoaded/loaderInfo.bytesTotal;
	preloader.gotoAndStop( int(percent*preloader.totalFrames)+1);
}
function onLoaded(e:Event):void {
	loaderInfo.removeEventListener(ProgressEvent.PROGRESS,onProgress);
	loaderInfo.removeEventListener(Event.COMPLETE,onLoaded);
	//moves to a designated frame in the animation after the loading process
	gotoAndPlay(2);
}
The "preloader" MovieClip will have its animation stop on frame number that is equal to percent amount of content loaded, so if the "preloader" has total of 10 frames and the move itself is loaded to, for example 20%, the frame displayed will be 2 (10*20% = 2).
Ready to use example: preloaderSimple.zip

2. For applications created in Flash Professional.
Here it gets a bit tougher. When creating project that heavily use ActionScript people don't usually think about preloaders first and foremost, which actually isn't a bad thing but might bring some complications, especially when exporting to the first frame.
Speaking of exporting to the first frame, lets take a moment to look at this function. When exporting graphics to ActionScript we have an option to "export in 1 frame", which does exactly what it says and puts all of the graphics in the first frame of main timeline - the trouble is, this leaves us with no room to later insert a preloader. In Flash Professional this can be dealt in two ways:
- by changing a designated frame in ActionScript's properties

- or by simply putting the graphics manually on the stage in proper frame. Lets, for example, take a class that makes use of a exported graphic on frame 3 in the main timeline, allowing us to put them on frame 2 (even outside of the screen if needed) while having the "export to 1 frame" opetion turned off.

3. For applications created in FlashDevelop.
… or any other development environment that loads SWC files. I'm referring here to external ActionScript libraries that may or may not come packed with graphics or other multimedia. Those multimedia elements are loaded as soon as there is something referencing the classes they are linked with, which basically means any kind of import from SWC will instantly be blocked till the graphics gets loaded into the memory. On the other hands omitting those imports simply means no SWC class will be compiled into the application. This begs a question: how can something be included along the application without actually importing it? There is only one answer and it was found by Keith Peters at: www.bit-101.com. Long story short, this brilliant trick can be summed down to a single line: [Frame(factoryClass="Preloader")] ("Preloader" is the name of the class that will server as a preloader), which has to be put right before documents class definition (but after all the imports) - called, for example: "Main". Main will get loaded but not initialized because this role will be taken over by the Preloader.
Unfortunately there is still a matter of instancing Main after the loading process, since we still can use imports - we import Main, Main imports something else, which in turn imports something else and sooner or later there will come along a class that imports straight from the SWC file, blocking our application the graphics gets loaded. Fear not however as flash.utils.getDefinitionByName comes to our aid being used in the following way:

var mainClass:Class = getDefinitionByName("Main") as Class;
if(mainClass) {
	addChild(new mainClass() as DisplayObject); 
}
WARNING! The getDefinitionByName() function may from time to time return the NULL value, meaning ENTER_FRAME Event might be good idea to allow for further retries in later times.
As per usual, here is an example code: preloader.zip
And in action it can be viewed here: Preloader.html