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

State

Getting yourself organized..


We can organize an object's programs into states, so it does one thing or another depending on its mood or situation. We see how to define your own states, and your own commands, how to change from one state to another, and how to put comments in your scripts to help you remember what it is doing (and other important things)! Check out the links and the library and our main blog

States

Sometimes you want to do one set of things in one situation or one mood, and another set of things in a different situation. One way to do this is to have more states than just the default one! The command to go to a NewState is just state NewState, and then you can declare what the script should do in that NewState. Here is a simple example, with comments:

default 
{   // this object has a problem with mood swings! 
    // anything you put after the 2 slashes are "comments" and SL ignores them! 
    state_entry() 
    { llSay(0, "I'm happy!");} 
     
    touch_start(integer total_number) 
    { state grouchy; } // This command says "go to the grouchy state" 
 
state grouchy // now we define what to do in the grouchy state 
    state_entry()  // first, what to do when you enter the state 
    { llSay(0, "I'm grouchy!"); } 
 
    touch_start(integer total_number)  // then, what to do when you get touched again! 
    { state default; } 
    // A comment can be about anything, but usually it is to explain your program 
    // Did I forget to mention Elvis? 

If you take the comments out, the program does exactly the same thing:

default 
{    
    state_entry() 
    { llSay(0, "I'm happy!");} 
     
    touch_start(integer total_number) 
    { state grouchy; } 
 
state grouchy 
    state_entry() 
    { llSay(0, "I'm grouchy!"); } 
 
    touch_start(integer total_number) 
    { state default; } 

So it is a good idea to put comments in your program just when they will really help to make it more understandable.

In each state, we have defined responses to 2 events: entering the state, and getting touched. Put this script (either the version with comments, or the version without comments) in an object and try it out!

Can you fix this script so that the first two times it is touched, it stays happy, and then it gets grouchy for two more touches, and then happy again?

More events for each state

We have mainly used just two events in our states: the entry event and the touch event. But there are many others.. Appendix B of the reference manual lists 32 of them.

One of the commonly used events is the timer event. Here is a simple clock that uses timer events:

integer on = 1; // 1 or 0 for "on" or "off" 
integer ticktock = 0; // 0 or 1 for "tick" or "tock" 
 
default 
    state_entry() 
    { 
       llSetTimerEvent(1.0); // for timer event every 1.0 second 
    } 
     
    timer(
    { 
        if (ticktock==0) 
        { llOwnerSay("tick"); ticktock=1;} 
        else 
        { llOwnerSay("tock"); ticktock=0;} 
    } 
 
    touch(integer touches) 
    { 
        if (on == 1) 
        {   llSetTimerEvent(0); // turn timer off 
           llOwnerSay("off"); // tell owner  
            on = 0; // set timer flag to "off"=0 
        } 
        else 
        { 
           llSetTimerEvent(1.0); // start timer again 
            on = 1; // set timer flag to "on"=1 
        } 
    } 

Try this one. How would you change the clock to tick-tock every 3 seconds? How would you change it so that the clock tells you when 1 minute is up?

Fancy rotator

In a post on the Scripting Tips Forum, Hewee Zetkin included this script (shortened and simplified here) for testing rotations. It is neat because it uses the timer events to change the axis of rotation every 2 seconds. It looks cool! (Copy it into the contents of a cube and try it... then try adjusting the timer period and the speed.)

float TIMER_PERIOD = 2.0; 
float ANGULAR_SPEED = 6.0; 
 
changeRotation() 
    float x = llFrand(1.0); 
    float y = llFrand(1.0); 
    float z = llFrand(1.0); 
   llTargetOmega(<x,y,z>, ANGULAR_SPEED, 0.1); 
 
default 
    state_entry() 
    { 
       llSetTimerEvent(TIMER_PERIOD); 
    } 
 
    timer(
    { 
        changeRotation(); 
    } 

The thing I really wanted to show with this example is how the new command changeRotation can be defined at the beginning and then used as a command. This isn't necessary. It is done just to make the code simpler or easier to read -- we could have just put the changeRotation() code right into the timer() block. In this case it really makes no difference, but we will see cases later where doing things this way is really better.

Try defining another new command called settimer that you can use in state_entry instead of llSetTimerEvent.