Introduction to timed movements?
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-20-2008 11:20
Hi,
I have done a little scripting, but I now need to start learning about timers and timed events.
I have a little project and a much larger project that both need timed events. The first, which I hope the forum can help me get going with, so I can look at code suggestions and see how the events are constructed, consists of simply moving a prim 10m vertically, over 5 seconds, in a smooth manner.
The wiki is not entirely clear on this, so any snippets are most welcome.
Vi
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-20-2008 13:24
OK, been experimenting. Maybe I don't need a timer to move the prim a certain amount every x seconds. I tried just by setting a small increment inside to do-while loop, and by setting the increment to 0.1 it works fine. Well, when I say 'fine' there is one small problem with this script, it does not stop! The prim keeps rising even though it is clearly higher than my condition, so what is wrong? Here is the basic script: vector down = <168.432,171.443,21.038>; vector up = <168.432,171.443,31.038>; vector curpos;
default { state_entry() { llSay(0, "Prim Raising Script"); }
touch_start(integer total_number) { do { curpos = llGetPos(); llSetPos(curpos + <0, 0, 0.1>); } while (curpos.z < up.z); } }
Vi
|
|
Viktoria Dovgal
…
Join date: 29 Jul 2007
Posts: 3,593
|
06-20-2008 16:59
If you want smooth (but non constant) movement to happen within a certain amount if time, check out llMoveToTarget.
The script you posted works for me, well it does stop. It does overshoot its target by a tiny bit because there is a < instead of a <= check in the while loop, plus the condition in a do{...}while gets evaluated after the loop iterates (so with the two problems you'll overshoot by 0.2).
Add in a little bit of floating point goofiness and you might still end up off by a little, you can correct at the end of the loop by explicitly setting the position to up.
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-20-2008 17:24
From: Viktoria Dovgal If you want smooth (but non constant) movement to happen within a certain amount if time, check out llMoveToTarget.
The script you posted works for me, well it does stop. It does overshoot its target by a tiny bit because there is a < instead of a <= check in the while loop, plus the condition in a do{...}while gets evaluated after the loop iterates (so with the two problems you'll overshoot by 0.2).
Add in a little bit of floating point goofiness and you might still end up off by a little, you can correct at the end of the loop by explicitly setting the position to up. Many thanks for that Viktoria. I did look at MoveToTarget, but the wiki says it is for Physical objects only, while mine is not. I noticed the small overshoots, so thanks for pointing out the <= error. Now I need to figure out how to make it come back down again, smoothly. I don't want to click the prim, but maybe another discreet nearby prim could be clicked to move it up, then clicked again to move it down, and so on. If I can get my head around it, that is  Vi
|
|
Shadow Subagja
Registered User
Join date: 29 Apr 2007
Posts: 354
|
06-20-2008 18:40
one way to do it would be to use llListen() in your moving object, and have your control prim (perhaps an up and a down arrow prim) llShout or llRegionSay a command in their touch_start() handlers (to respond to a click).
llListen() is the event that recieves chat on a known channel, llShout and llRegionSay broadcast a message on a known channel.
So if you had a listen handler for channel X in your 'elevator' it could recieve a string, then check if the string was "up" or "down", and move one way or the other.
|
|
Johan Laurasia
Fully Rezzed
Join date: 31 Oct 2006
Posts: 1,394
|
06-20-2008 19:47
You CAN do somewhat constant movement with llMoveToTarget(), you just need to set the target a reasonable distance from the waypoint so that the at target will trigger before too much damping occurs. http://www.secondscripter.com/
_____________________
My tutes http://www.youtube.com/johanlaurasia
|
|
Viktoria Dovgal
…
Join date: 29 Jul 2007
Posts: 3,593
|
06-20-2008 19:52
Here is some stuff from the junk drawer that might be fun to play with. It will move from A to B in the direction you need. You might use llVecDist with that 0.2s delay built into llSetPos(), to figure a step distance that will give you close to the speed you want. Lots of comments added, this thing was a mess =) // ---------------------------------------- // user functions
// Move the object from start to end, going stepsize meters each pass move_it (vector start, vector end, float stepsize) { float total_distance = llVecDist(start, end); llOwnerSay("Total distance " + (string)total_distance);
// llVecNorm is handy for this kind of thing, // it works out to 1m away in the direction you want to go. vector each_step = llVecNorm(end - start) * stepsize;
vector last_position = start;
// Get really close to our destination. We'll do the last step // separately to avoid slop, or a step size bigger than our whole // distance float f; for (f = stepsize; f < total_distance; f += stepsize) { last_position += each_step; llSetPos(last_position); }
// Report on slop, to make sure it's no more than stepsize llOwnerSay("Each step " + (string)stepsize + " m, " + (string)llVecDist(end, last_position) + " to go...");
// and go to our final resting spot. llSetPos(end); }
// ---------------------------------------- // event stuff
default {
touch_start(integer total_number) { vector origin = llGetPos(); // we'll just start where we were.
// 2 meters out, 1.34 down, hey it's an example. //vector destination = origin + <0., 2., -1.34>; // float how_far = 0.12; // how far to move in each step
// Numbers from the original post vector destination = origin + <0., 0., 1.>; float how_far = 0.1; // how far to move in each step
llOwnerSay("==========="); llOwnerSay("Start position " + (string) origin); llOwnerSay("Heading to " + (string) destination);
// go there move_it(origin, destination, how_far); llOwnerSay("Actual destination " + (string) llGetPos() + ", slop: " + (string) llVecDist(destination, llGetPos()));
// and come back move_it(destination, origin, how_far); llOwnerSay("Actual return point " + (string) llGetPos() + ", slop: " + (string) llVecDist(origin, llGetPos()));
} }
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-21-2008 11:46
From: Shadow Subagja one way to do it would be to use llListen() in your moving object, and have your control prim (perhaps an up and a down arrow prim) llShout or llRegionSay a command in their touch_start() handlers (to respond to a click).
llListen() is the event that recieves chat on a known channel, llShout and llRegionSay broadcast a message on a known channel.
So if you had a listen handler for channel X in your 'elevator' it could recieve a string, then check if the string was "up" or "down", and move one way or the other. Yes, thank you. I have done that now, and it works. The script for the prim (hidden in a piece of driftwood), send the triggers for up/down to the script in the pyramid (that I am trying to raise dramatically out of the sands). Here is the code: integer Channel = 701;
default { state_entry() { llSetText("P",<0.875,0.746,0.547>,1); }
touch_start(integer total_number) { llShout(Channel, "1"); //1 raises the Pyramid llWhisper(0, "Raise the Pyramid"); state down; } }
state down { touch_start(integer total_number) { llShout(Channel, "2"); //2 lowers the pyramid. llWhisper(0, "Lower the Pyramid"); state default; } }
The receiving and up/down script now follows, but does not work as expected. The delay seems to have no effect whatsoever, I can vary it without seeing any effect. Also the return to the down position does not work, it seems to move a fraction, then stops. Any comments gratefully received. integer Channel = 701; vector down = <182.000,196.062,13.654>; vector up = <182.000,196.062,20.783>; vector curpos;
default { state_entry() { llListen(Channel,"","",""); //anyone can change it. } listen(integer chan, string name, key id, string msg) { //------------------------------------------------------ if(msg=="1") { do { curpos = llGetPos(); llSetPos(curpos + <0, 0, 0.1>); llSleep(0.5); } while (curpos.z <= up.z); } //------------------------------------------------------ if(msg=="2") { llOwnerSay("About to lower the Pyramid..."); do { curpos = llGetPos(); llSetPos(curpos - <0, 0, 0.1>); llSleep(0.5); } while (curpos.z >= down.z); } { } } }
|
|
Viktoria Dovgal
…
Join date: 29 Jul 2007
Posts: 3,593
|
06-21-2008 12:09
From: Vi Shenley The receiving and up/down script now follows, but does not work as expected. The delay seems to have no effect whatsoever, I can vary it without seeing any effect. Also the return to the down position does not work, it seems to move a fraction, then stops. Any comments gratefully received. It works as expected here, changes to the sleep are showing and the cube I dropped the script into is making the full trip up and down. This pyramid, how big is it, and how far away are you when you observe it? Sometimes the viewer will factor out changes (sometimes due to bugs, sometimes not) that will hide things that really did happen. Sometimes turning around for a moment, then looking back at the object, will be enough for the changes to register on your end. You might try adding some chatter to your script while building so that it can report on its position.
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-21-2008 12:20
From: Viktoria Dovgal It works as expected here, changes to the sleep are showing and the cube I dropped the script into is making the full trip up and down.
This pyramid, how big is it, and how far away are you when you observe it? Sometimes the viewer will factor out changes (sometimes due to bugs, sometimes not) that will hide things that really did happen. Sometimes turning around for a moment, then looking back at the object, will be enough for the changes to register on your end. You might try adding some chatter to your script while building so that it can report on its position. The Pyramid is a megaprim, with four columns holding it to a megaprim floor (that is the root prim andcontains the script). I am stood around 50m away when observing. I will try some debug chatter, and try the script in a regular prim for debugging too. Many thanks for the tips (I am also looking at the other script you kindly provided too). Vi
|
|
Vi Shenley
Still Rezzing
Join date: 24 Oct 2006
Posts: 103
|
06-21-2008 12:58
Ahh, I see the problem now.
When I change the values for the Pyramid to 20m down, and 30m up, it works fine. The problem comes when I use values of 13m down and 20m up (to send the pyramid beneath the ground (sand), it just wont do it.
Any thoughts whther this is solvable??
Vi
|
|
Viktoria Dovgal
…
Join date: 29 Jul 2007
Posts: 3,593
|
06-21-2008 13:42
You can try making the root at the peak instead of the floor. SL doesn't like root prims to go more than a tiny bit below the ground.
|
|
Pale Spectre
Registered User
Join date: 2 Sep 2005
Posts: 586
|
06-21-2008 14:30
Here's a more generic approach using a timer instead of a do loop. I feel a timer is ultimately a better approach as it doesn't suspend a script's event handling during the loop. Timing also becomes easier as it's a natural function of the timer. I've also taken out the hard coding for the height in favour of a Range over which you want the object to travel. As an additional finesse I've also made it operate with the single command which simply reverses direction each time it's called. Indeed, if you remove the iStatus checks the object will happily reverse its direction in mid flight - the iStatus check ensures it reaches its destination before accepting any further command. Only bug in my code is that you must reset the script if you manually move the object to make sure strpos gets reset. integer Channel = 701; vector strpos; vector curpos; float fRange = 1.0; // extent of travel float vShift = 0.1; // increments float fDelay = 0.5; // time between increments integer iHeading; // up and down integer iStatus; // currently moving check
default { state_entry() { llListen(Channel,"","",""); strpos = llGetPos(); }
listen(integer chan, string name, key id, string msg) { if(iStatus == 0) { if(msg=="1") iHeading = ! iHeading; iStatus = 1; llSetTimerEvent(fDelay); } }
timer() { curpos = llGetPos(); if(iHeading == 1 && curpos.z < strpos.z + fRange) llSetPos(<curpos.x, curpos.y, curpos.z + vShift>); else if (iHeading == 0 && curpos.z > strpos.z) llSetPos(<curpos.x, curpos.y, curpos.z - vShift>); else { llSetTimerEvent(0.0); iStatus = 0; } } }
|