[flashpro] AS2 Preloader - - Help Needed...

Timo Stamm t.stamm at macnews.de
Fri Sep 30 21:35:29 EDT 2005


Fes Hudson wrote:
 > Hello

Hi Fes.


 > What I want to accomplish is to build a
 > preloader using AS2.
  > [...]
 > have the preloader "animate in" BEFORE
 > it starts preloading, and then "animate out" AFTER the
 > load is complete, but BEFORE the content is visible.


This is actually not a trivial thing to do because:

- data is loaded asynchronously
- there is no wait() function in flash

So you can not simply write something like:

fadeIn(preloader);
loadMovie();
fadeOut(preloader);
fadeIn(movie);



Most people solve this by:

- using the timeline and as few code as possible (not re-usable)
- using loops and checking the state (only re-usable by copy & paste and
    a lot of variables, etc.)
- using callbacks (partially re-usable)


You don't need AS2 to do it this way. In fact, AS2 just makes it a lot
more complicated. To really leverage the advantages of AS2, you need
some experience in OO design in order to create really discrete and
re-usable classes.

Your question inspired me to write a preloader that can be used as easy
as this:

new DefaultPreloader(_root.target, "g.swf", _root.display);


The first argument is the movieclip where the movieclip or image is to
be loaded into. The second argument is the URL of the movieclip to be
loaded. The third argument is an instance of the class PreloaderDisplay
that displays the loading progress.


With import statements and creation of the necessary objects, it looks
like this:

import de.kyon.preloader.DefaultPreloader;
import de.kyon.preloader.DefaultPreloaderDisplay;

Object.registerClass("display", DefaultPreloaderDisplay);
_root.attachMovie("display", "display", 99);
_root.createEmptyMovieClip("target", 77);
new DefaultPreloader(_root.target, "g.swf", _root.display);


Now to the rest of the code. There are three packages:

- preloader
	Contains classes specific to the preloader

- asyncaction
	A package to support flow control with asynchronous actions such
	as animation and loading.

- transition
	Contains base classes for programmatic animation that are
	compatible with	flow control management of the asyncaction
	package.



Here are the classes (can send a zip file containing the classes):


import de.kyon.preloader.DefaultPreloaderDisplay;
import de.kyon.preloader.Load;
import de.kyon.preloader.Preloader;
import de.kyon.transition.FadeIn;
import de.kyon.transition.FadeOut;

class de.kyon.preloader.DefaultPreloader extends Preloader {
		
	public function DefaultPreloader (target : MovieClip, url : String,
display : DefaultPreloaderDisplay) {
		super(target, url, display);
		addAction(new FadeIn(display, 1500));
		addAction(new Load(target, url, display));
		addAction(new FadeOut(display, 1500));
		addAction(new FadeIn(target, 1500));
		start();
	}
	
}



import de.kyon.asyncaction.AbstractAsynchronousActionImpl;
import de.kyon.asyncaction.AsynchronousActionListener;
import de.kyon.asyncaction.ActionQueue;
import de.kyon.asyncaction.AsynchronousAction;
import de.kyon.preloader.PreloaderDisplay;

class de.kyon.preloader.Preloader extends AbstractAsynchronousActionImpl
implements AsynchronousActionListener {

	private var queue : ActionQueue;

	public function Preloader (target : MovieClip, url : String, display :
PreloaderDisplay) {
		queue = new ActionQueue();
		queue.addListener(this);
	}
	
	public function addAction(a : AsynchronousAction) : Void {
		queue.addAction(a);
	}
	
	public function onComplete (Void) : Void {
		queue.removeListener(this);
		complete();
	}

	public function start (Void) : Void {
		queue.start();
	}

}




import de.kyon.preloader.PreloaderDisplay;

class de.kyon.preloader.DefaultPreloaderDisplay extends MovieClip
implements PreloaderDisplay {

	public function onLoadStart(Void) : Void {
		trace("requesting")
	}

	public function onLoadProgress(target_mc:Object, loadedBytes:Number,
totalBytes:Number, url:String) : Void {
		trace("" + loadedBytes + " bytes of " + totalBytes + " loaded from " +
url)
	}

	public function onLoadError (target_mc:MovieClip, errorCode:String,
url:String) : Void {
		trace("error while loading " + url + ": " + errorCode)
	}

}




interface de.kyon.preloader.PreloaderDisplay {

	public function onLoadStart(Void) : Void;

	public function onLoadProgress(target_mc:Object, loadedBytes:Number,
totalBytes:Number, url:String) : Void;
	
	public function onLoadError (target_mc:MovieClip, errorCode:String,
url:String) : Void;
	
}




import de.kyon.asyncaction.AbstractAsynchronousActionImpl;
import de.kyon.preloader.PreloaderDisplay;

class de.kyon.preloader.Load extends AbstractAsynchronousActionImpl {
	
	private var loader : MovieClipLoader;
	private var target : MovieClip;
	private var display : PreloaderDisplay;
	private var url : String;
	
	public function Load (target : MovieClip, url : String, display :
PreloaderDisplay) {
		loader = new MovieClipLoader();
		loader.addListener(this);
		this.target = target;
		this.url = url;
		this.display = display;
		target._alpha = 0;
	}

	public function start (Void) : Void {
		loader.loadClip(url, target);
	}
	
	public function onLoadStart (target_mc:MovieClip) : Void {
		display.onLoadStart(target_mc, url);
	}
	
	public function onLoadComplete (target_mc:MovieClip) {
		complete();
	}
	
	public function onLoadError (target_mc:MovieClip, errorCode:String) {
		display.onLoadError(target_mc, errorCode, url);
		complete();
	}
	
	public function onLoadProgress (target_mc:MovieClip,
loadedBytes:Number, totalBytes:Number) {
		display.onLoadProgress(target_mc, loadedBytes, totalBytes, url);
	}
		
	public function onLoadInit (target_mc:MovieClip) {
		// ignore
	}
	
}



import de.kyon.transition.Fade;

class de.kyon.transition.FadeIn extends Fade {
	
	public function FadeIn (target : MovieClip, duration : Number) {
		super(target, duration);
	}
	
	public function onFade (percentComplete : Number) : Number {
		return percentComplete;
	}
	
}



import de.kyon.transition.Fade;

class de.kyon.transition.FadeOut extends Fade {
	
	public function FadeOut (target : MovieClip, duration : Number) {
		super(target, duration);
	}
	
	public function onFade (percentComplete : Number) : Number {
		return 100 - percentComplete;
	}
	
}



import de.kyon.transition.Transition;

class de.kyon.transition.Fade extends Transition {
	private var target : MovieClip;
	
	public function Fade (target : MovieClip, duration : Number) {
		super(duration);
		this.target = target;
	}
	
	public function onInterval (percentComplete : Number) : Void {
		target._alpha = onFade(percentComplete);
	}
	
	public function onFade (percentComplete : Number) : Number {
		// overwrite in subclasses
		// return new alpha value
		return null;
	}

}



import de.kyon.asyncaction.AbstractAsynchronousActionImpl;
import de.kyon.transition.TransitionListener;

class de.kyon.transition.Transition extends AbstractAsynchronousActionImpl {

	public static var FPS : Number = 25;

	private var intervalId : Number;
	private var duration : Number;
	private var startTime : Number;

	public function Transition (duration : Number) {
		this.duration = duration;
	}

	public function start (Void) : Void {
		startTime = getTimer();
		intervalId = setInterval(this, "$int", 1000/FPS);
		for (var i:Number = 0; i<listeners.length; i++) {
			TransitionListener(listeners[i]).onComplete();
		}
	}

	public function onInterval (percentComplete : Number) : Void {
		// overwrite this method in subclasses
		// return true if transition is complete
	}
	
	public function $int (Void) : Void {
		var percentComplete : Number = (getTimer() - startTime) / duration * 100;
		if (percentComplete > 100) {
			clearInterval(intervalId);
			complete();
		} else {
			onInterval(percentComplete)
		}
	}
	
}



import de.kyon.asyncaction.AsynchronousActionListener;

interface de.kyon.transition.TransitionListener extends
AsynchronousActionListener {}




import de.kyon.asyncaction.AbstractAsynchronousActionImpl;
import de.kyon.asyncaction.AsynchronousActionListener;
import de.kyon.asyncaction.AsynchronousAction;

class de.kyon.asyncaction.ActionQueue extends
AbstractAsynchronousActionImpl implements AsynchronousActionListener {

	private var actions : Array;
	private var currentAction : AsynchronousAction;

	public function ActionQueue (Void) {
		actions = [];
	}

	public function addAction(a : AsynchronousAction) : Void {
		actions.push(a);
	}
	
	public function start(Void) : Void {
		next();
	}
	
	private function next(Void) : Void {
		if (actions.length > 0) {
			currentAction = AsynchronousAction(actions.shift());
			currentAction.addListener(this);
			currentAction.start();
		} else {
			complete();
		}
	}

	public function onComplete (Void) : Void {
		currentAction.removeListener(this);
		next();
	}

}




import de.kyon.asyncaction.AsynchronousAction;
import de.kyon.asyncaction.AsynchronousActionListener;

class de.kyon.asyncaction.AbstractAsynchronousActionImpl implements
AsynchronousAction {
	
	private var listeners : Array;
	
	public function AbstractAsynchronousActionImpl(Void) {
		listeners = []; // we must initialize the array in the constructor
because flash is dumb
	}
	
	public function complete () {
	  for (var i:Number = 0; i<listeners.length; i++) {
			AsynchronousActionListener(listeners[i]).onComplete();
		}
	}
	
	public function start (Void) : Void {
		// overwrite this method in subclasses
	}
	
	public function addListener (listener : AsynchronousActionListener) :
Void {
		removeListener(listener);
		listeners.push(listener);
	}
	
	public function removeListener (listener : AsynchronousActionListener)
: Void {
		for (var i:Number = 0; i<listeners.length; i++) {
			if (listeners[i] == listener) {
				listeners.splice(i, 1);
				break;
			}
		}
	}

}




import de.kyon.asyncaction.AsynchronousActionListener;

interface de.kyon.asyncaction.AsynchronousAction {

	public function start (Void) : Void;

	public function addListener (listener : AsynchronousActionListener) : Void;

	public function removeListener (listener : AsynchronousActionListener)
: Void;

}




interface de.kyon.asyncaction.AsynchronousActionListener {

	public function onComplete (Void) : Void;

}




Some notes:

- Transition should have methods for pause, continue, stop and
retrieving the state; TransitionListener should define the events
accordingly.

- FadeIn should not ignore the initial value of target._alpha, but
rather fade from 30% to 100%, for example.

- It should be very easy to enable other animation packages to work with
the flow control management. There is only one simple interface to
implement (AsynchronousAction), or you can derive your class from a
standard implementation (AbstractAsynchronousActionImpl).

- Please note that this code is pretty much untested.


Timo


More information about the FlashPro mailing list