Flash Banner part 2 – The ActionScript and Shockwave

See the prior tutorial on what kind of information the ActionScript in this tutorial needs and how it is generated.

It’s time to walk the AS2:

import flash.filters.*;
import flash.external.*;

var info:String 	= String(ExternalInterface.call("getInfo"));
var def_info:String = String(ExternalInterface.call("getDefault"));
var base_url:String = String(ExternalInterface.call("getUrl"));

if(info == 'null')
	info = def_info;

We begin by importing the filters, we will use the drop shadow further down in the code. External is required to communicate with the Javascript, we call the Javascript functions getInfo, getDefault and getUrl which were described in the prior tutorial.

If the page specific information has not been defined we will instead use the default information. If you browse to the dive site (not yet finished) you will see this logic in action. Currently only the Richelieu Rock dive site has its own banner, the rest of the pages use the default.

Note that we get a string ‘null’, not something that would actually evaluate to null, a very important detail.

var info_arr:Array 				= info.split('|');
var txts:Array 					= info_arr[1].split(':');
var images:Array 				= info_arr[0].split(';'); 
var settings:Array				= info_arr[2].split(';'); 
var imgClips:Array 				= new Array();
var imgListeners:Array 			= new Array();
var imgLoader:MovieClipLoader 	= new MovieClipLoader();
var curImage 					= 0;
var stageTime:Number			= int(settings[0]);
var speed:Number				= int(settings[1]);
var countDown					= stageTime;

We set some globals by first splitting the imported string by ‘|’, if you check the site with “view source” you can see what these strings look like at the moment. We continue by splitting the texts part by ‘:’ to get each sub string containing the text to display and the coordinates where it is to be displayed.

We do the same kind of splitting for the images part and a couple of global settings. We initiate an array that will contain callback objects for each picture being loaded. Next we create the required MovieClipLoader and set a variable keeping track of which image we are currently working with to 0.

The stageTime will be used to control how long each image stays before it is being faded out to make room for the next one, and the speed will control the speed of the fading. As you can see both of these values can be set from within MODx when the chunk is being created. These two values will be strings when imported, hence the need to use int() to convert them properly.

var txtHeight					= 70;
var txtConts:Array 				= new Array();
var fmt:TextFormat 				= new TextFormat();
fmt.color 						= 0xFFFFFF;
fmt.size						= 50;
fmt.font						= "tahoma20";

Some text specific globals, for instance an array that will contain all texts. The most important part here is “tahoma20” which is a font symbol that can be created in the library menu by going New Font -> size 20 and bold (in this case). After that you have to right click your new font in the library and select Linkage. Export for ActionScript and Export in first frame needs to be checked. I chose “tahoma20” as the identifier. Yes I know the fmt.size is 50, not 20, for some reason this didn’t matter, it still looks good.

for(i in images){
	imgClips[i] 		= this.createEmptyMovieClip("img_mc"+i, this.getNextHighestDepth());
	imgListeners[i] 	= new Object();
	imgListeners[i].onLoadComplete = function(target_mc:MovieClip, status:Number):Void {
		target_mc.loadStatus = 'imported';
	}
	imgLoader.addListener(imgListeners[i]);
	imgLoader.loadClip(base_url + images[i], imgClips[i]);
}

Next we setup the movieclips for loading by iterating over them. We put each in the imgClips array, create a callback object for each in imgListeners and set the onLoadComplete function to set a member variable to ‘imported’ when the import is finished. Finally we connect with addListener and execute with loadClip which will get the full path to the image, for instance “http://asiandivingvacation.com/assets/images/pic.jpg”. Relative URLs wouldn’t work.

function loadImages(){
	for(i in imgClips){
		var img = imgClips[i]; 
		if(img.loadStatus == 'imported'){
			img.loadStatus 	= 'yes';
			img.animIn 		= false;
			img.animOut 	= false;
			if(txts.length == imgClips.length)
				createTxt(i);
			img._alpha 		= 0;
		}
	}
}

This function is responsible for checking each image if it has been loaded (loadStatus is ‘imported’, not null). If an image is imported we set some member variables and loadStatus to ‘yes’ to indicate that the image has now been fully loaded, not just imported, animIn is set to false because we don’t want to start fading the image in until we say so, neither do we want some fading out to take place. We also create the text that belongs to the current image with createTxt. Finally we want the image to start by being completely invisible.

function createTxt(i){
	var txt 				= txts[i].split(';');
	var txtWidth 			= this._width - txt[1];
	var curTxt 				= this.createTextField("txt", this.getNextHighestDepth(), txt[1], txt[2], txtWidth, txtHeight);
	var dropFilter 			= new DropShadowFilter();
	var curFilters:Array 	= curTxt.filters;
	curFilters.push(dropFilter);
	with(curTxt){
		embedFonts 	= true;
		multiline	= false;
		text 		= txt[0];
		setTextFormat(fmt);
		filters 	= curFilters
		_alpha 		= 0;
	}
	txtConts[i] = curTxt;
}

We begin by splitting the current text in the txts global, the result will be the name (ex: ‘pic.jpg’), x-position (ex: ‘100’) and y-position (ex: ‘100’). We need to set the width of the text and since it will be clipped if bigger anyway it is safe to set it to the stage width minus the x-position. We create the text field and store it in curTxt. Next we create the drop shadow in dropFilter , temporarily save the current text’s filters in curFilters, then we push the dropFilter on top of that stack, later on you see that we reassign it to the filters member variable (who said AS was straightforward?). Anyway notice how we finally create a reference in txtConts for later retrieval.

this.onEnterFrame = function(){
	loadImages();
	var img = imgClips[curImage];
	if(img.loadStatus == 'yes'){
		if(countDown == stageTime){
			img.animIn = true;
			countDown--;
		}else if(countDown < stageTime && countDown > 0){
			if(images.length > 1)
				countDown--;
		}else{
			if(curImage == imgClips.length - 1){
				curImage 	= 0;
				countDown 	= stageTime;
				img.animOut = true;
			}else if(imgClips[curImage + 1].loadStatus == 'yes'){
				curImage++;
				countDown 	= stageTime;
				img.animOut = true;
			}
		}
	}
	animImages();
}

The main loop. As already noted we call loadImages all the time to check for new additions to the image stack and act accordingly. Next we examine the current image (will start at 0 remember?). If it is loaded we continue. If countDown equals stageTime (it will in the beginning) we set the animate flag to true to start fading the image in on the stage. And we decrease the countDown value with one too.

If the countDown value is lower than the stageTime but bigger than 0 (which it will be the second time we loop after the first condition evaluated to true) we simply decrease the countDown number with one (not if we only have one picture though since we don’t want that single picture to fade out forever).

When the countDown value hits 0 we have to do something. If we are at the last image in the stack we have to start all over again, that’s why we set curImage to 0 again. Notice that we don’t need to check if the next image is loaded or not in this case because it is safe to assume that all images have loaded when we are working with the last one.

In case we are not working with the last one we have to check if the next image in the stack has loaded yet, if it has we can safely fade out the current image and start working with the next one. Finally we call animImages:

function animImages(){
	for(i in imgClips){
		var img = imgClips[i];
		var txt = txtConts[i];
		if(img.animIn == true && img._alpha < 100){	
			img._alpha 	+= speed;
			txt._alpha 	+= speed;
		}else			
			img.animIn = false;
		
		if(img.animOut == true && img._alpha > 0){	
			img._alpha 	-= speed;
			txt._alpha 	-= speed;
		}else							
			img.animOut = false;
	}
}

Here we check the contents of both the image container and text container. Initially I tried putting the texts inside each image container and animate only the container but the texts would not play nicely in that case, I don’t know why. Anyway, it works when they are animated separately and it only added a few lines to the code.

If we are to fade in (animIn equals true and the alpha is less than 100) we increase the alpha by the speed value, the opposite happens when animOut equals true. And that’s it, the whole code, currently the clip is 960×250 with a fps of 25, works OK.

Related Posts

Tags: , ,