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

Interfaces in Flash [basic]

In programming, by ‘Interface’ we understand an abstract definition of methods that by themselves don’t do anything, except for forcing a certain syntax in a class that implements them. In other words we define a function and its arguments in one place and then implement its mechanics in another (target class). Of course by no means its the best way to create a function in Flash, but interfaces have a special trait that makes them irreplaceable in certain scenarios. This trait is ability to cast an object to the interface they implement, which in turn allows us to communicate with it, without actually know what the object is.
I think it is best to demonstrate it on a example, starting from the very beginning: let’s say we want to create a game that displays some information through pop-ups in such way, that each of them contains an “OK” button:
public class MyPopup extends MovieClip {
	private var myButton:OKButton;
	public function MyPopup() {
		myButton = new OKButton(this);
		addChild(myButton);
	}

	public function close():void {
		this.visible = false;
	}
}
public class OKButton extends MovieClip {
	private var myPopup:MyPopup;
	public function OKButton(popup:MyPopup) {
		myPopup = popup;
		this.addEventListener(MouseEvent.CLICK,onMouse);
	}
	private function onMouse(e:MouseEvent):void {
		myPopup.close();
	}
}
At first everything might like fine, but as soon as we start adding more pop-ups the limitation of the above code become apparent - what if we want to reuse the same button for MyPopup2 ? Is adding another argument ( OKButton(popup:MyPopup, popup2:MyPopup2) {} ) enough? Should we repeat this for each new pop-up we want to add? One solution for sure is to create a base class for every pop-up, so we cast it down to use shared methods. However such root classes might bring some troubles in Flash, that I won’t be discussing here. At this point it is probably quite obvious what I am trying to say - the best solution is to use Interfaces. So, let’s create a new AS file:
public interface IPopup {
	function close():void
}
And then modify existing classes:
public class MyPopup extends MovieClip implements IPopup{
	private var myButton:OKButton;
	public function MyPopup() {
		myButton = new OKButton(this);
		addChild(myButton);
	}

	public function close():void {
		this.visible = false;
	}
}
public class MyButton extends MovieClip {
	private var myPopup:IPopup;
	public function MyButton(popup:IPopup) {
		myPopup = popup;
		this.addEventListener(MouseEvent.CLICK,onMouse);
	}
	private function onMouse(e:MouseEvent):void {
		myPopup.close();
	}
}
The difference is quite small, but possibilities definitely much broader. From now on MyButton can communicate with every pop-up without actually knowing what class it is, as long as they implement the proper interface.