Push instance name of movieClip into array using a for-loop - arrays

I have a bunch of movieclips on the stage with instance names ball1 - ball200. I was hoping I didn't have to create an array and manually set all the instance names into the array
ballArray = [ball1, ball2,ball3, etc];
I was trying to get a for loop to cycle through and add each instance name to my array like so:
function createTheArray():void{
for(var i:int = 1; i < 20;i++){
ballArray.push(ball + i);
trace(newArray[i])
}
}
But I keep getting back undefined array index's. It also tells me that I doesn't know what "ball" is. How would you use part of a instance name and combine it with the index value of the loop. So that the first time through you get ball1 as the first index value of your array?

Dragging out 200 balls onto the timeline and giving them instance names doesn't sound like much fun!
BEST OPTION:
right click the ball object and go to the properties, click "export for actionscript" and give it a unique name. (Lets call it MyBall for this example)
in your timeline code do this:
var ballArray:Vector.<MyBall> = new Vector.<MyBall>();
for(var i:int=0;i<200;i++){
ballArray.push(new MyBall());
addChild(ballArray(ballArray.length-1));
}
NEXT BEST OPTION
if all your balls are on the timeline already, you can still do the step from above (export for actionScript and give it a name) but do the following code:
var ballArray:Vector.<MyBall> = new Vector.<MyBall>();
var i:int = numChildren;
while(i--){
if(this.getChildAt(i) is MyBall) ballArray.push(this.getChildAt(i) as MyBall);
}
ANOTHER OPTION
If your balls are not all the same library objects, if you put them all as the only objects in a movie clip container (let's say you gave it the instance name ballContainer, you can still use this code so you don't have to give them instance names:
var ballArray:Vector.<DisplayObject> = new Vector.<DisplayObject>();
var i:int = ballContainer.numChildren;
while(i--){
ballArray.push(ballContainer.getChildAt(i));
}

You can use a string in brackets to get a property of an object. In your case, your object is referred to as this. So your syntax for getting a ball is this["ball"+index].
Try this:
function createTheArray():void{
for(var i:int = 1; i < 20; i++){
ballArray.push(this["ball" + i]);
}
trace(ballArray);
}
Referencing Properties by String isn't really a great practice though. If it's possible to create your balls dynamically as well, that would be a better implementation. You can create a ball MovieClip on your timeline, and select Export For ActionScript in the properties. Then you can use this code to instantiate 20 or more balls:
//add 20 balls to stage
var ballArray:Array = [];
for(var i:int = 0; i < 20; i++){
var ball:Ball = new Ball();
addChild(ball);
ballArray.push(ball);
}
trace(ballArray);

Related

In a form, I need to populate the contents of same spreadsheet column like 50 times. Is there a way to script this logic with fewer iterations

I'm working on a form where I need to pull the contents of a spreadsheet column like 50 times, to try to input multiple items from a list. I see that I can do this by defining a few variables and redoing a small piece of Script again and again. I want to see if anyone can help me overcome this lengthy script to make it smaller with fewer iterations. Thanks.
function updateForm(){
// call the form and connect to the drop-down items
var Form_SQ = FormApp.openById("FORM ID");
var SQ_IT01_List = Form_SQ.getItemById("ITEM 01").asListItem();
var SQ_IT02_List = Form_SQ.getItemById("ITEM 02").asListItem();
//Similarly defining upto 50 dropdown lists.
var SS01 = SpreadsheetApp.getActive();
var SQ_IT01_Names = SS01.getSheetByName("Sheet2");
var SQ_IT02_Names = SS01.getSheetByName("Sheet2");
//Similarly defining upto 50 names lists.
// Item_01 Part Number Dropdown
var SQ_IT01_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT01_Names.getMaxRows() - 1).getValues();
var SQ_IT01_Items = [];
for(var i = 0; i < SQ_IT01_Values.length; i++)
if(SQ_IT01_Values[i][0] != "")
SQ_IT01_Items[i] = SQ_IT01_Values[i][0];
SQ_IT01_List.setChoiceValues(SQ_IT01_Items);
// Item_02 Part Number Dropdown
var SQ_IT02_Values = SQ_IT01_Names.getRange(2, 1, SQ_IT02_Names.getMaxRows() - 1).getValues();
var SQ_IT02_Items = [];
for(var i = 0; i < SQ_IT02_Values.length; i++)
if(SQ_IT02_Values[i][0] != "")
SQ_IT02_Items[i] = SQ_IT02_Values[i][0];
SQ_IT02_List.setChoiceValues(SQ_IT02_Items);
//Similarly defining upto 50 lookup lists.
}
Problem
Reusing code and making use of loops. Scripting is all about efficiency (see DRY principle): make as little assignments and same-functionality coding as possible - use loops, move reusable code snippets to functions that can be called on demand, etc.
Solution
This sample makes several assumptions:
SQ_IT01_Names is different for each item (in your sample it always is Sheet2 - if this is the case, you don't have to reassign it 50 times, one variable assignment will do just fine).
You intended to do something when a value is an empty string (the sample just filters them out). As you use the [index] notation, those values in the resulting Array will be undefined (and that's not something one would want in an Array of choice values).
All items are choice items (if you need id filtering, the sample is easily expanded).
function updateForm() {
var form = FormApp.openById("FORM ID");
//access every item;
var items = form.getItems();
var ss = SpreadsheetApp.getActive();
//loop over items;
items.forEach(function(item,i){
var namesSheet = ss.getSheetByName('Sheet'+i); //assuming this is diff each time;
var namesRange = namesSheet.getRange(2,1,namesSheet.getLastRow());
var namesValues = namesRange.getValues();
//map values to first column;
namesValues = namesValues.map(function(value){
return value[0];
});
//filter out undefined (undefined and false functional equivalence);
namesValues = namesValues.filter(function(value){
return value;
});
item.asListItem().setChoiceValues(namesValues);
});
}
Notes
Please, use closures {} with loops and if statements, this way you'll be able to keep track of which statements are enclosed in it and save yourself debugging time when looping / conditioning multiple statements.
Since you only need rows that have data in them, use the getLastRow() method instead of the getMaxRows()-1 calc you have to perform in your script.
Reference
forEach() method reference;
filter() method reference;
map() method reference;
getLastRow() method reference;

Array whose each clip is linked to its equal clip of another array

Hello I apologize in advance for my question which I'm sure is pretty basic.
On a map are set 33 landmarks with an array calling a class in the library.
A second array defines the coordinates of those landmarks.
for (var i:uint = 0; i < 33; i++) {
mark[i] = new landMark();
landMarks.addChild(mark[i]);
mark[i].x = lmxy[i]['x'];
mark[i].y = lmxy[i]['y'];
}
var lmxy:Array = [{x:1620,y:880},{x:1850, y:1050},etc...];
So far so good, the landmarks show each in its right place.
The third array contains different legends supposed to show when a landmark is clicked.
So the landmark [1] should show the legend [1] and the landmark [31] the legend [31]
var lgd:Array = [lgdA, lgdB, etc... ];
var legends:MovieClip;
for (var j:uint=0;j<lgd.length;j++) {
legends = new lgd[j]();
legends.x = 300;legends.y = 170;
}
Edit cause obviously that was unclear :
I tried that in the loop to link the marks to the legends but I get an error :
mark[i].addEventListener(MouseEvent.CLICK, getLgd);
function getLgd(e:Event):void {stage.addChild (lgd[i]);}
Any help would be very welcome !
The problem is that the variable i doesn't have a definition. The only way for you to find out which of the landmarks were clicked is to find its index in the array, then you can add the legend that has the same index. Because the index isn't passed from the event listener, you need to use e which has the target property.
This should do the trick:
mark[i].addEventListener(MouseEvent.CLICK, getLgd);
function getLgd(e:Event):void
{
var i:int = mark.indexOf(e.target);
stage.addChild(lgd[i]);
}

actionscript 3: how to access to elements of an array created in a loop dynamically

In the library of the .fla file I have a square exported as Class "cuad" on frame 1
I want to create an Array with 100 squares so as to move them later
So I do like this:
for (var i:uint = 0; i<100;i++)
{
var cuad_mc = new cuad();
addChild(cuad_mc);
myArray.push("cuad_mc");
trace(myArray[i]);
}
I have a runtime error
The error you experience is
Error #1069: Did not find alpha propiety in the String and there is not any value predetermined
The problem comes from your line
myArray.push("cuad_mc");
What you are doing here is pushing a String Object into your Array, not the cuad Object you want. String Objects don't have Alpha values, or x values.
What you want to do is
myArray.push(cuad_mc);
cuad_mc (without the " quotation marks) is a reference to the object you just created.
This should solve your problem. I also recommend using Vectors instead of Array if you only need to store one type of Object. Like this:
var myArray:Vector<cuad> = new Vector<cuad>();
for(var i:int=0;i<100;i++){
var cuad_mc:cuad = new cuad();
addChild(cuad_mc);
myArray.push(cuad_mc);
trace(myArray[i]);
}
Vectors are just like Arrays, but they only allow one specific type, so that a situation like yours doesn't occur.

How to keep track of objects in an Array?

I need help in keeping track of objects in an array. I have tried giving each object an arrayIndex var, so I can splice by getting that var which represents the index in the Array.
object0.arrayIndex = 0;
object1.arrayIndex = 1;
object2.arrayIndex = 2;
object3.arrayIndex = 3;
But this is problematic if you move objects to different arrays. Objects would move from different places and therefore the arrayIndex var needs to be constantly updated.
I have done this by adding an static ID to each object. With a for loop I check each object for the corresponding object ID I want to splice
var objectID:Number = objectArrayTarget.id;
for (var t:int; t<_objectArrayLayer1.length; t++)
{
if (objectID == _objectArrayLayer1[i].id)
{
var indexOfObject:Number = (_objectArrayLayer1.indexOf(_objectArrayLayer1[i]));
}
}
_objectArrayLayer1.splice(indexOfObject, 1);
While this works is there a more efficient way of keeping track of objects in an Array? With 100+ objects this might create some slowdown
P.S. These objects are getting spliced and then pushed to a new array.
If your "Objects would move from different places" means same object from one place to another place, there is no arrayIndex needed
var indexOfObject:Number = _objectArrayLayer1.indexOf(targetObj);
if (indexOfObject >= 0) {
_objectArrayLayer1.splice(indexOfObject, 1);
}
If it means different object, like a copy, you could compare some properties to get the targetObj
for (var t:int = 0; t<_objectArrayLayer1.length; t++)
{
if (targetObj.id == _objectArrayLayer1[i].id)//assume id is unique key of the object
{
break;//i is the index here
}
}
if (i != _objectArrayLayer1.length) {//find target object
}
If the object type has a unique key, like a id, or you can make a unique key with some properties of the object, like name + "_" + order, you could use dictionary, Like Patel mentioned.
var dic:Dictionary = new Dictionary(true);
dic[obj1.id] = obj1;
dic[obj2.id] = obj2;//assume id the unique key,or you can use other key
So you can find obj like this
var obj:Object = dic[target.id]
Instead of using an Array.
I think you should use a Set implementation like Hashset
You'll get constant-time lookup, no sorting required,you can add,remove and lookup for object.

Displaying all items in an array in a dynamic textfield [Actionscript 3]

I have an array of items which I would like to be displayed within a dynamic textfield to form a high score list.
The amount of items within the arraylist with vary depending on how many high scores are added to it. It is created as standard like this:
var lvl1ScoreArray:Array = new Array();
And items are added to it within the following code:
if (currentLevel == 1)
{
lvl1highScores.push({score:int(vinylCollected) , player:String(highScoreInput.text)});
lvl1highScores.sortOn("score", Array.DESCENDING | Array.NUMERIC);
}
I can obviously trace all the items in the array as follows:
for (var i:int = 0; i < lvl1highScores.length; i++)
{
trace(lvl1highScores[i].score, lvl1highScores[i].player);
}
But I would like to do this within a dynamic textfield called highScoreTxt.. Any suggestions?
That is simple, just create a movie clip with a text field in it with an instance name of txt. Name the movie clip HighScoreTF and set its linkage to HighScoreTF Then your for loop will looking something like so
for (var i:int = 0; i < lvl1highScores.length; i++)
{
var tf:HighScoreTF = new HighScoreTF();
tf.txt.text = lvl1highScores[i].score + " - " + lvl1highScores[i].player;
tf.y = i * tf.height; //-- you can replace tf.height with a number to adjust spacing
addChild(tf);
}

Resources