Need help with a light script.
|
|
Khashai Steinbeck
A drop in the Biomass.
Join date: 15 Oct 2005
Posts: 283
|
02-12-2006 23:25
OK, this is my first real script I have tried to write with LSL. Im trying to make a script that operates a light on or off via touch. I had it working earlier this evening, but then it stopped working properly - it infinitley loops now, I know why it does this, just havent been able to correct it (no idea why it worked somewhat like I wanted it to the first time around) My main problem is this: When the prim changes material from wood to light, its smooth without hesitation. When the prim changes from light to wood, there seems to be about a 2 second stall. The script in the scripting library does the same thing, although it was put together in a different manner. I know its possible to make a touch light script that has no hesitations, but I just cant figure out how. my code is below. I know its bad, but hey, it was a first attempt! //TouchLight Script //By Khashai Steinbeck, Feb 13, 2006
integer ksLightOn;
ksLightInit() { ksLightOn = FALSE; //Light off by default. return; }
default {
touch_start(integer total_number) { //Turns On the Light. llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]); ksLightOn = TRUE; if (ksLightOn = TRUE) llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_WOOD]); ksLightOn = FALSE; } }
Obviously, the problem with the loop is caused in the default state, where it goes directly from ksLightOn = True; to if (ksLightOn = TRUE).
|
|
Osgeld Barmy
Registered User
Join date: 22 Mar 2005
Posts: 3,336
|
02-12-2006 23:36
to me it seems abit overcomplicated i would use
integer ksLightOn; // 0 = false or off 1 = true or on
default {
touch_start(integer total_number) { if (ksLightOn == 0) { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]); ksLightOn = 1; } else { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_WOOD]); ksLightOn = 0; } } }
i also never use TURE or FALSE, the wiki defines them as 0 and 1 in the constants section, and im too lazy to type more than i need to 
|
|
Masakazu Kojima
ケロ
Join date: 23 Apr 2004
Posts: 232
|
02-13-2006 04:09
From: Khashai Steinbeck my code is below. I know its bad, but hey, it was a first attempt! Here's the output from lslint: WARN:: ( 7, 1): function `ksLightInit' declared but never used WARN:: ( 23, 13): assignment used in comparison WARN:: ( 23, 13): condition is always true TOTAL:: Errors: 0 Warnings: 3 Your script runs something like this: always set material to light always set ksLightOn to true always set ksLightOn to true again, and if that's true (it always is): set the prim type to wood always set ksLightOn to false You need to use two equal signs (==) to compare values, and if you have more than one statement you want executed when a condition is true, group them within curly brackets. Osgeld's script demonstrates those, so here is another way to approach it: integer ksLightOn;
ksLightInit() { // See if light is already on list pp = llGetPrimitiveParams([PRIM_MATERIAL]); ksLightOn = (llList2Integer(pp, 0) == PRIM_MATERIAL_LIGHT); }
default { state_entry() { ksLightInit(); }
touch_start(integer total_number) { ksLightOn = !ksLightOn; // toggle light if ( ksLightOn ) llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]); else llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_WOOD]); } } As for the two second stall, it seems to happen randomly and I don't think there's any way around it. It even happens when you change the material manually sometimes. It seems to happen most often when you turn it on and then turn it back off within a couple seconds. You can add an llOwnerSay("debug"  ; to show that your script isn't stalling, and you can turn on Show Updates on the debug menu to see that the object is updated at the correct time. The delay may have been what made your script appear to work correctly before. From: Osgeld Barmy too lazy integer o;default{touch_start(integer n){llSetPrimitiveParams([2,3+(o=!o)*4]);}}
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
Look ma! No variables!
02-13-2006 07:15
default { state_entry() { if(llList2Integer(llGetPrimitiveParams([PRIM_MATERIAL]),0) == PRIM_MATERIAL_LIGHT) state on; else state off; } } state off { state_entry() { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_WOOD]); } touch_start(integer num) { state on; } }
state on { state_entry() { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]); } touch_start(integer num) { state off; } }
|
|
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
|
02-13-2006 07:21
I <3 states 
|
|
Adman Drake
Registered User
Join date: 9 Feb 2006
Posts: 96
|
02-13-2006 09:58
if (ksLightOn = TRUE)
There's your problem.
= is assignment.
== is comparison.
Adman
|
|
Khashai Steinbeck
A drop in the Biomass.
Join date: 15 Oct 2005
Posts: 283
|
I think my head just exploded =)
02-13-2006 12:09
Thanks for the help all, as you can no doubt tell, I'm very new at this.
Hopefully, one day, I will be able to make better sense of things...
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-13-2006 12:30
touch_start(integer num)
That's a variable  And in this case, your variable-less solution has 6 functions. I can't see how that would use less bytecode memory than adding one variable. also, the VM has to execute all these state changes, call state_entry in each one... I really wonder how it's better to use states for something like this. I always see this "states are good, variables are bad, use states wherever possible" kind of thinking, and it never makes sense to me. Not picking on you personally, Argent  I'm pretty sure you did this more as an academic exercise than anything. But this has recently become something of a 'pet peeve' for me. I've had people take something I've written and 'improve' it by replacing a boolean variable check with a state change. "Because the Wiki says it's better". Well.. how is it better?
|
|
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
|
02-13-2006 12:32
Tight and hideously ugly? I have no idea if it'll even compile, though, since i'm at work... list primParam = [ PRIM_MATERIAL, PRIM_MATERIAL_WOOD, PRIM_MATERIAL, PRIM_MATERIAL_LIGHT ];
integer lightOn = 0;
default { touch_start( integer total_num ) { lightOn = ( !lightOn ) * 2; llSetPrimitiveParams( llList2List( primParam, lightOn, lightOn + 1 )); } }
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-13-2006 12:36
Hah! Tighter and uglier. And I have no idea if this will work either  list primParam = [ PRIM_MATERIAL_WOOD, PRIM_MATERIAL_LIGHT ];
integer lightOn;
default { touch_start( integer total_num ) { llSetPrimitiveParams( [PRIM_MATERIAL, llList2Integer(primParam, (lightOn = !lightOn)) ]); } }
|
|
Zalandria Zaius
Registered User
Join date: 17 Jan 2004
Posts: 277
|
not exactly sure what the deal is with states and variables
02-14-2006 10:05
I used to use the if then else stuff alot, but switched to states.. If nothing else it makes the code quicker and easier to alter later. Those if/elseif/else statements can really start turning into a mess quick.
Plus there's no comparisons to slow it down.. you click it goes.. I think some of the lag you guys may be experiencing with the code is there is a 2 second delay changing a prim using llSetPrimParamet
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
02-14-2006 11:09
From: Ziggy Puff And in this case, your variable-less solution has 6 functions. I can't see how that would use less bytecode memory than adding one variable. It's not bytecode memory I'm trying to save, it's neural memory. With a state based solution like this, everything that the script is "aware of" is visible in one state, and you can easily see the entire state of the script at a glance. More complex scripts, or scripts with a lot of shared code, are easier to understand and follow with variables, or with an explicit state table in a list. I've done all three... and I've even managed two state variables using states when that seemed the best way. For this solution, I think states are really the best way to go, especially if you want to make the light do something more when it's on.
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
Look Ma, No Variables! No States! One Statement!
02-14-2006 11:18
default { touch_start( integer i_am_not_a_variable_i_am_a_parameter ) { llSetPrimitiveParams( [ PRIM_MATERIAL, llList2Integer([PRIM_MATERIAL_LIGHT,PRIM_MATERIAL_WOOD], PRIM_MATERIAL_LIGHT == llList2Integer(llGetPrimitiveParams([PRIM_MATERIAL]),0) ] ); } }
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-14-2006 11:19
From: someone With a state based solution like this, everything that the script is "aware of" is visible in one state, and you can easily see the entire state of the script at a glance. OK, I'll buy that  Not saying I don't use states or that I don't think peopel should, because neither is true. I've probably spent more time in my job coding state machines than anything. But they're a tool just like everything else IMO. Speaking of which, a state table would be sweet, with the ability to switch to a state that is specified by indexing into that table. right now, there's no way (that I know of) where a state (or the name of a state) can be specified in a variable of any kind. From: someone integer i_am_not_a_variable_i_am_a_parameter LOL!!! You're right, of course. But it's similar to a variable in the sense that it takes up space in the stack 
|
|
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
|
02-14-2006 14:48
BTW, the lights in my own house have a script that's more like this: default { touch_start(integer num) { state low; } }
state low { state_entry() { llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, TRUE]); } state_exit() { llSetPrimitiveParams([PRIM_FULLBRIGHT, ALL_SIDES, FALSE]); } touch_start(integer num) { state high; } }
state high { state_entry() { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_LIGHT]); } state_exit() { llSetPrimitiveParams([PRIM_MATERIAL, PRIM_MATERIAL_WOOD]); } touch_start(integer num) { state default; } }
It would be more efficient to combine the param setting between low and high, but this illustrates the use of state_exit(), and again is easier to understand. This kind of light goes through three states, off, low, and high. In low it's obviously "on", but since FULLBRIGHT doesn't illuminate anything it's like it's "on low". This is a cute effect, and also allows you to "turn the lights on" without causing as much light lag for the neighbors.
|
|
Ziggy Puff
Registered User
Join date: 15 Jul 2005
Posts: 1,143
|
02-14-2006 15:13
I like that design too. And like I said, as long as this isn't accompanied with a "It's better to use states because a variable takes up more memory", I don't have any complaints 
|
|
Lindsey Dassin
Fallen Angel
Join date: 14 Sep 2005
Posts: 33
|
02-14-2006 17:09
From: Argent Stonecutter BTW, the lights in my own house have a script that's more like this:
(snip!)
It would be more efficient to combine the param setting between low and high, but this illustrates the use of state_exit(), and again is easier to understand.
This kind of light goes through three states, off, low, and high. In low it's obviously "on", but since FULLBRIGHT doesn't illuminate anything it's like it's "on low". This is a cute effect, and also allows you to "turn the lights on" without causing as much light lag for the neighbors. Mmm... your code has a simplicity to it that's just ... strikingly beautiful, really. Resetting object properties on the state_exit() event makes great use of it -- i like.  For a light that can only be "on" or "off", where the same single property of the object is being changed every time, i'd argue that something like what i wrote would be fine (if it was more straightforward, anyway). A construct like that would even do great for a continuum of values (say, a dimmer switch), as long as it's the same property of the object that's being changed every time. But in your three-way switch you set/reset a completely different prim parameter of the object. More than that, you turn one off, then turn the other one on. Incorporating something like that into a single-state script could get ugly really quickly. Thinking more abstractly, though, the code in a state_entry()/state_exit() needn't always relate to a prim parameter: They could be something like "begin transaction" or "end transaction" messages in a communications protocol to another script, or relate to land properties, or some combination of different things. Or anything else, for that matter. In a sense, you're kind of like treating these two event handlers like constructors and destructors... maybe LSL isn't quite as primitive as i at first took it to be. *scratches her head* Well, okay, there's no way to do anonymous code blocks... *scratches her head some more* No indirect memory addressing of any kind for that matter... *sighs* And everything is done through a library of "llPerformBackwardsSomersault()" routines instead of class methods... Okay, so nothing's perfect. At least we we have the tools to argue about how many LSL scripters it takes to change a light bulb. 
|
|
Jopsy Pendragon
Perpetual Outsider
Join date: 15 Jan 2004
Posts: 1,906
|
02-14-2006 17:28
Argent -- You're my hero. (even if you do use local lighting sometimes.  ... mis-quote: touch_start( integer dammit_Jim_Im_a_parameter_not_a_variable ) // !
_____________________
* The Particle Laboratory * - One of SecondLife's Oldest Learning Resources. Free particle, control and targetting scripts. Numerous in-depth visual demonstrations, and multiple sandbox areas. - Stop by and try out Jopsy's new "Porgan 1800" an advanced steampunk styled 'particle organ' and the new particle texture store!
|