AS3 How to remove previous loaders - actionscript-3

In Flash CS4, I'm creating a photo gallery. My goal is to load different thumbnails from a number of images. I have managed that when one clicks an image, a number of thumbnails are being displayed, but when one clicks another image, the new thumbnails are placed on top of the old ones. Can someone help me on how to get rid of the old thumbnails?
Here is the code:
for (var i:int = 0; i < thumbnails.length(); i++) {
imgLoader.unload();
imgLoader = new Loader();
imgLoader.load(new URLRequest(thumbnails[i]));
imgLoader.name= i;
imgLoader.x = 95 * columns;
imgLoader.y = 80 * rows;
imgLoader.alpha = 0;
details.gallery.addChild(imgLoader);
if (columns+1< 5) {
columns++;
} else {
columns = 0;
rows++;
}
}

This is where an Array is your friend. You could do this without an array by merely using a while loop to remove every last child from the sprite or movieclip that you added the thumbs to. The reason we use arrays is so that we can reuse the thumbs, instead of reloading them we merely remove them from the display list. You push a reference to each object into an array for each thumb as you add it to the display list. Each thumbContainer node in the XML gets its own array which get added to the main array. The main array holds references to thumbnail arrays. Thumbnail arrays hold references to loaded thumbnails so that they can be added and removed from the display list. If you plan to never use the thumbs after they have been seen once you may set it's reference equal to null, otherwise merely remove it from the display list; There is no reason to load it many times. When you are ready to add the new thumbs you must clear out previous thumbs. The easiest way to do this is with a while loop.
//Assuming the thumbs were loaded into container
while(container.numChildren > 0)
{
//Remove the first child until there are none.
container.removeChildAt(0);
}
//The XML / 2 Containers / thumbContainer[0] and thumbContainer[1]
<?xml version="1.0" encoding="utf-8"?>
<xml>
<thumbContainer>
<thumb path="path/to/file" />
<thumb path="path/to/file" />
<thumb path="path/to/file" />
</thumbContainer>
<thumbContainer>
<thumb path="path/to/file" />
<thumb path="path/to/file" />
<thumb path="path/to/file" />
</thumbContainer>
</xml>
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
public class DocumentClass extends Sprite
{
private var _container:Sprite;
private var _mainArray:Array;
private var _xml:XML;
private var _urlLoader:URLLoader;
private var _urlRequest:URLRequest;
public function DocumentClass():void
{
if(stage) _init();
else addEventListener(Event.ADD_TO_STAGE, _init, false, 0 , true);
}
private function _init(e:Event = null):void
{
//Will contain arrays for each thumbContainer in the XML.
_mainArray = [];
_urlRequest = new URLRequest('path/to/xml');
_urlLoader = new URLLoader();
_urlLoader.addEventListener(Event.COMPLETE, _onXMLComplete, false, 0, true);
}
private function _onXMLComplete(e:Event):void
{
_xml = new XML(e.target.data);
_loadThumbs(0);
}
private function _loadThumbs(pIndex:int):void
{
_clearThumbs();
//Find out how many sets of thumbs there and add to _mainArray
for(var i:int = 0; i < _xml.thumbContainer.length(); i++)
{
var tempArray:Array = new Array();
for(var j:int = 0; j < _xml.thumbContainer[i].thumb.length; j++)
{
tempArray[i].push(_xml.thumbContainer[i].thumb[j].#path);
}
_mainArray.push(tempArray);
}
//Here is where we add the new content to container, or you can call a function to do it.
}
private function _clearThumbs():void
{
while(container.numChildren > 0)
{
//Remove the first child until there are none.
container.removeChildAt(0);
}
}
}
}
Again, it is good practice to hold a reference to something that is reusable and to simply remove it from the display list instead of setting to null and prepping for garbage collection only to be loaded again later. I already have written more than I intended and wasn't able to slap in all the code I wanted. It is important to setup the code that makes sure it only loads a particular set of thumbs once; That is the whole idea. As for removing them, it's as simple as the while loop I showed you, you just need to know the name of the DisplayObjectContainer that parents them.

You are adding new thumbnails to your gallery object via the addChild() methods, so you should call a method that removes all thumbnails from the gallery before adding new ones.

I believe it is removeChild() you should use.
I had some very weird problems with this not long ago, causing all sorts of crazy hit collisions and what not. My solution were to call removeChild() on the object I wanted to remove, and then I set it to "null". Prior to this I had a check if the object were null (can't removeChild something that's null).
Can't guarantee this is how you "should" do it, as I'm pretty newbie to the Actionscript scene myself. Hope it solves your problem.

You can remove them by passing the object into details.gallery.removeChild(object) or by index using details.gallery.removeChildAt(index). If you use removeChild(), be sure to check for a null or it will throw an error.
Make sure to check out the flash help files, they're by far the best resource you can use.

This will remove all children within a movieclip called gallery:
while( gallery.numChildren > 0) { gallery.removeChildAt(0); };

Related

AS3 I can't get removeChild to delete my items when they are listed in Array

using ActionScript 3 on Animate, I'm trying to delete a bunch of items from the stage using Array and for loop. I actually downloaded this code from this site, but it doesn't seem to work for me. It will only delete one item and won't delete the others. and when I redraw the stage it will then not delete anything at all. I have another function button down the road that will restart (redraw) the game, I'm using the gotoAndPlay() to redraw. FYI, the "squares" are sprites and the "myTFs" are text fields that are 'paired' together to become buttons. What am I doing wrong?
function mainFunc(): void {
var btnsArray: Array = new Array("square", "myTF3", "square2", "myTF2", "square4", "myTF4");
for (var ii = 0; ii < btnsArray.length; ii++) {
removeChildAt(btnsArray[ii]);
btnsArray.length = 0;
}
}
If you have an Array of DisplayObject's names you want to batch operate (e.g. remove from display list or something else) you can do the following:
var A:Array = ["square", "myTF3", "square2", "myTF2", "square4", "myTF4"];
// Iterate over items of the Array.
for each (var aName:String in A)
{
// Obtain a reference to the object by its instance name.
var aChild:DisplayObject = getChildByName(aName);
// Check if it is a valid instance before removing to avoid errors.
if (aChild)
{
removeChild(aChild);
}
}

ActionScript 3: Adding multiple instances of the same object to the stage and removing each separately

I have a piece of code adding three insances of the same MovieClip to the stage. I also added MouseEvent.CLICK listener. Once any of the MovieClips gets clicked, I want it to be removed from the stage. My problem is, whenever any of the elements gets clicked, only the last one gets removed and when I click again on a different instance, I'm getting:
ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.
I added these three MovieClips to an array, but I don't know how I can properly identify which instance got clicked and remove only the said instance.
This is the excerpt of code I have:
var myMC: SomeMC;
var myArray: Array = [];
function Loaded(e: Event): void {
for (var i: int = 0; i < 3; i++) {
myMC = new SomeMC();
myMC.addEventListener(MouseEvent.CLICK, Clicked);
myMC.y = 50;
myMC.x = 50 * i;
addChild(myMC);
myArray.push(myMC);
}
}
function imageClicked(e: MouseEvent){
// Only the last instance gets removed.
e.currentTarget.parent.removeChild(myMC);
}
I'd be grateful for any help.
In Loaded function you create 3 instances of the object, but by doing:
myMC = new SomeMC();
you overwrite reference. In first iteration myMC is 1st one, in 2nd 2nd one, etc...
Then in imageClicked you're trying to remove it. 1st time it's working because it's referencing the last object, but after you removed it from stage it won't work anymore.
How about changing e.currentTarget.parent.removeChild(myMC); to e.currentTarget.parent.removeChild(e.currentTarget); ? That should remove clicked one.

as3 animation with multiple images

I have only 3 images that I'm working with for animating a running animal:
1: animal standing
2: animal in stride/jumping
3: animal on its back dead
Currently, I'm embedding them into the main class as sprites and changing their .alpha properties whenever I want one and not the other 2. Is there a better way to do what I'm doing? One of the annoying things is updating the properties for each sprite individually. It would be ideal to have one object and being able to change the image on the object so I would only have to change one object's properties.
For this it would be best to handle your animation in its own Class!
Something like this, let's say your animal is a horse so that's what I'll call the class
package {
import flash.display.Sprite;
public class Horse extends Sprite{
private var holder:Sprite = new Sprite();
public function Horse() {
var img1:Image1 = new Image1();// ur images from library
var img2:Image2 = new Image2();
var img3:Image2 = new Image3();
holder.addChild(img1);
holder.addChild(img2);
holder.addChild(img3);
addChild(holder);
setImage(0);// set 1st image visible
}
public function setImage(nr:uint):void
{
for(var i:int = 0; i < holder.length;i++;)
holder[i].visible = false;
holder[nr].visible = true;
}
}
}
then you would use it like this for example!
var horse:Horse = new Horse();
addChild(horse);
horse.x = 25;
horse.y = 25; // move the whole object(all 3 images)
horse.setImage(2);// or to whatever frame you need
Use the visible attribute instead of the alpha value. If u just set alpha to 0 it will still be rendered and cost cpu. if you set visible to false it will not be rendered!
EDIT: As Amy pointed out, blitting is a possibilty here to, although the fastest aproach would be BitmapData Frame Assignment!
Here you keep all your Frames as BitmapData in a Vector, which you load from a SpriteSheet and just assign the new BitmapData to your Bitmap instead of using copyPixels. It's faster then blitting and you still have all your builtin methods availible!!

I can't seem to access automatically named objects (instance##) placed on the stage in AS3, am I missing something?

I have a movieclip in the library that is added to the stage dynamically in the document class's actionscript. This movieclip contains many many child images that were imported directly from photoshop at their original positions (which must be preserved).
I do not want to manually name every single image instance, as there are dozens upon dozens.
I have already gone through and manually converted the images to symbols, as apparently flash won't recognize the "bitmap" objects as children of a parent movieclip in AS3 (numChildren doesn't see the bitmaps, but it sees the symbols).
I have an array filled with references to the dozens of children, and I loop through it, checking if each one is under the mouse when clicked. However, somehow, it is not detecting when I click over the items unless I manually name the child symbols (I tested by manually naming a few of them -- those ones became click-sensitive.)
I have already done trace() debugging all throughout the code, verifying that my array is full of data, that the data is, in fact, the names of the instances (automatically named, IE instance45, instance46, instance47, etc.), verifying that the function is running on click, verifying that the code works properly if I manually name the symbols.
Can any one see what's going wrong, or what aspect of flash I am failing to understand?
Here is the code:
//check each animal to see if it was clicked on
private function check_animal_hits():void
{
var i:int = 0;
var animal:Object = this.animal_container;
for (i=0; i<animal.mussels.length; i++)
{
if (this.instance_under_cursor(animal.mussels[i].name))
{
var animal_data = new Object();
animal_data.animal = "mussel";
this.send_data(animal_data);
}
}
}
Here is the code for the instance_under_cursor() method:
// Used for finding out if a certain instance is underneath the cursor the instance name is a string
private function instance_under_cursor(instance_name)
{
var i:Number;
var pt:Point = new Point(mouseX,mouseY);
var objects:Array = stage.getObjectsUnderPoint(pt);
var buttons:Array = new Array ;
var o:DisplayObject;
var myMovieClip:MovieClip;
// add items under mouseclick to an array
for (i = 0; i < objects.length; i++)
{
o = objects[i];
while (! o.parent is MovieClip)
{
o = o.parent;
}
myMovieClip = o.parent as MovieClip;
buttons.push(myMovieClip.name);
}
if (buttons.indexOf(instance_name) >= 0)
{
return true;
}
return false;
}
Update:
I believe I have narrowed it down to a problem with getObjectsUnderPoint() not detecting the objects unless they are named manually.
That is the most bizarre way to find objects under mouse pointer... There is a built-in function that does exactly that. But, that aside, you shouldn't probably rely on instance names as they are irrelevant / can be changed / kept solely for historical reasons. The code that makes use of this property is a subject to refactoring.
However, what you have observed might be this: when you put images on the scene in Flash CS, Flash will try to optimize it by reducing them all to a shape with a bitmap fill. Once you convert them to symbols, it won't be able to do it (as it assumes you want to use them later), but it will create Bitmpas instead - Bitmap is not an interactive object - i.e. it doesn't register mouse events - no point in adding it into what's returned from getObjectsUnderPoint(). Obviously, what you want to do, is to make them something interactive - like Sprite for example. Thus, your testing for parent being a MovieClip misses the point - as the parent needs not be MovieClip (could be Sprite or SimpleButton or Loader).
But, if you could explain what did you need the instance_under_cursor function for, there may be a better way to do what it was meant to do.

How do I remove a bunch of dynamically created things from the stage?

I am trying to delete a bunch of different things from the stage all at once.
I have 3 dynamically created text fields and 2 dynamically created movie clips.
I added them to the stage through my document class buy creating them, editing their properties and then...
addChild(myText1);
addChild(myText2);
addChild(myText3);
addChild(myMovieClip1);
addChild(myMovieClip2);
I want to delete them all and I have tried...
removeChild(myText1);
ETC
But this doesn't work.
can anyone help me.
If you want to remove everything from the current object, you can do :
while (numChildren > 0) removeChildAt(0);
If your DisplayObjects are on the stage, you can do :
stage.removeChild(myText1);
If you only want to be able to delete those specific objects, then you'll need to store references to them somewhere.
An alternative solution would be to populate the .name property of each object when you create it, and then use that name at a future time to grab a reference to the object:
var __dynamicMovieClip:MovieClip = new MovieClip();
__dynamicMovieClip.name = "foo";
addChild(__dynamicMovieClip);
And then at some later time:
removeChild(getChildByName("foo"));
getChildByName carries quite a bit of overhead though, so it's really not a good idea to call it repeatedly, or in a situation where the current display list is complex/deep
You need to have member variables for each of the dynamically created objects so you can reference them outside of the function you used to create them. If you only need a reference to remove them from the stage, an array will work great.
private var objectsToDelete : Array = [];
private function someFunction ( ) : void
{
objectsToDelete.push(myText1);
objectsToDelete.push(myText2);
objectsToDelete.push(myText3);
objectsToDelete.push(myMovieClip1);
objectsToDelete.push(myMovieClip2);
}
private function removeObjects () : void
{
var i : int = 0;
var max : int = objectsToDelete.length;
for ( i; i < max; i++ )
{
removeChild( objectsToDelete[ i ] );
}
}