How to detect how many objects are in the display object? (AS3) - actionscript-3

I'm making a game in which coins are randomly generated. Once a coin (multiple on the screen at once) is collected it respawns in another location. I have a few ways of doing this, but to advance I need these questions answered:
How would I go about detecting how many objects are in the display list?
How to detect when an object is removed from the display list?
All answers are appreciated in advance.

for detecting number of objects, you could do a recursive function that loops through each all children, and returns the count
import flash.display.DisplayObjectContainer;
function numAllChildren($do:DisplayObjectContainer):int{
var $c:int = 0;
for (var $i:int = 0; $i < $do.numChildren; $i++){
if($do.getChildAt($i) is DisplayObjectContainer){
$c += numAllChildren($do.getChildAt($i) as DisplayObjectContainer);
}
$c++;
}
return $c;
}
trace(numAllChildren(_mc));
To see if there has been a change, you'd use an event listener on ADDED and/or REMOVED. But you'll need to put it on every DisplayObject
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html#ADDED
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/events/Event.html#REMOVED

Take a look here : DisplayObjectContainer
It contains all what you need, for your 2nd question see Events part.

Related

Flash AS3 How to display a random item from an xml list then remove that item from the list so it will not be reused

I'm using Flash AS3 trying to display random questions from an xml list on stage. When the user clicks an option it should move on to another question but the one they got should be removed from the list so it will not come back.
I have the randomize part okay but can't figure out how to remove the question from the list.
Here is the section I have.
function randomizeQuestion():void {
var numOfQuestions:Number = xmlData.item.length();
var shuffledNumbers:Array = new Array(randomAns.length);
var randomPos:Number = 0;
//Randomizes selected question
currentQuestion = int(Math.random() * numOfQuestions);
//Randomizes answer numbers
for (var i:int = 0; i < shuffledNumbers.length; i++)
{
randomPos = int(Math.random() * randomAns.length);
shuffledNumbers[i] = randomAns.splice(randomPos, 1)[0];
}
randomAns = shuffledNumbers;
correctAns = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct"));
}
Try to get index:
correctAnsIndex = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct")).childIndex();
or if more elements, to get first one:
correctAnsIndex = xmlData.item[currentQuestion].children().(hasOwnProperty("#correct"))[0].childIndex();
then use delete where appropriate, like here:
delete xmlData.item[correctAnsIndex];
I would add another array to your code in which you can store all the questions that are eligible. As a question gets asked, remove it from that array. So you'll have one array of allQuestions and another array of eligibleQuestions. allQuestions can just be a comprehensive list. Then, push all the questions you want to go through into the eligibleQuestions array. As the questions get answered, splice them from the array.
It would be good to also share an example of your XML file that you're loading, but let's use the example below.
<data>
<item>
<question></question>
<option1></option1>
<option2></option2>
</item>
<item>
<question></question>
<option1></option1>
<option2></option2>
</item>
</data>
Based on the code you have, I assume your function is being called each time you want to randomize a question.
Now what you'd want to do is create an array that holds the number of <item> tags you have outside of this function so that you can remove values from it whenever you want.
You can create this var numOfQuestions:Array = new Array(); as a global variable and then initialize it using a loop before you enter the randomizeQuestions() function.
for(var i = 0; i < xmlData['item'].length(); i++)
{
numOfQuestions.push(i);
}
Basically this array will serve as a method of calling a specific item and removing it from the program without altering the actual XML file in any way.
Then whenever you wish to remove an element you use
numOfQuestions.splice(numOfQuestions.indexOf(valueToBeRemoved), 1);
This will search the array for the element you wish to remove and then remove it from the array.
Lastly the randomizeQuestion function has to be modified.
currentQuestion = int(Math.random() * numOfQuestions.length); //since numOfQuestions is now an array instead of a Number

getting a random element from an array of movieclips(or labels in a timeline) in Flash CC . Actionscript 3

I am making a pretty neat quiz-game in flashCC right now and I definitely need your help.
My skills are more on the design then the programming side. So to many of you this might seem a baby question (and asked many times before) but from all the answers I saw so far, I couldn't get any results for my project.
So here is the thing :
I need the EXACT script for creating an array (with movieclips inside? or instance names of mcs? How does this even work?)
and a method, to pick a random element of this array without repeats until the "game is over".
Paul
The easiest way to pick a random element from an array without repeating is to first sort the array with a "random" function, then pop or shift items out of it until the array is empty.
Let's say you have an array of items which can be filled with either instances or instance names, you've chosen instance names: :
var FirstArray:Array = ["blau", "orange", "green"];
Now, you'll need a random sort function:
// you do not need to modify this function in any way.
// the Array.sort method accepts a function that takes in 2 objects and returns an int
// this function has been written to comply with that
function randomSort(a:Object, b:Object):int
{
return Math.random() > .5 ? -1 : 1;
}
The way a sort function normally works is it compares two objects and returns -1 if the first item precedes the second item, 1 if the opposite is true, and 0 if they are the same.
So what we're doing in the function above is returning -1 or 1 randomly. This should get the array all jumbled up when you call:
FirstArray.sort(randomSort);
Now that the array is randomly sorted, you can begin pulling items from it like so:
if(FirstArray.length) // make sure there's at least one item in there
{
// since you are using instance names, you'll need to use that to grab a reference to the actual instance:
var currentQuizItem:MovieClip = this[FirstArray.pop()];
// if you had filled your array with the actual instances instead, you would just be assigning FirstArray.pop() to currentQuizItem
// every time you call pop on an array, you're removing the last item
// this will ensure that you won't repeat any items
// do what you need to do with your MovieClip here
}
else
{
// if there aren't any items left, the game is over
}
When strung together, the above code should be enough to get you up and running.
You could try something like:
var array:Array = [1, 2, 3, 4, 5];
var shuffledArray:Array = [];
while (array.length > 0)
{
shuffledArray.push(array.splice(Math.round(Math.random() * (array.length - 1)), 1)[0]);
}
trace('shuffledArray: ', shuffledArray, '\nrandom item: ', shuffledArray[0]);

How do i populate an Array in one class based on a textfield in another class?(Actionscript 3.0)

i have a class (TheList.as). in which i have an array "Data" and it has a couple of values. Then i have a loop through which i am creating a scrollable list which uses the values from "Data" array. [I am trying make a unit converter]
Then i have another class "Units.as". In that class i have created three instances of "TheList". A main list ("myList"), and to sublists "ListFrom" and "ListTo". They are using values from "Data" array. Now i have text field whose value changes to whatever item is clicked. When i click "Angle" in the main list, i want the sublists to get populated with ("Degree", "Radian" etc)..
Here is what i tried
if(myList._TextLabel.text == "Angle")
{
ListFrom.Data = ["Degree", "Radian"];
}
But nothing happens, i do not get any error either. When i do this in an "ENTER_FRAME" event and trace (ListFrom.Data), i can see that the values change, but they do not get assigned to the list items in the list. I would really appreciate the help. Thanks!
Here are complete Classes for understanding the situation better(the code is pretty messy, as i am a newbie to OOP)
TheList.as: http://pastebin.com/FLy5QV9i
Units.as : http://pastebin.com/z2CcHZzC
where you call ListFrom.Data = ["Degree","Radian"], make sure when the data changed, the renders in the ListFrom have been set new data. for example, you may use MyRender in ListFrom for show, you should debug in the set data method in MyRender.
you should call the code below after you call ListFrom.Data = ["Degree","Radian"];
for (var i:int = 0; i < Data.legnth;i++) {
var render:MyRender = ListFrom[i] as MyRender;
if (render) {
render.data = Data[i];
} else {
var render:MyRender = new MyRender();
render.data = Data[i];
ListFrom.addChild(render);
}
}
You can use event listeners, singleton classes or reference one class to another, depending on the style you want. All are equally valid and fast / efficient.

AS3 stack overflow?

Working with Arrays. I create objects on a Class base, push them into an Array, I have 2 buttons: one adds a Child and pushes it into the Array, second one Shifts Array and removes the Child. Also a function on my mouse, if I click an object, I define it's Array number, remove the Child and... well, not sure if successful but "delete Array[i];" where i is target's Array number. I can see Array.length in a text field every time I do something. Second button actually does remove an object from Array, the number decreases. But deleting a specified object from the Array, as well as Array.slice(i,1), doesn't reduce the Array length. So I'm afraid it may cause overflow. It's only Array, not sure, maybe it's fine to have over a million cells in an Array? Like if I make a game with meteor shower, meteors are removed from the screen, but the Array still has their cells. And if they appear like 30-50 per sec, it's obvious I may get memory problems in 20 minutes of running it. Well it's 60k so maybe I shouldn't worry as only graphics take much memory?
Still, I could use an advice on how to shift an object in a middle of an Array. Chosen one. How do I delete it as if it never was created, same as Shift does? (it does, right?)
Array.splice() will do most of the tricks. As you remove the meteor off screen, you can splice it out of the array, do like this:
var i:int=meteorArray.indexOf(meteorToRemove);
if (i>=0) meteorArray.splice(i,1);
You should not create a new object as a good practice if you are deleting other. Try recycling, or better said 'object pools'
You should figure out the number max of elements you may use at once. create a property 'active' on each and set it to true or false instead of creating/deleting. Then you can run the update on each object and update it only if necessary
For example:
var meteors:Array = [];
// create 500 meteors
for ( var i:int = 0; i < 500; i++ ) {
var meteor:Meteor = new Meteor();
meteor.active = false;
meteors.push(meteor);
}
// enable one meteor
meteors[0].active = true;
// in your update method:
for each (var meteor in meteors )
if ( meteor.active )
meteor.update();
Hope that helps.
Also you can add a helper method to get a meteor available:
function getMeteorAvailable():Meteor
{
for each (var meteor in meteors )
if ( !meteor.active )
return meteor;
}

Re-stacking MovieClips in an Array

I was trying to make a similar thing with the game SameGame (ie. the block above the removed blocks fall downward). Before trying this with an Array that contains MovieClips, this code worked (tried it with int values). With MovieClips on the array, it seems not working the same way.
With int values, example:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After: 1,2,3,4,6,7,8,9,10
But with MovieClips:
popUp(0, 4): Before: 1,2,3,4,5,6,7,8,9,10; After; 1,2,3,4
// Assume the numbers are movieclips XD
Basically, it strips everything else, rather than just the said block >_<
Here's the whole method. Basically, two extra arrays juggle the values above the soon-to-be removed value, remove the value, then re-stack it to the original array.
What could be wrong with this? And am I doing the right thing for what I really wanted to emulate?
function popUp(col:uint, row:uint)
{
var tempStack:Array = new Array();
var extraStack:Array = new Array();
tempStack = IndexArray[col];
removeChild(tempStack[0]);
for(var ctr:uint = tempStack.length-(row+1); ctr > 0; ctr--)
{
removeChild(tempStack[ctr]);
extraStack.push(tempStack.pop());
trace(extraStack);
}
tempStack.pop();
for(ctr = extraStack.length; ctr > 0; ctr--)
{
tempStack.push(extraStack.pop());
//addChild(tempStack[ctr]);
}
IndexArray[col] = tempStack;
}
PS: If it's not too much to ask, are there free step-by-step guides on making a SameGame in AS3 (I fear I might not be doing things right)? Thanks in advance =)
I think you just want to remove an element and have everything after that index shift down a place to fill what you removed. There's an inbuilt function for this called splice(start:uint, length:uint);
Parameters:
start - the index to start removing elements from
length - the amount of elements to remove
var ar:Array = ["hello","there","sir"];
ar.splice(1, 1);
ar is now -> ["hello", "sir"];
As per question:
Here's an example with different types of elements:
var ar:Array = [new MovieClip(), "some string", new Sprite(), 8];
ar.splice(2, 1);
trace(ar); // [object MovieClip], some string, 8
And further example to display the indexes being changed:
trace(ar[2]); // was [object Sprite], is now 8