Getting yourself organized..
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?
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?
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.