Countdown timer for time-based game - actionscript-3

I have a game in which the objective is to shoot as many (randomly generated) enemy ships as possible but I want to add a 30 second timer counting down to zero to add a time limit in, but I am not sure how I would do it? I have several AS files with all of my code in to generate different sized ships at different speeds and whatnot, so if snippets of code are needed, I will add them.
I tried doing it this way and it didn't work:
var gameTime:Number = 30;
var gameTimer:Timer;
static var timeText:TextField = new TextField();
timeText = new TextField();
timeText.x = 560;
timeText.y = 0;
timeText.text = gameTime.toString();
addChild(timeText);
gameTimer = new Timer(30000, gameTime);
gameTimer.addEventListener(TimerEvent.TIMER, gameTimeCount);
gameTimer.start();
function gameTimeCount(e:TimerEvent):void
{
gameTime--;
timeText.text = gameTime.toString();
}
But the count stays at 30 and doesn't go down.
What I have now:

Here's one way you could do this :
// in class variable declarations
public var gameTime:int;
public var levelDuration:int;
// where you want to start it
levelDuration = 30;
gameTime = levelDuration;
var gameTimer:Timer = new Timer(1000,levelDuration);
gameTimer.addEventListener(TimerEvent.TIMER, updateTime);
gameTimer.addEventListener(TimerEvent.TIMER_COMPLETE, timeExpired)
gameTimer.start();
function updateTime(e:TimerEvent):void
{
// your class variable tracking each second,
gameTime--;
//update your user interface as needed
}
function timeExpired(e:TimerEvent):void
{
var gameTimer:Timer = e.target as Timer;
gameTimer.removeEventListener(TimerEvent.TIMER, updateTime)
gameTimer.removeEventListener(TimerEvent.TIMER, timeExpired)
// do whatever you need to do for game over
}
This code works just fine, you need to do as the updateTime function comment suggests :
//update your user interface as needed
Based on your code in your post, you need to adjust that function to look like this :
function updateTime(e:TimerEvent):void
{
trace(gameTime);
// your class variable tracking each second,
gameTime--;
//update your user interface as needed
timeHeader.text = "Time : " + String(gameTime);
}
I added a trace too, so you can see that it is indeed updating each second.

Related

AS3 running an event for a set duration after button (or anything) event

For the purposes of the question, Imagine I have an object onstage. When I click on another button, I want the colour to change for 1 second, then revert back again when finished.
Here's what my demo code looks like:
Button.addEventListener(MouseEvent.CLICK, Colour_Change);
function Colour_Change(evt: MouseEvent): void {
var my_color: ColorTransform = new ColorTransform();
my_color.color = 0xFF0000;
Coloured_Object.transform.colorTransform = my_color;
}
What I am wanting is some sort of timer function to be incorporated in the above function. I haven't got any idea how to do it, hence why there's no implementation.
You should use the flash.utils.Timer class.Adobe ActionScript 3.0 Reference for the Timer class
The following should be enough to get you headed in the right direction:
import flash.utils.Timer;
var myTimer:Timer = new Timer(1000, 1); // 1 second
var running:Boolean = false;
Button.addEventListener(MouseEvent.CLICK, Colour_Change);
myTimer.addEventListener(TimerEvent.TIMER, runOnce);
function Colour_Change(evt: MouseEvent): void {
var my_color: ColorTransform = new ColorTransform();
my_color.color = 0xFF0000;
Coloured_Object.transform.colorTransform = my_color;
if(!running) {
myTimer.start();
running = true;
}
}
function runOnce(event:TimerEvent):void {
// code to revert the button's color back goes here
myTimer.reset();
running = false;
}
Let me know if you need more help or if this example has errors via this answer's comments section.
To further explain the Timer class as used above:
when creating a new timer
myTimer=new Timer(1000,1)
the first number in the brackets is the number of milliseconds you want the timer to run for (e.g. 1000 = 1 second)
The second number is how many times you want the timer to repeat (or 0 for infinite repetition).
Every time the timer reaches the time you entered (1000), this is will trigger any event listeners for the event Timer_Event.TIMER, so for example if u wanted to make it change color on and off, you could have multiple repetitions on the timer and change the function.
Other useful things timers can do:
You can add an event listener for
Timer_Event.TIMER_COMPLETE
(goes off when all repetitions are complete)
myTimer.currentCount
will return the number of repetitions the timer has done so far.
To do that you can use, as other answers said, a Timer object or the setTimeout() function, like this :
// the current color of our target object
var default_color:ColorTransform;
// the delay in milliseconds
var delay:int = 1000;
btn.addEventListener(MouseEvent.CLICK, Colour_Change);
function Colour_Change(evt: MouseEvent): void {
// save the current color of our target object
default_color = target.transform.colorTransform;
var new_color:ColorTransform = new ColorTransform();
new_color.color = 0xFF0000;
target.transform.colorTransform = new_color;
var timer:Timer = new Timer(delay, 1);
timer.addEventListener(TimerEvent.TIMER, function(e:TimerEvent):void {
// after the delay, we use the default color of our target
target.transform.colorTransform = default_color;
})
timer.start();
// using setTimeout(), you have to disable this if using the Timer
var timeout:int = setTimeout(
function(){
clearTimeout(timeout);
// after the delay, we use the default color of our target
target.transform.colorTransform = default_color;
},
delay
);
}
Hope that can help.

How to get a percentage from new Date();

I have a digital clock for now, and I need the corn to know when 10 seconds as passed, this way it can go to the next frame. Im having difficulty finding out how to gather the 10 secs and make it out of 100% for example
its 9:30:21 and i pushed the button
at 9:30:31 it should be done
but I want to create a percentage bar based on that 10sec.. heres my code
farmSlot1.addEventListener(MouseEvent.CLICK, farmClick1);
var startTime: Date = new Date();
var startSec: Number = startTime.seconds;
function farmClick1(e: MouseEvent): void {
addChild(menu);
menu.x = 400;
menu.y = 90;
menu.buyCornBtn.addEventListener(MouseEvent.CLICK, buyCorn1);
}
function buyCorn1(e: MouseEvent): void {
var startTime: Date = new Date();
startSec = startTime.seconds;
menu.buyCornBtn.addEventListener(Event.ENTER_FRAME, cornloading1);
farmSlot1.progressB.visible = true;
menu.buyCornBtn.removeEventListener(MouseEvent.CLICK, buyCorn1);
removeChild(menu);
}
function cornloading1(event: Event): void {
var now: Date = new Date();
var hr: Number = now.hours;
var min: Number = now.minutes;
var sec: Number = now.seconds;
var finished: Number = startSec + 5
var percent = Math.round((finished-sec) * 100)
if(sec < finished){
farmSlot1.loader_txt.text = percent
Object(root).farmSlot1.progressB.bar.scaleX = percent;
trace("hit");
}else if (sec == finished && farmSlot1.currentLabel != "corn") {
removeEventListener(Event.ENTER_FRAME, cornloading1);
trace("It did it");
farmSlot1.loader_txt.text = ""
farmSlot1.gotoAndStop("corn");
}
}
At first, as I see you are writing the code inside Flash frames. Incapsulating your code within classes is better approach which allows to avoid tons of problems in the future. Here is a link described some basic approaches for using classes:
http://www.kirupa.com/developer/as3/classes_as3_pg1.htm
In answer to your question:
You can simply use flash.utils.Timer class instead of using Date and ENTER_FRAME event: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/Timer.html
Some piece of code:
//Import timer class
import flash.utils.Timer;
...
//In the class's body
//Create a timer instance. Timer will be executed 10 times every 100 milliseconds
private var timer:Timer = new Timer(100, 10);
...
//Somewhere in class's method (usually in the constructor)
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
//Add click handler
button.addEventListener(MouseEvent.CLICK, buttonClickHandler);
...
private function buttonClickHandler(event:MouseEvent):void
{
//Do some stuff and start timer.
timer.start();
}
private function timerHandler(event:TimerEvent):void
{
//Update progress indicator
}
private function timerCompleteHandler(event:TimerEvent):void
{
//1 second is over so do some stuff.
}

How do I unload an external ".swf" file to load another?

I am a student who's working for months on a game and now I've got stuck on a problem.
I am new to actionscript 3 but i learn fast.
I can load my menu screen ("startScreen.swf") into my game (firstgame) automatically and everything works fine when I click play or storyScreen or instructionsScreen. But the problem is that I want to return after pressing ESC button. I have tried many code but nothing works exactly how I want.
Example: I click on story and the swf (storyScreen.swf) loads and I can read the story and when I am finished, I want to press ESC to reload my swf (startScreen.swf) and all the functions in it. Like play and instructions.
You can find my code and empty space in the function (esc).
I know it is maybe easy to solve but I really don't know how. :(
public class FirstGame extends MovieClip
{
public var Player:MovieClip
private var leftKeyIsDown:Boolean;
private var RightKeyIsDown:Boolean;
private var aMissileArray:Array;
private var aEnemyArray:Array;
public var scoreTxt:TextField;
public var ammoTxt:TextField;
public var MenuEnd:EndGameScreen;
public var menuAgain:EndGameScreen;
private var MenuStart:mcStartGameScreen;
private var MenuStory:mcStartGameScreen;
private var MenuInstructions:mcStartGameScreen;
private var nScore:Number;
private var nAmmo:Number;
private var tEnemyTimer:Timer;
public function FirstGame()
{
//Create a loader object
var startLoader:Loader = new Loader();
//add event listener to listen for the complete event
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
//load our loader object
startLoader.load(new URLRequest("startScreen.swf"));
}
public function startLoaded(e:Event):void
{
MenuEnd.hideScreen();
Player.visible = false;
scoreTxt.visible = false;
ammoTxt.visible = false;
//get a reference to the loaded movieclip
MenuStart = e.target.content as mcStartGameScreen;
//listen for start game event
MenuStart.addEventListener("START_GAME", playGameAgain);
//add it to the stage
addChild(MenuStart);
//get a reference to the loaded movieclip
MenuStory = e.target.content as mcStartGameScreen;
//listen for start game event
MenuStory.addEventListener("SHOW_STORY", storyGameScreen);
//add it to the stage
addChild(MenuStory);
//get a reference to the loaded movieclip
MenuInstructions = e.target.content as mcStartGameScreen;
//listen for start game event
MenuInstructions.addEventListener("SHOW_INSTRUCTIONS", instructionsGameScreen);
//add it to the stage
addChild(MenuInstructions);
}
private function instructionsGameScreen(e:Event):void
{
var instructionsLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("instructionsScreen.swf");
instructionsLoader.load(url);
addChild(instructionsLoader);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
}
private function storyGameScreen(e:Event):void
{
var storyLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("storyScreen.swf");
storyLoader.load(url);
addChild(storyLoader);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
}
private function esc(e:KeyboardEvent):void
{
if (e.keyCode == 27)
{
//fscommand("quit");
/////////test//////////////////(new URLRequest(stage.loaderInfo.url), "FirstGame.swf");
}
}
private function playGameAgain(e:Event):void
{
//initialize variables
aMissileArray = new Array();
aEnemyArray = new Array();
nScore = 0;
nAmmo = 20;
Player.x = 262,95
Player.y = 323,30
Player.visible = true;
scoreTxt.visible = true;
ammoTxt.visible = true;
MenuStart.hideScreen();
MenuEnd.addEventListener("PLAY_AGAIN", playGameAgain);
MenuEnd.hideScreen();
updateScoreText();
updateAmmoText();
//trace("First Game Loaded");
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
stage.addEventListener(Event.ENTER_FRAME, gameLoop)
//creat an timer object
tEnemyTimer = new Timer(1000)
//listen for the timer ticks/intervals
tEnemyTimer.addEventListener(TimerEvent.TIMER, addEnemy)
//start our timer
tEnemyTimer.start();
}
I believe you should be able to start a new request on the same loader object. Either way, you're dealing with object creation + cleanup. The crux of the solution I'm offering is that you reuse your loaders.
Your current code is somewhat repetitious, so I've modified it slightly to demonstrate how you could simplify the code. Some thoughts while reviewing your code:
You're adding the same object to the stage multiple times (ie.,
MenuStart, MenuStory, MenuInstructions); these are all pointers to
the same root swf you loaded (a.k.a., startLoader).
You've registered events the stage at multiple locations. Best
practice is to place these in your constructor as they are
persistent.
Because you want to reuse your loaders at a later point, keeping a
table with them makes it easier to reference.
Any time you find yourself programming the same code in similar ways,
it's a good indication that you can simplify with a single function
(simply change the arguments).
Give this a try:
public var Player:MovieClip
private var leftKeyIsDown:Boolean;
private var RightKeyIsDown:Boolean;
private var aMissileArray:Array;
private var aEnemyArray:Array;
public var scoreTxt:TextField;
public var ammoTxt:TextField;
public var MenuEnd:EndGameScreen;
public var menuAgain:EndGameScreen;
private var MenuStart:mcStartGameScreen;
private var MenuStory:mcStartGameScreen;
private var MenuInstructions:mcStartGameScreen;
private var nScore:Number;
private var nAmmo:Number;
private var tEnemyTimer:Timer;
private var screens:Object = {
"SHOW_INSTRUCTIONS":{
"loader":new Loader(),
"url":new URLRequest("instructionsScreen.swf")
},
"SHOW_STORY":{
"loader":new Loader(),
"url":new URLRequest("storyScreen.swf")
},
"START_GAME":{
"loader":new Loader(),
"url":new URLRequest("startScreen.swf")
}
}
public function FirstGame() {
var startLoader:Loader = loadScreen({"type":"START_GAME"});
//Register our event listeners
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
stage.addEventListener(KeyboardEvent.KEY_UP, esc);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUp);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
stage.addEventListener(Event.ENTER_FRAME, gameLoop)
}
private function loadScreen(e:Object):Loader {
screens[e.type].loader.load(screens[e.type].url);
addChild(screens[e.type].loader);
return screens[e.type].loader;
}
public function startLoaded(e:Event):void {
//initialize variables
aMissileArray = new Array();
aEnemyArray = new Array();
nScore = 0;
nAmmo = 20;
Player.x = 262, 95
Player.y = 323, 30
Player.visible = true;
scoreTxt.visible = true;
ammoTxt.visible = true;
MenuEnd.addEventListener("PLAY_AGAIN", playGameAgain);
MenuEnd.hideScreen();
updateScoreText();
updateAmmoText();
//creat an timer object
tEnemyTimer = new Timer(1000)
tEnemyTimer.addEventListener(TimerEvent.TIMER, addEnemy)
tEnemyTimer.start();
var swfRoot = screens.START_GAME.loader["content"];
swfRoot.addEventListener("START_GAME", loadScreen);
swfRoot.addEventListener("SHOW_STORY", loadScreen);
swfRoot.addEventListener("SHOW_INSTRUCTIONS", loadScreen);
}
private function esc(e:KeyboardEvent):void {
if (e.keyCode == 27) {
//fscommand("quit");
// Loop through our loaders, and reset them all.
for each (var entry:Object in screens) {
entry.loader.unloadAndStop();
removeChild(entry.loader);
}
// Reload the start screen
var startLoader:Loader = loadScreen({"type":"START_GAME"});
startLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, startLoaded);
}
}
The last thing I want to be guilty of is telling you how to run your project, however, I think you may be taking the wrong approach, here.
Instead of setting up the story and the game as separate swf files, what you would probably need to do is set up the story as a MovieClip, and the game as a MovieClip. (Yes, MovieClips can contain other symbols, including other MovieClips.) Then, you'll want to hide/show or add/remove these MovieClips from your stage using code.
If you need to know how to do this, let me give you the age-old admonishment: RTD (Read the Documentation). These are basic tasks that are covered both in the online Adobe Flash documentation, and across numerous tutorials online.
I hope that helps!

trouble resetting a flash game

I'm trying to build a simple flash game in which I need to be able to restart the game if the user dies. However resetting all of the variables doesn't seem to be accomplishing anything. All of my game elements are stored in arrays and I thought that maybe setting each of them to the array constructor wasn't deleting the objects that they were pointing to and that they were left on the screen as a result. Does anyone know of a way to delete those elements (since I can't iterate over the list to delete them for obvious reasons) or does anyone know of a better way to reset a game in flash? For reference, here's the init function and the variable declarations at the top of my program that are supposed to start/reset the game.
public class Main extends MovieClip {
//put field variables here
static var hudLayer:Sprite; //layer used to represent HUD elements
static var gameLayer:Sprite; //layer used to represent objects in the game space
static var uiTextLayer:Sprite; //layer used to represent text that should appear ON TOP of the HUD
static var backgroundLayer:Sprite; //layer used to display the background image
static var players: Array; //array of all the player objects for reference
static var backgrounds:Array; //array of all the background objects
static var lines: Array; //array of all the lines
static var powerUps:Array; //array of all the powerups
static var enemies:Array; //array of all the enemies
static var miscellaneousObjects:Array; //array of miscellaneous objects that I'd like to be able to keep track of
var xCoords:Array, yCoords:Array; //Used to temporarily hold x and y coordinates when making new drawings
static var grav:Number; //coefficient representing the force of gravity
static var isPaused:Boolean; //manages pausing mechanic
static var timer:Timer; //used for time delayed updating of game elements
var pt:Point; //variable used by collision detection
var asteroidTiming:Number; //used to properly delay creating of asteroids on the screen
static var asteroidDelay:Number; //current delay between when asteroids are deployed, changes over course of execution
static var score:Number; //this should be self-explanatory
var scoreField:TextField; //used to display the score
static var myTextFormat:TextFormat; //used to format the text in the scoreField
static var inGameOver:Boolean; //used to determine if we're at the game over screen
[Frame(factoryClass="Preloader")]
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
public function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
//set up the Sprite Layers
backgroundLayer = new Sprite();
gameLayer = new Sprite();
hudLayer = new Sprite();
uiTextLayer = new Sprite();
addChild(backgroundLayer);
addChild(gameLayer);
addChild(hudLayer);
addChild(uiTextLayer);
//instantiate important variables
xCoords = new Array();
yCoords = new Array();
players = new Array();
backgrounds = new Array();
enemies = new Array();
powerUps = new Array();
miscellaneousObjects = new Array();
grav = .04;
addBackGround();
addPlayer(400, 50);
isPaused = false;
lines = new Array();
score = 0;
inGameOver = false;
//instantiate text fields
scoreField = new TextField();
scoreField.text = "Score: " + score;
hudLayer.addChild(scoreField);
scoreField.x = 20;
scoreField.y = 20;
scoreField.textColor = 0xFFFFFF;
myTextFormat = new TextFormat();
myTextFormat.size = 15;
scoreField.setTextFormat(myTextFormat);
//set up timer
timer = new Timer(5);
timer.addEventListener(TimerEvent.TIMER, function():void { update()});
timer.start()
asteroidTiming = 0;
asteroidDelay = 150;
//set up mouse listener
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownEvent);
//set up key listener
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyEvent);
//tests
}
Since I can't see all your code, I will guess that you are not using removechild() to get rid of display objects off the stage.
To create a object:
var object:DisplayObject = new DisplayObject();
To make it visible on the display list:
parent.addChild(object);
To remove it from the display list:
parent.removeChild(object);
To erase its memory:
object=null;
(These four things must be done in this order, for this to work properly. IF you make something null without removing it from the display list, you leave it there, still visible, with no way of referencing it. It like lost in your application.
You have to make sure you always use removeChild() before making a variable null, or overwriting the variable.

How to add pictures to a container Sprite with forEach and progress bar?

I am successful in loading a single image and creating it using addChild(). Now I am trying to load multiple images into a sprite "Container" using a forEach loop increasing the X value for each image so they are displayed in a row. The imageloader is referenced to linkage within an XML document. If I testrun this code, this error pops up at the point when the image is loaded and I try to removeChild() the loadBar Animation.
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
at flash.display::DisplayObjectContainer/removeChild()
Here is the AS3:
private function loadBG():void {
var artGrab:Number = 0;
var artX:Number = 0;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
ldrAnim.x = artX;
ldrAnim.y = 200;
imgLdr.load(imgURL);
artGrab++;
artX + 481;
ldrAnim.x + 481;
}
}
private function onLoading(evt:ProgressEvent):void {
var bytesToLoad:Number = imgLdr.contentLoaderInfo.bytesTotal;
var numberLoaded:Number = imgLdr.contentLoaderInfo.bytesLoaded;
ldrAnim.progBar.scaleX = numberLoaded / bytesToLoad;
var loadedPercent = Math.round(numberLoaded / bytesToLoad * 100);
ldrAnim.progPercent.text = loadedPercent + " %";
trace("Loading..." + loadedPercent + "%");
}
private function onBGLoaded(evt:Event):void {
trace("image loaded!");
//image setup
addChildAt(imgLdr,0);
//now that its 100% loaded, you can resize it , etc.
removeChild(ldrAnim);
//use cross multiplying of fractions to maintain aspect ratio
var origW = imgLdr.contentLoaderInfo.width;
var origH = imgLdr.contentLoaderInfo.height;
trace("orig width: "+ origW + "orig height: " + origH);
//set new width
imgLdr.width = 481;
var newH:Number = 481 * origH / origW;
imgLdr.height = newH;
//may wish to do positioning AFTER resizing
imgLdr.x = stage.stageWidth / 2 - imgLdr.width / 2;
imgLdr.x = 0;
imgLdr.y = 0;
imgLdr.width = 480;
imgLdr.height = 480;
imgLdr.alpha = 1;
imgLdr.z = 0;
}
Bless you for reading this all, I don't understand what is causing this error so comments are appreciated!
You need to have an array of animations for your loaders to hold with the loaders themselves, then when another ProgressEvent.PROGRESS event will arrive, query the array for event.target index, grab corresponding animation and adjust that, and stop relying on single-valued global vars once you put a single listener onto multiple different objects!
var animations:Vector.<AllLoader>;
var loaders:Vector.<LoaderInfo>;
private function loadBG():void {
var artGrab:int=0;
var artX:int=0;
animations=new Vector.<AllLoader>();
loaders=new Vector.<LoaderInfo>;
for each (var albumData:XML in mainXML.artist[artistID].album) {
imgURL = new URLRequest(mainXML.artist[artistID].album[artGrab].art);
imgLdr = new Loader();
//if you're loading a bigger image or need a preloader
imgLdr.contentLoaderInfo.addEventListener(Event.COMPLETE,onBGLoaded);
imgLdr.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoading);
//add loader animation "All Loader"
ldrAnim = new AllLoader();
albumContainer.addChild(ldrAnim);
anomations.push(ldrAnim)
loaders.push(imgLdr.contentLoaderInfo); // fill the arrays
ldrAnim.x = artX;
ldrAnim.y=200;
imgLdr.load(imgURL);
artGrab++;
artX+=481;
}
}
private function onLoading(evt:ProgressEvent):void{
var bytesToLoad:Number=evt.target.bytesTotal;
var numberLoaded:Number=evt.target.bytesLoaded; // note it now refers to target of event
var index:int=loaders.indexOf(evt.target); // should be valid
var ldrAnim:AllLoader=animations[index]; // grab corresponding animation
ldrAnim.progBar.scaleX = numberLoaded/bytesToLoad;
var loadedPercent=Math.round(numberLoaded/bytesToLoad*100);
ldrAnim.progPercent.text = loadedPercent +" %";
trace("Loading..."+loadedPercent +"%");
}
Do the same trick with your onBGLoaded function yourself, as a lesson. Note, you have to retrieve imgLdr value correctly from the event.
What's happening is that you have populated the variable ldrAnim multipe times, creating a new AllLoader each time. When you call removeChild(), this works fine the first time (sort of--it will remove the last one you created, whether it matches the image that loaded or not). When you call removeChild() again, you're calling it for the same one you just removed (which is no longer a child of the object you're calling it on).
One way to fix this is to use a Dictionary and associate each AllLoader with the Loader for that image. When the COMPLETE event fires, you can then look up the Alloader based on the event's properties and remove it.
Another solution is to write a Class that wraps an AllLoader and a Loader and then handles the transition between the two itself when the Loader has finished loading.
That might look something like this:
public class LoadSwitcher extends Sprite{
protected var loader:Loader;
protected var allLoader:AllLoader;
public function loadSwitcher(url) {
super();
loader = new Loader();
var request:URLRequest = new URLRequest(url);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchLoaders);
allLoader = new AllLoader(loader);//assume AllLoader now has logic to watch the loader for % complete
loader.load(request);
addChild(allLoader);
}
protected function switchLoaders(e:Event):void {
removeChild(allLoader);
addChild(loader);
}
}
Then just create and position one of these for each one of your albums.