Make all children do something...? - actionscript-3

I'm wondering if there is an easy way to make all children simultaneously do something. In particular, I want everything on my stage to shake back and forth like an earthquake. It's a bit hard to single out everything on stage and add in the proper code because at a given time I don't always know the amount of children on stage.
Also, I'm not sure if it makes a difference, but sometimes when I addChild something, I don't go out of my way to add it to the stage...Like for a few buttons I'll do this.addChild(mybutton). I don't know if there's a way to access everything that has been addChilded even though I may not have added them directly to the stage? I'm pretty sure numChildren returns the value of the number of objects on screen, but I could be wrong...
I was thinking of doing something like
Inside my loop
if (numChildren >= 10 && nukeShakeTimer.currentCount == 0)
{
nukeShakeTimer.start();
}
if (nukeShakeTimer.currentCount > 0)
{
NukeShake();
}
NukeShake
public function NukeShake():void
{
numberChildren = numChildren;
trace(numberChildren);
while (numberChildren > 0)
{
var tempObject:Object = getChildAt(numberChildren)
if (nukeShakeTimer.currentCount % 2 == 1)
{
tempObject.x += 10;
}
if (nukeShakeTimer.currentCount % 2 == 0)
{
tempObject.x -= 10;
}
numberChildren -= 1;
}
if (nukeShakeTimer.currentCount > 30)
{
nukeShakeTimer.reset();
}
}
When I try this though, I get a runtime error for the line var tempObject:Object = getChildAt(numberChildren) and the error reads RangeError: Error #2006: The supplied index is out of bounds.
Also I feel like it may be possible to do this operation much faster without using a while loop, but maybe not. Help please, thanks!

If you want to address every child on the stage then you'll need to loop through them. As Cherniv says, changing your getChildAt call to use numberChildren-1 should resolve your error.
It shouldn't matter whether or not everything is directly on the stage or not. Looping through the stage children will get you whatever container you added the objects to. Moving that container will move its children too. (Though you'll have to do more work if you need to move those children independently).
But...
In your specific case, it looks like you just want to shake everything on the screen together, in the same direction at the same rate. In this case, I would probably just add all my objects to a single container Sprite on the stage. Then, when you want to do a shake effect, you only need to move that one container object and everything moves together.

Related

Flash AS3 Remove Clip, reorder other items

I have a scrollpane to which I add movieclips to. I am using it a an online users list. It works well so far but now I have run into a problem. I am able to remove the movieclips I want easily enough using removechild, but when I remove it there is only a blank space where the removed clip was. So I need to know how to have the scrollpane refresh somehow and move the clips below that one removed up. How can I do this?
I have tried invalidate, refreshPane, update, etc. Maybe I didnt have them in the correct order or something, but how can this be done?
If the answer is complex, could an example be provided please? Im really not good enough with as3 just yet to code an entire algorithm to get the number of children, remove them all, readding them, etc.
Any help please?
Just a variation, but saves the -1, simply rearrange such as:
lstOnline.removeChild(lstOnline.getChildByName("NAMEHERE"));
var numleft:Number = lstOnline.numChildren;
for(var i = 0; i < numleft - 1; i++) {
lstOnline.getChildAt(i).y = i*60;
}
Guess I was a little better than I thought. In case anyone else faces this problem, the solution I found was the following:
var numleft:Number = lstOnline.numChildren;
lstOnline.removeChild(lstOnline.getChildByName("NAMEHERE"));
for(var i = 0; i < numleft - 1; i++) {
lstOnline.getChildAt(i).y = i*60;
}
lstOnline is the name of the ScrollPane and in my case 60 is the height of the added movieclips.

Generalizing instance name in ActionScript3

Imagine there is a situation : I have 100 movieclips with instance names : MC1a, MC2a, MC3a .. MC100a
and i want all of them to be invisible is there any other way than :
MC1a.visible = false; ... MC100a.visible = false;
because in this way the code gets very heavy and i thinks it's not the right way. so i was thinking is there any possible way to be something like that :
MC*a.visible = false;
all the movieclips that contains 'MC' in the begging and 'a' and the ending to disappear ? maybe something with array ?
If the parent of all these movieclips is called container you can do :
container["MC"+i+"a"].visible=false
This is due to the script nature of ActionScript.
For your particular case you can do
for(i=0;i<100;i++){
container["MC"+i+"a"].visible=false;
}
If you don't have all number between 0 and 100 you can do something like this :
for each(MovieClip mc in container){
name=mc.name;
if(name.substring(0,2)=="MC" && name.substring(-1)=="a"){
mc.visible=false;
}
}
(This is non tested pseudocode written on the fly)
There are several ways you can achieve this. First - make a Sprite container, which will be their common parent, then alter its visibility. This is not a flexible way, for example, if your movie clips are located on two different areas of stage, and need to interact somehow, you might be unable to put them all under a single parent in your display list. The second way is to make an array out of those 100 movie clips at the time of their instantiation (if possible, of course), then you iterate through the array and assign their visibility in a loop.
Basically, if you have some objects that should form a structure, consider linking them somehow first, then altering their visibility or other parameters all together. Should you need to move them all at once, or hide, the container approach will be better. Should you need them to perform similar, but not exactly same actions (say you have monsters as movie clips, and you need them to move together, but each with their own direction and speed), you should have an array.
Another thing to consider, if there is a movie clip that has a name like "MCbig_a", that is, complies with your condition, but does not exactly belong to the group of MCs you desire to make invisible, you will have to take precautions about such occurrences.
Assuming that al children are added in the same container called myContainer
var container:MovieClip = myContainer;
var i:uint = container.numChildren;
while (i--)
{
var child:* = container.getChildAt(i);
child.visible = false;
}

Flex AS3 : Find and remove elements from container of certain class

How can I remove only every image found in a Bordercontainer which also holds Textinputs and Buttons ?
i tried:
for(var i:int=0;i<container.numElements;i++){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);}
}
But as expected this loop does not fully work since the numElements changes which means that not all Images get removed.
I know there is some simple trick to this...but I cant think of it right now...Please help
As commenters have suggested, it seems like looping backwards would be the way to do it. I'd try something like this:
var totalElements : int = container.numElements;
for(var i:int=totalElements-1;i>=0;i--){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);
}
}
By storing the numElements in a variable before starting the loop, you can be sure that the value will not change while processing the loop. Since your going backwards, you don't have to worry about the child index changing.
A second option would be to queue up the image instances in one loop and remove them in a second loop using the removeElement method. I suspect the two loop method will have significantly worse performance.
Looping backwards would be 1 way to do this.
Another would be
for(var i:int=0; i<container.numElements; i++){
if(container.getElementAt(i) is Image){
container.removeElementAt(i);
i--; //This nullifies the effect of removing an element
}
}

How to know if a popup is already showing up on the screen in flex

I need to know if a popup (which is a singleton titlewindow, hence would be initialized only once) is already shown in the screen or not, if not then i will call a function to show it up, otherwise do something else.
I tried findPopup.focusEnabled //findPopup is the titlewindow class for popup
But it is always true irrespective of whether the popup is shown in the screen currently or not.
Thanks.
Use isPopUp
Set to true by the PopUpManager to indicate that component has been
popped up.
All objects rendered on the screen have a root:DisplayObject property. If it is removed from the screen, then root will be null. If your concern is whether the pop-up is in front of everything else, then use popUpObj.parent.setChildIndex(popUpObj, popUpObj.parent.numChildren - 1) to ensure it (more on this below). You will need to iterate through all of the parent until you reach the root itself. (With the PopUpManager, I believe that the MovieClip is added directly to the root, so it should only be once, but I don't recall at the moment)
Everything else is obvious:
is alpha = 1?
visible = true?
is width > 5
is height > 5
... I could continue, but I think the idea is pretty clear.
On testing visibility of obscured objects:
Honestly, this is easiest to do on the root.
var firstParent:DisplayObjectContainer = /*
find the ancestor which is on
the root. You may need to look up
"path to root AS3"
*/
var num:int = root.numChildren;
//iterate backwards to exclude things below the target clip.
for( var i:int = num - 1; i >= 0; i-- )
{
var kid:DisplayObject = root.getChildAt( i );
if( kid == firstParent ) break; // no sense in continuing.
if( firstParent.hitTestObject( kid ) )
{
// kid at least partially obscures the pop-up. Do something with it.
}
}
You can check if the object exists with an if block
if(findPopup)
findPopUp.visible=true;
assuming you turned of the visibility off to hide the window. You can of course destroy the object and recreate it if desired. In this case, you don't need that if block because it'll be reconstructed from scratch.
You can still use that if logic to be sure if somewhere in your code, something has already created your popup object. Maybe another class will be doing that behind the scenes so the basic idea is to guarantee that such object exists or not.
[Edit:]
Didn't know you were using PopUpManager. Please use Ranhiru Cooray's answer.
A reminder that PopUpManager has it's own method to put a pop up in front of all other objects: bringToFront(popup)
[/Edit]
Are you trying to find out if the pop up has been added to the stage or if it is still actually visible on the screen and not hidden behind other display objects ?
If it's the first, you could find out with a search (flex 3)
// popUpContainer is the object containing the pop up
if (popUpContainer.contains(FindPopup.getInstance()))
{
// The popup was added to stage
}
else
{
popUpContainer.addChild(FindPopup.getInstance());
}
If it's the second, you could make sure it is visible by adding it to the application root and making sure it has the highest index. But it's hard to test if it's actually being shown on the screen, since it could be 40% or 60% hidden behind other objects.
// Placing the pop up on top of other display objects in the application root
this.setChildIndex(FindPopup.getInstance(), this.numChildren - 1);

Random position without overlapping

How to stop MCs from overlapping each other?
private function loadWishes():void {
for (i; i<myXMLList.length(); i++) {
cBox=new MovieClip();
checkOverlap(cBox);
addChild(cBox);
commentArray.push(cBox);
}
}
private function checkOverlap(wishB:MovieClip) {
wishB.x=Math.random()*stage.stageWidth;
wishB.y=Math.random()*stage.stageHeight;
for (var i:uint=0; i<commentArray.length; i++) {
if (wishB.hitTestObject(commentArray[i])) {
checkOverlap(wishB);
return false;
}
trace(commentArray.length);
}
}
This doesn't seems to be working cause the amount of it checking whether MC is overlapping is about the amount of MC on stage. how to make it keep checking till everything's fine?
The code you have here should work in general for preventing overlapping (though you should be careful - in a worst-case scenario this code might loop infinitely if the clips are too big or the stage is too small).
However, your problem is that you're calling this code on newly-created MovieClip objects, which are empty - so they can never overlap. Presumably you're adding in some child contents to the clips later, and at that point they overlap. So the fix is, you should populate the clips first, before checking if they overlap, or alternately, if you know the size of the clips, then instead of calling hitTestObject you could manually check whether the clip's position is too close to other clips.