Select blog: [setup] [lsl] [tst] [sfx] [img] [loop] [3d] [state] [bldg] [out] [vfx]

Loop

How to do things until they're done!


Check out the links and the library and our main blog

Counting, and fancy counting

Everyone should be able to count to 10, or 100! It should not be hard! You can make an object count to 10 just by giving a list of all 10 numbers to say, but it's easier to tell the object to start counting at 1, and stop when the object gets to 10 (or 100 or whatever!).

Here is how we do that in LSL:

integer Counter; 
default 
    state_entry() 
    { 
       llSay(0, "..I can count to myself, up to 10!.."); 
    } 
 
    touch_start(integer total_number) 
    { 
        for (Counter=1; Counter<=10; ++Counter) 
        { 
           llOwnerSay((string)Counter); 
        } 
    } 
   llOwnerSay("That wasn't so hard!"); 

Line 11 is the tricky one. Because that line begins with for, we know it begins a loop! The loop itself is given in the following block, it is just {llOwnerSay((string)Counter);}. But the instructions for how many times to do this loop are given in line 11. The instructions after for are given in 3 parts inside the parentheses. The first part says to start by setting Counter=1. The second part says to do the loop if the Counter is less than or equal to 10. And the third part says ++Counter, which means "after each loop, add 1 to Counter".

We can draw a flowchart of these steps:

What kind of fancy counting does this next program do? (Hint: the only change is the *7 in the loop, and * means multiply) Put this script into a new object and touch the object to see if you are right!

integer Counter; 
default 
    state_entry() 
    { 
       llSay(0, "..I can count to myself!.."); 
    } 
 
    touch_start(integer total_number) 
    { 
        for (Counter=1; Counter<=10; ++Counter) 
        { 
           llOwnerSay((string)(Counter*7)); 
        } 
    } 
   llOwnerSay("That wasn't so hard!"); 

Help! Help!

In the "Running out of Patience" script on the Sounds blog, we saw that you can keep a number to count how many times your object has been touched. Suppose you wanted your object to say "Help!" after it is touched once, and say "Help! Help!" after it is touched twice, and "Help! Help! Help!" after it is touched three times,... How could you do that?

Here is a recipe. Each time you are touched, add one to your TouchCounter, and then create *another* counter TempCounter, also an integer. Now start this loop: beginning with TempCounter set = 1, if TempCounter is less than or equal to TouchCounter, say "Help!", then add 1 to TempCounter and then start the loop again. Otherwise, if TempCounter is NOT less than or equal to TouchCounter, you are done so stop.

That recipe works! Here is the slightly tricky way to write it in LSL:

integer TouchCounter = 0; 
integer TempCounter; 
default 
    state_entry() 
    { 
       llSay(0, "Help us, Obi-Wan Kenobi!"); 
    } 
 
    touch_start(integer total_number) 
    { 
        TouchCounter = TouchCounter+1; 
        for (TempCounter=1; TempCounter<=TouchCounter; ++TempCounter) 
        { 
           llSay(0, "Help!"); 
        }; 
       llSay(0,"Over here..."); 
    } 

When you get touched, in line 12, you add 1 to TouchCounter. Then you do the loop from line 13 to 16 as many times as you have to. And finally, after the loop, you say "Over here" in line 17.

It figures that line 13 is the tricky one! That line starts the loop! To begin the loop, you set TempCounter = 1. Then test whether TempCounter is less than or equal to TouchCounter, and if the test is True, you do what comes in the brackets { llSay(0, "Help!");}, and then you ++TempCounter which means add 1 to TempCounter and start the loop again! Put this script into an object and try it!

Counting "mod 3", with colors! (for those who dare!)

Suppose you have 3 colors, and you want to change from one to another a bunch of times. One way to do this is to use a counter, and look at the remainder of this counter with 3. The remainder when you divide 1 by 3 is 1. The remainder when you divide 2 by 3 is 2. The remainder when you divide 3 by 3 is 0. The remainder when you divide 4 by 3 is 1 again. And so on.

In LSL, the remainder function, also called the mod function, is written %. So

1%3==1.

2%3==2.

3%3==0.

4%3==1.

5%3==2.

6%3==0.

7%3==1.

And so on.

So if we count 1,2,3,4,5,... with a counter, then if we take "mod 3" of the counter we get 1,2,0,1,2,0,... Perfect for changing through 3 colors over and over! Here is a program that changes red, green, blue, red, green, blue,... over and over, sleeping 1 second in each color:

integer i; 
default 
    state_entry() 
    { llOwnerSay("..I change colors..");} 
 
    touch_start(integer total_number) 
    { 
        for (i=0; i<=12; ++i) 
        { 
            if (i%3==0) 
            { llOwnerSay("red"); llSetColor(<1,0,0>,ALL_SIDES); llSleep(1);} 
            else if (i%3==1) 
            { llOwnerSay("green"); llSetColor(<0,1,0>,ALL_SIDES); llSleep(1);}                
            else 
            { llOwnerSay("blue"); llSetColor(<0,0,1>,ALL_SIDES); llSleep(1);}; 
        } 
       llOwnerSay("Whew, that was a lot of changes!"); 
    } 

How would you add a fourth color, like white <1,1,1>?

Counting, "mod 3", with music!

Suppose we want to play 3 parts of a nice song over and over, like these tone1, tone2, tone3. (You might have found some better ones!)

We can use the same idea from the previous script!

integer i; 
default 
    state_entry() 
    { llOwnerSay("..I sing a beeping song.."); } 
 
    touch_start(integer total_number) 
    { 
        for (i=0; i<=12; ++i) 
        { 
            if (i%3==0) 
            { llTriggerSound("tone1",1.0); llSleep(0.2); } 
            else if (i%3==1) 
            { llTriggerSound("tone2",1.0); llSleep(0.2); } 
            else 
            { llTriggerSound("tone3",1.0); llSleep(0.2); }; 
        } 
       llOwnerSay("Whew, that was a long song!"); 
    } 

To use this code, you have to have the three tones in your inventory, and drag them into the object that has the script. Try adjusting the sleep times.. on different computers, different times may sound better.

OK but that singer was not so good

Even randomness is better than the previous script: 0,1,2,0,1,2,0,1,2,0,1,2,... Ho hum. Let's use a bigger set of notes and just number them 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Then, the command to randomly choose a number between 0 and 9 is llFloor(llFrand(10.0)), so we can make this little change in the previous script to let some randomness loose on the universe:

integer i; 
 
default 
    state_entry() 
    { llSay(0,"..touch and I play a computer song.."); } 
 
    touch_start(integer total_number) 
    { 
        for (i=0; i<=32; ++i) 
        { 
       llTriggerSound((string)(llFloor(llFrand(10.0))+1),1.0); 
       llSleep(llFrand(1.0)); 
        }; 
         
       llSay(0,"thank you very much..."); 
    } 

How does that command llFloor(llFrand(10.0)) work? Well, llFrand(10.0) produces a random decimal number (called a "float" or "floating point" number) less than 10.0 -- that is, a number between 0 and 9.99999999999... Then llFloor takes that number and rounds it down, so that llFloor(2.99999) is 2, llFloor(1.31312) is 1, and llFloor(0.12345) is 0. Mathematicians call this "rounding down" function the "floor" function, so this is the Linden Lab Floor function, llFloor. Then we add 1 to our random number, so that we have a random number between 1 and 10. Since we have named our notes 1-10, we can just change the number to a string to play the note.

Once you can do basic arithmetic, tests, and loops, you can compute anything that any computer can compute. This is a version of a very famous idea called the the Church-Turing Thesis. All the rest of scripting is just practicing with the details! (Hector likes to brag that he took a class with Professor Church when he was at UCLA!)