multiple variables and complex expressions in AS3 switch case statements - actionscript-3

I'm cleaning up some AS3 code today, and want to replace a bunch of messy if/else if/else statements with a switch statement.
private const myConstant:int = 3;
private var someNumber:int = 1000;
for(var i:int=0; i < someNumber; i++){
switch(i, myConstant){
case 0:
function1();
break;
case (i % myConstant == 0):
function2();
break;
default:
function3();
}
}
My program has many more case statements and variables, however, I cut it down for the sake of brevity. In this example, I want to call function2() on every third iteration of the loop. Now, myConstant is an important setting for the class which is used elsewhere, so I can't just put a literal 3 in the expression.
Can I evaluate multiple variables (and constants) in one switch?
Can I evaluate expressions such as the second case statement in my example?

The switch keyword takes only one expression inside the parentheses (your comma separated variables above would not evaluate to one expression).
The case keyword also expects to evaluate one expression.
In your example, it's unnecessary to pass either i or myConstant into the switch statement. These vars are declared immediately above the switch and are accessible to any code inside the switch statement.
Perhaps you want something like this:
for (var i:int = 0, i < someNumber; i++)
{
switch (true)
{
case i == 0:
function1();
break;
case i % myConstant == 0:
function2();
break;
default:
function3();
}
}

Related

How can this be the output?

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);
}
}

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.

object.hitTestObject(other_object) is executed too many times

Why is that happening?
when two objects are touching each other, then i put trace, and they show me many messages:
private function onEnterFrame(e:Event):void{
e.target.x += 4;
var moved = false
if(!moved)
{
for(var i = 0; i < arrows.length; i++)
{
if(e.target.hitTestObject(arrows[i]))
{
trace('boom');
moved = true;
break;
}
}
}
so here it writes the word "boom" to many times instead of 1 time, how to fix this?
You are checking hit test on every frame, so everytime it gives you the value of hit test. I think your problem is that you define your boolean variable "moved" inside the loop and it loses it's purpose because it's always false when it comes into loop. Try defining your boolean variable outside the function. That will help solve the problem :)

C++ if statement seems to ignore the argument

Here's the code.
bool b_div(int n_dividend)
{
for (int iii = 10 ; iii>0 ; iii--)
{
int n_remainder = n_dividend%iii;
if (n_remainder != 0)
return false;
if (iii = 1)
return true;
}
}
After testing this function I made for a program, the function seems to stop at the if (n_remainder != 0) part. Now then the function SHOULD test if the number that the function takes in can be divided by all numbers from 10 to 1.(it takes in numbers until it returns true) I know the first number that this works with it is 2520 but even on this number it stops at if(n_remainder != 0). So I was hoping for some advice! Im having trouble troubleshooting it! Any links or words I should look for would be awesome! Im still pretty new to programming so any help you can give for learning would rock! Thanks!
Change your last if statement to:
if (iii == 1)
return true;
Currently you have only a single equals sign, which sets the variable iii to 1, and is always true. By using a double equals it will compare iii and 1.
In addition to SC Ghost's answer, you can actually also clean up your function a bit more :)
bool b_div(int n_dividend) {
for (int i = 10 ; i > 1 ; i--) {
int n_remainder = n_dividend % i;
if (n_remainder != 0) {
return false;
}
}
return true;
}
A few notes,
modulus of 1 will always be zero, so you only need to iterate while i > 1
you can completely remove the if(i == 1) check and just always return true after the for loop if the for loop doesn't return false. It basically removes an unnecessary check.
I think it's more standard to name your iterator iii as i, And I prefer brackets the way I wrote them above (this is of course completely personal preference, do as you please)

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);