I had a REALLY hard time understanding loops. I really twisted my head for days and weeks, but I just
couldn't get them into my head. Now that I understand loops I can't manage to script without them. Loops
will deal with repetative tasks and save you many many lines.

From the helpfiles:

for (initialization; condition; change of condition) {
statement;
statement;
...
}

There are more info on it in the helpfiles. This is just a portion.

I'll go through two examples. One loop creates 11 nurbsSpheres, another loop will create buttons for a UI.

int $ma_i;
for ($ma_i = 0; $ma_i <= 11; $ma_i = $ma_i +1){
sphere -name ("spherName" + $ma_i);
}

Click the image to see the result:

window -t "just a test" ma_superWindow;
rowColumnLayout -nc 5 ma_superColumn;

for ($ma_a = 1; $ma_a<= 50; $ma_a++){
button -l ("nr." + $ma_a);
}

showWindow ma_superWindow;

I know the layoutstuff appeared a bit early here, but I needed it to show the example.

Click the image to see the result:

OK, now I will go through the code:

example one:

  • First I declare a variable ( $ma_i ) ( note that you don't have to declare it before the loop, it actually
    gets declared inside the loop when you set the initialization )
  • The initialization requires that I cast a value to the integer I just declared. Since I want it to start at "0"
    I set $ma_i = 0.
  • The next thing to consider is the condition. ( How long should this loop last. ) All I want is 11 spheres so
    I'll say "as long as there are 10 or less spheres", create one.
  • The change of condition will be "add one to the variable" so that the next time you loop the variable will
    have another value. In this case the previous value + one. ( $ma_i = $ma_i +1 )

The spheres clearly illustrates this. The command was

sphere -n ("sphereName" + $ma_i);

Since the flag -n (name) expects a single string I have to concatenate inside brackets.
You can see that the names of the spheres start at 0 and ends at 10. If you change the initialization, condition
or the change of condition you'll see what happens. If you want the naming to start at "1" and stop at "5" you
simply change the code to this:

int $ma_i;
for ($ma_i = 1; $ma_i <= 5; $ma_i = $ma_i +1){
sphere -name ("sphereName" + $ma_i);
}

See where I'm going with this?

exapmple two:

  • I declared the variable inside the loop here ($ma_a = 1)
  • I say that the loop should continue until I have 50 buttons.
  • And then I suddenly write $ma_a++. But that's not what I wrote down earlier. This is the same as
    $ma_a = $ma_a + 1; The reason I can write it like this is this:

in programming these two lines mean the exact same:

$variable = $variable +1;
$variable += 1;

You see that since I cast a new value to the variable using the variable itself I can throw the equation around.
Say the variable $variable was 2. After executing the first line I get $variable = 2+1. If I print this variable
now I get 3. So I actually redeclared it. Since we're adding "one" I can actually leave the right side out and
write $variable++ ( guess how you subtract with one ;) ). This is also very helpful when we write expressions.
For instance:

pSphere.rotateX += time; // this will rotate the X value with itself and add time.

  • Then the command is very simple. It's just a button command with the label ("nr." + $ma_a). This is
    similar to the sphereLoop.

 

 
 

This kind of loop is very effective to use when you want to change something for many objects. I'll go through
an example that shows this very well. I'll create a variable where I store all the selected objects and then I'll
translate all of these objects in random directions.

string $ma_selectedObj[] = `ls -sl`;

for ($eachObj in $ma_selectedObj){
setAttr ($eachObj + ".translate") 0 1.2 0;
}

Say you create 5 polySpheres, select them and list them in the string $ma_selectedObj[]. The command "ls"
lists things and the flag "-sl" is for selected. So we list all the selected objects in that string by using the
command. Also, we need the backquotes because we use a command to cast the value into it.

This is what I get in the scriptEditor when I declare- and print the variable:

string $ma_selectedObj[] = `ls -sl`;
// Result: pSphere1 pSphere2 pSphere3 pSphere4 pSphere5 //
print $ma_selectedObj;
pSphere1
pSphere2
pSphere3
pSphere4
pSphere5

So if we manually want to set the translate value to 0 1.2 0 we have to set this value 5 times like this:

setAttr ( $ma_selectedObj[0] + ".translate" ) 0 1.2 0;
setAttr ( $ma_selectedObj[1] + ".translate" ) 0 1.2 0;
setAttr ( $ma_selectedObj[2] + ".translate" ) 0 1.2 0;
setAttr ( $ma_selectedObj[3] + ".translate" ) 0 1.2 0;
setAttr ( $ma_selectedObj[4] + ".translate" ) 0 1.2 0;

If you have 5000 objects you can't do it like this... That's why we create the loop. The for-in loop does this
by taking the first object in the list and executing the command. Then it reads what the next item in the
selection is and does the same with that one. When there are no more objects left in the list to pick from the
loop stops. The $eachObj variable here will substitute $ma_selectedObj[0], then [1] and so on and so forth.

This loop sends me into another thing I'd like to talk about. If I want a random value for all the translate-
values and I want to use them inside the loop, I have to declare the random values INSIDE the loop. If
I declare it outside the loop the random value will not be redeclared for all the objects. I'll write down the wrong
way and the correct way here so you can try them both.

//First off I cast the selection to a string
string $ma_selectedObj[] = `ls -sl`;

//I'll use a vector to set the random values:
vector $ma_translateVector = <<rand(0,2),rand(0,2),rand(0,2)>>;

//As you can see above the translateAttribute need three floats to determine the values //for x, y and z. You can also use translateX, translateY or translateZ to set the
//value for just one of them.

//Now, here's the loop:
for ($eachObj in $ma_selectedObj){
setAttr ($eachObj + ".translate") ($ma_translateVector.x) ($ma_translateVector.y) ($ma_translateVector.z);
}

The problem here is that within the loop we get the same random values all the time because we declared it
once outside the loop. If we want a random value for each element in the loop we have to make sure Maya
gets a chance to redeclare the variable every time the loop is executed. To do this we need to put the
variable INSIDE the loop like this:

string $ma_selectedObj[] = `ls -sl`;

for ($eachObj in $ma_selectedObj){
vector $ma_translateVector = <<rand(0,2),rand(0,2),rand(0,2)>>;
setAttr ($eachObj + ".translate") ($ma_translateVector.x) ($ma_translateVector.y) ($ma_translateVector.z);
}

 

 


 

From the helpfiles:

A while loop has the form:

while (condition) {
statement1;
statement2;
...
}

The while statement checks the condition, and if it's true, executes the block, then repeats. As long as the condition is true, the block continues to execute.

So a while loop is actually a loop that "includes" an if statement. While something is true, execute the code
inside the curly braces.

int $ma_while = 2;

while ($ma_while < 5){
sphere -n ("sphereName" + $ma_while);
$ma_while++;
}

if you don't increase $ma_while here Maya will crash because $ma_while will ALWAYS be less than 5. You can
also look up do - while loop It's built like this: do this (execute commands) while statement and you could also
look up "switch...case" if you like.

 
 
 
 

The content of this tutorial is copyrighted by law.
Reproduction of the content without permission
will result in legal prosecution.

www.final3.com © 2006