How can this be the output? - actionscript-3

It is simple program, but the output of the program is so unexpected .
Programming language : ActionScript 3.0

So, we have 3 kinds of syntax:
// 1. Variable declaration.
var a:int;
// 2. Assign value to variable.
a = 0;
// 3. Declare variable and assign value in one go.
var b:int = 1;
The tricky moment is that in AS3 variable declaration is NOT an operation. It is a construction that tells compiler you are going to use a variable with a certain name and type within a given context (as a class member or as a timeline variable or as a local variable inside a method). It literally does not matter where in the code you declare your variables. AS3 is, I must admit, ugly from this very perspective. The following code might look weird yet it is syntactically correct. Lets read and understand what it does and why.
// As long as they are declared anywhere,
// you can access these wherever you want.
i = 0;
a = 0;
b = -1;
// The 'for' loop allows a single variable declaration
// within its parentheses. It is not mandatory that
// declared variable is an actual loop iterator.
for (var a:int; i <= 10; i++)
{
// Will trace lines of 0 0 -1 then 1 1 0 then 2 2 1 and so on.
trace(a, i, b);
// You can declare a variable inside the loop, why not?
// The only thing that actually matters is that you assign
// the 'a' value to it before you increment the 'a' variable,
// so the 'b' variable will always be one step behind the 'a'.
var b:int = a;
a++;
}
// Variable declaration. You can actually put
// those even after the 'return' statement.
var i:int;
Let me say it again. The place where you declare your variables does not matter, just the fact you do at all. Declaring variable is not an operation. However, assigning a value is. Your code actually goes as following:
function bringMe(e:Event):void
{
// Lets explicitly declare variables so that assigning
// operations will come out into the open.
var i:int;
var score:int;
for (i = 1; i <= 10; i++)
{
// Without the confusing declaration it is
// obvious now what's going on here.
score = 0;
score++;
// Always outputs 1.
trace(score);
// Outputs values from 1 to 10 inclusive, as expected.
trace(i);
}
}

Related

Actions with a list of instances - AS3

what is the best way to do an action with many instances at the same time?
Lets say I have 50 movieclip instances called A1 to A50, and I want to run an action with only A20 to A35.
For example:
(A20-A35).gotoAndStop(2)
You want an algorithm operation called loop. You are not able to abstractly address things in bunches at once, but you can loop and iterate the bunch one by one which produces basically the same result. Please read this: https://en.wikipedia.org/wiki/Control_flow#Loops When you need to do a quantity of similar operations it is always loop.
With regard to your problem:
// Loop iterator from 20 to 35 inclusive.
for (var i:int = 20; i <= 35; i++)
{
trace("");
// Compose the name of the MovieClip to retrieve.
var aName:String = "A" + i;
trace("Retrieving the MovieClip by name", aName);
// Retrieve the instance by its instance name.
var aChild:DisplayObject = getChildByName(aName);
// Sanity checks about what exactly did you find by that name.
if (aChild == null)
{
// Report the essence of the failure.
trace("Child", aName, "is not found.");
// Nothing to do here anymore, go for the next i.
continue;
}
else if (aChild is MovieClip)
{
// Everything is fine.
}
else
{
// Report the essence of the failure.
trace("Child", aName, "is not a MovieClip");
// Nothing to do here anymore, go for the next i.
continue;
}
// Type-casting: tell the compiler that the child is actually
// a MovieClip because DisplayObject doesn't have gotoAndStop(...)
// method so you will get a compile-time error even if you are
// sure the actual object is a valid MovieClip and definitely has
// the said method. Compile-time errors save us a lot of pain
// we would get from run-rime errors otherwise, so treasure it.
var aClip:MovieClip = aChild as MovieClip;
trace(aClip, "is a MovieClip and has", aClip.totalFrames, "frames.");
if (aClip.totalFrames < 2)
{
// Nothing to do here anymore, go for the next i.
continue;
}
// Now you can work with it.
aClip.gotoAndStop(2);
}
Now that you understand the while idea step by step, if you are sure all of them are present and all of them are MovieClips you can go for a shorter version:
for (var i:int = 20; i <= 35; i++)
{
(getChildByName("A" + i) as MovieClip).gotoAndStop(2);
}
UPD: You can as well address children with square bracket access operator.
for (var i:int = 20; i <= 35; i++)
{
// You can skip type-casting as this["A" + i] returns an untyped reference.
this["A" + i].gotoAndStop(2);
}
Yet there are differences and complications. Method getChildByName(...) always returns a DisplayObject with the given name (or null if none found). Square brackets operator returns an untyped OOP field of the current object.
It will not work with dynamically added children (unless you pass their references to the respective fields).
It will not work if "Automatically Declare Stage Instances" publish option is off.
Finally, this["A" + 1] and A1 are not exactly the same because the latter could refer to a local method variable rather than object member.
I'm not saying that square brackets are evil, they're as fine, yet, as always, programming is not a magick thus understanding what you are doing is the key.

Find count of elements in a Vector

If I assign a Vector like
var vec1:Vector.<Number> = new Vector.<Number>(3);
vec1 = (1,2);
the result of vec1.length is 3. Is there any built-in method to return the number of the elements actually present in the vector?
I'm an ActionScript noob so any help would be appreciated.
Well you can solve your problem by creating an empty vector instead of a defining the vector size at the time of its declaration and then you gradually add and remove elements to the vector. In this way you will always get the total number of elements inside the vector when you call vector.length
For example:
var vec1:Vector.<Number> = new Vector.<Number>();
vec1.push(5);
vec1.push(6,7);
vec1.pop();
Then vec1.length would give you 2.
Its been awhile, heres the reference: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Vector.html
I believe the .length is the normal way to check its length. If you want to check for "empty elements" you will need to loop through it with a loop.
I don't remmember the exact syntax, but to loop, do something like:
int count = 0;
for (int i = 0; i < vec.length; i++) {
if (vec[i] == ... );
count++;
}

AS3 - Not Retrieving Correct Item

In this section of code, I'm checking if a level in a game is unlocked or not. The Array "levels" contains 12 Movieclips and "levelsUnlocked" is the users highest level reached. So with this code, I'm checking if the level position is higher than the levelsUnlocked value, and if it is, it moves it to frame 2(which is the locked image), if is lower, it keeps it at frame 1.
My question is:
In the else statement, when I refer to levels[levels.length - i], it doesn't treat it as a Movieclip, but if I were to refer to it as levels[1] or levels[3], it does. Can someone tell my why this is happening?
function unlockLevels():void
{
for (var i:int = 0; i < levels.length; i++)
{
if (levels.length - i > levelsUnlocked)
{
levels[levels.length - i].gotoAndStop(2);
}
else
{
levels[levels.length - i].gotoAndStop(1);
}
}
}
Array length gives you the length of the array like this :
var a:Array = [0,1,2,3,4]
var length:int = a.length
trace(a)
//=> 5
in your first iteration in the loop your int is zero.
a[a.length - 0]
// a[5] == undefinded
You can use MovieClip(levels[levels.length-i]).gotoAndStop(2);
Edit:
Answer for your question:
You're trying to access the array elements from the end of the array while looping.
someArray[someArray.length-i] gives the "last - i" element of the array.

For-loop variable scope confusion

I have noticed a weird behavior of the variables in for loops. It's not really a problem, but it disturbs me a lot.
Actually I've created two loops this way:
for (var i:uint; i<19; i++) SomeFunction (i);
for (var i:uint; i<26; i++) SomeOtherFunction (i);
What I received was a compilation warning:
Warning: Duplicate variable definition.
This warning really surprised me. Nothing like that ever happened to me in other languages.
It seems that the i variable gets into the scope that is higher in the hierarchy and becomes available out of the loop's block. I've also tried to embrace the loop block in a curly brace, but it didn't change anything.
Why does it happen? Is it normal? Is it possible to avoid it? For now I've just set different names for both of the variables, but that's not a real solution I think. I'd really like to use the i-named variable in most of my for-loops.
yes, the loop increment variable is in the scope of the loops parent, not inside the loop itself. This is intentional, for examples like this:
public function getPositionOfValue ( value:String ) : int
{
for ( var i:int = 0; i < someArray; i++ )
{
if (someArray[i] == value )
{
break;
}
}
return i;
}
this allows you to access the value of i once the loop is over. There are lots of cases where this is very useful.
What you should do in the cases where you have multiple loops inside the same scope is var the i outside of the loops:
public function getPositionOfValue ( value:String ) : int
{
var i:int;
for ( i = 0; i < 15; i++ )
{
//do something
}
for ( i = 0; i < 29; i++ )
{
//do something else
}
return i;
}
then you get rid of your warning. The other thing to consider is to name your loop increment variables something more descriptive.
Update: Two other things to consider:
1) you shouldn't use uints except for things like colors and places where Flex expects a uint. They are slower than int's to use. Source]1 Update: it looks like this may no longer be the case in newer versions of the flash player: source
2) when you var a loop increment variable inside of a loop declaration, you want to make sure you set it to the proper initialization value, usually 0. You can get some hard to track down bugs if you dont.
As mentioned here, as3 has global and local scope and that's about it.
It does not do block-level scoping (or for-level either). With hoisting, you can even write to variables before you define them. That's the bit that would do my head in :-)
Early versions of Visual C had this bug, leading to all sorts of wonderful funky macro workarounds but this is not a bug in as3, it's working as designed. You can either restrict your code to having the declaration in the first for only or move the declaration outside all the for statements.
Either way, it's a matter of accepting that the language works one way, even though you may think that's a bad way :-)
Declare the variable i outside the loops to avoid this. As long as you reset it (i=0) you can still use it in all loops.
var i : uint;
for (i=0; i<19; i++) SomeFunction(i);
for (i=0; i<26; i++) SomeOtherFunction(i);

Declaring variable in loop or before loop in AS3?

Should I declare the _mcContainer var before the loop or no? (performance increase?)
for(var i:uint = _startIndex; i <= _endIndex; ++i){
var _mcContainer:MovieClip = _mcParent["i_" + _position];
}
or
var _mcContainer:MovieClip;
for(var i:uint = _startIndex; i <= _endIndex; ++i){
_mcContainer = _mcParent["i_" + _position];
}
?
It's not hard to test...
...however according to the docs, it shouldn't make any difference because variable declarations are hoisted to the top of the method block anyway.
From the docs:
An interesting implication of the lack of block-level scope is that you can read or write to a variable before it is declared, as long as it is declared before the function ends. This is because of a technique called hoisting , which means that the compiler moves all variable declarations to the top of the function.