Jump to content

Multi-door Sliding Door Script


LindsayKat
 Share

You are about to reply to a thread that has been inactive for 3186 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

So, i'm having some pretty frustrating issues here and i don't know where to start on this damned thing! Anyway.

i have a frame and then two doors, one that is to slide left and the other to the right, into the wall. The script is in the frame of the door.

Side note, for some reason, clicking on the frame will pop a debug saying that yes, its getting the click and opening and closing the door, but when i click on the doors themselves, it won't do that.

i'm so confused. Would someone please help? (Heads up, i am, ah, rather new to scripting.)

Thanks.

Code below.

/*
 * Sliding double door! IT WORKS!
 * By Lindsaykat (SL) / Katie Onyx (OpenSim private grid)
 * With a lot of help from the SL forums (in no particular order):
 * Qie Niangao, Rolig Loon, Profaitchikenz Haiku, Innula Zenovka
 * Updated 20150730 1040 SLT
 */

//Variables
integer doorState = 0; //Indicates if door is opened or closed.
integer dLLink = -1; //Link number for left door.
integer dRLink = -1; //Link number for right door.
vector dLPos; //Left door original position.
vector dRPos; //Right door original position.
float dLSlide = -0.1; //Original left door slide amount.
float dRSlide = 0.1; //Original right door slide.
list paramsL; //List for left door parameters.
list paramsR; //List for right door parameters.
key owner = NULL_KEY;
float cT = 30.0; //Timer original time.

//Functions
init() 
{
    integer iiMax = llGetNumberOfPrims(); //Find the number of prims in the door.
    integer ii; //To determine what the actual link numbers are....
    
    for(ii = 1; ii <= iiMax; ++ii) //Find them using this!
    {
        string name = llGetLinkName(ii);
        if(name == "L") //Feed the link number to dLLink
            dLLink = ii;
        else if(name == "R") //Or feed it to dRLink
            dRLink = ii;
    }
    
    owner = llGetOwner();
}

open()
{
    
    paramsL = llGetLinkPrimitiveParams(dLLink, [PRIM_POS_LOCAL]); //Grab original position, feed to left list.
    dLPos = ((vector)llList2String(paramsL, 0)); //Also feed that vector to the original pos.
    paramsR = llGetLinkPrimitiveParams(dRLink, [PRIM_POS_LOCAL]); //Feed original position to right list.
    dRPos = ((vector)llList2String(paramsR, 0)); //Feed vector to position vector.
    
    llSetLinkPrimitiveParamsFast(dLLink, [PRIM_POS_LOCAL, <dLPos.x, dLPos.y + dLSlide, dLPos.z>]); //Move dL along the Y axis .8 meters.
    llSetLinkPrimitiveParamsFast(dRLink, [PRIM_POS_LOCAL, <dRPos.x, dRPos.y + dRSlide, dRPos.z>]); //Move the right door now, .8 meters, y axis.
    
    doorState = 1; //Set the door state to 1.
    
    //llWhisper(0, "Door Opened"); //Debugging.
    
    llSetTimerEvent(30.0);
}

close()
{
    llSetTimerEvent(0.0);
    
    //Move doors back to original position.
    llSetLinkPrimitiveParamsFast(dLLink, [PRIM_POS_LOCAL, dLPos]);
    llSetLinkPrimitiveParamsFast(dRLink, [PRIM_POS_LOCAL, dRPos]);
    
    doorState = 0; //Set door state to close.
    
    //llWhisper(0, "Door Closed"); //Debugging.
}

//Main
default
{
    state_entry()
    {
        if(owner == NULL_KEY)
            init();
        
        //Debugging.
        //llSay(0, (string)dLLink);
        //llSay(0, (string)dRLink);
        
        llSetTimerEvent(0.0);
        
        dLSlide = -0.65;
        dRSlide = 0.69;
    }
    
    touch_start(integer num_detected) //When touched, open or close.
    {
        if(doorState == 0) //If door state is closed:
        {
            open();
        }
        
        else if(doorState == 1)
        {
            close();
        }
        
        else
        {
            //llWhisper(0, "Invalid Command");
        }
    }
    
    timer()
    {
        close();
    }
}

 

Link to comment
Share on other sites

The build floater numbers are not reliable. The thing to do is identify the individual objects with unique names, and check for them in an initialisation call. Should you edit the build and objects get added or deleted, re-run or reset the script. Snippets follow

 

key owner = NULL_KEY;integer leftDoor = -1;integer rightDoor = -1;init(){    integer iiMax = llGetNumberofPrims();
integer ii;

for( ii = 1; ii <= iiMax; ++ii)
{
string name = llGetLinkName(ii);
if( namne == "door left") leftDoor = ii;
else if( name == "door right") rightDoor = ii; }
owner = llGetOwner();}

state default
{
state_entry()
{
if( owner == NULL_KEY) init();

// then check none of the important integers such as leftDoor is still -1

 The idea of using the owner key in the way I do is to allow from switching stgates and not triggering all the setup stuff again when returning from another state.

 

Both Qie Niango and ChaliceYeo  have explained some of the reasons whythe floater numbers are not the numbers a script call obtains in the past, but I don't have saved bookmarks to their posts, some of which are probably on another site completely.

There are probably still typos in my post even after three edits, so expect the code to make the syntax checker vomit if you try a C&P inworld.

  • Like 1
Link to comment
Share on other sites

It wasn't me, maybe somebody else, but yes: Chalice Yao explained that "[t]he bug of the viewer showing the wrong link numbers at times stems from lazy updating on the viewer side" in http://www. s l u n i v e r s e .com/php/vb/scripting/107842-stupid-question-link-numbers.html#post2149434 (subject to the obvious URL fix because an actual link is verboten here)

At first glance there's going to need to be some changes to management of the params list; as posted, it's only updated when the door is closed -- but that's done by appending to the list, never removing from it, and I'm not seeing a call to llSetLinkPrimitiveParamsFast() using that list.

Also, is this door frame the root (link 1) of the linkset? If not, scripts inside it won't be seeing touches to other linked prims such as the doors themselves.

[ETA: Oh, also, I notice the calls to llList2Vector seem to specify the link number as list index, rather than just 0 to fetch the sole, PRIM_POS_LOCAL value on the list.]

Link to comment
Share on other sites

Profaitchikenz Haiku, thank you, that helped me figure out that the link set numbers were wrong anyway. Also, it has reminded me how much i hate for-loops, but that's another topic entirely. The checker would totally have vomited, but what you wrote was perfect to use with minor edits, so thank you.

Qie Niangao, i thought it only updated when the door opened, but i didn't realize that wouldn't work... but even with the llSetLinkPrimitiveParamsFast, it still isn't moving anything.... i think maybe my problem isn't understanding how the list is supposed to play with all of this. Ideas? Also, yes, the top of the frame is the link set's root. Now, for some reason, when i click on the doors, it works though, so that's a start. Maybe restarting the sim did the trick.... Or script reset or something, i don't even know.

Okay, now, using the llSetPrimitiveParamsFast is throwing an error, i think because i'm trying to use a vector instead of an int, and i don't know how to fix it. Sooo confused.

Added a timer, and now it's closing the door every thirty seconds. Now what did i mess up? Placement? If i use an if(doorState == 0) statement, then it doesn't work at all...

i've considered doing this the stupid way, and using listeners, but then i'd have to change the listener channel in every single door and that's a **bleep** that i don't want to deal with. (There will be a lot of doors.)

 

(Code edited in first post to reflect updated version.)

Link to comment
Share on other sites

You are setting the timer to operate every 30 seconds in your state_entry, when it should be set to 0.0 there, and also set to 0.0 at the start of the close function. At the end of the open function, set the timer to the duration required. That way, touching the door to close it ahead of the timeout will zero the timer and prevent it kicking in again.

 

I noticed in passing that you are adding/subtracting values from a couple of variables in the init(0 function which will not have values assigned to them (the slide and pos).

Link to comment
Share on other sites

I was a bit rushed this morning and now too much time has elapsed for me to edit the post above and expand upon the timer.

 

When you call llSetTimerEvent with a value x, you are setting a repeating timer event to occur every x seconds, and until a time of 0.0 is specified, the timer will continue to raise the timer event every x seconds, or a different value of another call is made to llSetTimerEvent with a new non-zero figure.

 

In your case, you want the door to close 30 seconds after it has been opened, unless closed earlier by a definite touch event. Therefore you need to call llSetTimerEvent(delay) as soon as you have opened the door.

The first thing you should do inside the timer event is call llSetTimerEvent(0.0), to prevent it then being called again 30 seconds later. You then make the call to close the door.

 

Inside the call to close the door when a touch event specifies it, you should call llSetTimerEvent(0.0) to cancel any waiting timer set by the previous open command.

 

Now, it does seem as though you could therefore dispense with the call to llSetTimerEvent)0.0) immediately inside the timer, and I agree, you could, but you are then relying on program flow to keep track of where you have set up or cancelled timers. Also, in very short time loops, you might run the risk of another timer event being triggered whilst you are still processing the first one, resulting ( I think), in them stacking up *, so as soon as you complete the first bit of processing, a second timer event is raised, and you could end up getting lockewd inside a non-stop stream of timer-events.

 

A satisfactory alternative which does at least remove a redundant call to zeroing the timer inside the timer loop is to write such a call, comment it out, and add a further comment explaining that the door-close function zeros the timer.

 

* As far as I can determine, events are stacked in the order in which they occur, so a very fast timer or repeating sensor will stack events to be handled, and not allow touches, listens, link_messages etc to get priority. I originally assumed that there was a round-robin poll of all the different types of events so that a stacked touch would then be procesed, followed by a stacked listen, then back to the stacked timer, but it does not appear to me that anything like that happens, it's purely a first-come first served occurrence. Also, I have some evidence that not all events stack as reliably or are detected as reliably as others; timers, sensors and touches are always reliable, but moving_end can sometimes be missed, and collision_starts  and _ends also seem unpredictable.

  • Like 1
Link to comment
Share on other sites

Yay! Thank you for that explanation, and that helped me to fix the problem. Updating code.

Problem still is in the move part. Wish it were as simple as doing it with listeners and non-touch-linked. Okay, so what am i misunderstanding about the list itself? i get that llSetLinkPrimitiveParamsFast takes an int and a list. Is the list supposed to be what holds the vector for the move? If so, what's the integer in the llSet...Fast(int,list) supposed to be of?

Link to comment
Share on other sites

It's the link number of the prim that the parameters are supposed to be applied to.  See http://wiki.secondlife.com/wiki/LlSetPrimitiveParams .  The parameters are defined as SLPPF is applied, so if it is meant to move a link, the parameter to apply will always be either PRIM_POSITION or PRIM_POS_LOCAL, depending on the situation.  The vector that is supplied there tells the script where to move to.

Compare your script with https://community.secondlife.com/t5/LSL-Library/Linkable-Multiprim-Sliding-Door/m-p/722649 , for example, to see how SLPPF is applied.

 

  • Like 1
Link to comment
Share on other sites

Hmmm, okay. i had seen that script before and because i am moving multiple doors in the same thing, in different directions, etc, i wasn't sure how much it applied to me. But, it is useful, and thank you very much for reminding me.

Question though: Do i have to have a rotation set as well, or can i just move the door without the rotation change?

Link to comment
Share on other sites

Code updated in first post.

HUZZAH! We have movement! Problem is... well... um. When i click on it, the doors a, skitter about five centimeters off center from each other then, b, fly about five meters away on a diagonal course. When i click on the frame to close it, they continue to slide another five meters away. Needless to say, i screwed something up, but apparently i know nothing of physics either, so... i know i've asked for a lot of help from you guys, but, please?

Link to comment
Share on other sites

Right, it's a matter of correcting the geometry-handling now.

So, firstly, when dLPos and dRPos are calculated in the open() function, they're already local coordinates (PRIM_POS_LOCAL) so you don't need to correct for root position. That is, you don't want to subtract llGetPos() from the values you're getting.

Secondly, still in open(), the new positions you're setting shouldn't add the current positions to themselves plus the amoount of slide; rather, just add the slide value to the position. So, one of those might look like this: 

llSetLinkPrimitiveParamsFast(dLLink, [PRIM_POS_LOCAL, <dLPos.x, dLPos.y + dLSlide, dLPos.z>]); //Move dL along the Y axis .8 meters.

Thirdly, in close(), you don't want to add or subtract those slide values again, but instead simply revert to the positions you've already stored. So one of those might look like this: 

llSetLinkPrimitiveParamsFast(dLLink, [PRIM_POS_LOCAL, dLPos]);

Now, there are some other little things that might make this more efficient and robust, but let's just see if this gets it working as intended.

 

Link to comment
Share on other sites

Holy crap. It's working perfectly now. HUZZAH! i never was very good at geometry, so sorry about that. Thank you for the fixes, everyone. Now i need to study the absolute crap out of this to figure out what i need to do differently in the future. Yay, learning. Qie, what kind of efficiency changes would you suggest?

Link to comment
Share on other sites


what kind of efficiency changes would you suggest?

It's most important to realize that none of the following will have any practical effect on performance. With a script this size, and one that only runs when triggered by a human, there's only rarely anything wrong of practical significance to efficiency. That said, it's okay to consider some things that might matter in a larger script, or one that runs with much higher frequency.

1. The init() function is only called from one point in the script, which might suggest it could just as well be copied "inline" into the place where it's called. In fact, however, this particular init() function is doing something that would be good to do not only in state_entry where it's already called, but also in a changed() handler for CHANGED_LINK. (Otherwise, think about what might happen if somebody links this to their castle without resetting this script. It might not be pretty.)

(1a. In this particular case, it would be just as well to have CHANGED_LINK call llResetScript() and go ahead and inline the init() code into the state_entry handler. That uses a tiny bit less memory than having a separate init() function called by both event handlers.)

2. The global variables paramsL and paramsR are really only used locally to the open() function, as intermediate stores on the way to calculating dLPos and dRPos. For several reasons, it's generally best to restrict variable definitions to their most local "scope" -- that is, if they don't need to be global, don't make them global. In this case, however, these global variables hint at a slightly cleaner way to write the whole script:

3. As written, every time open() is called, it will end up with the same list of parameters to pass to llSetLinkPrimitiveParamsFast(), but the script recalculates and re-assembles that list anew each time. Instead, everything about those parameter lists is defined at init() time, so they could just as well be calculated and assembled that one time, stored in global variables, and then simply referenced when open() needs them. The very same idea could be applied to close().

4. It may seem that suggestion #3 implies four global list variables: separate L and R prim parameter lists for open() and for close(). In fact, however, PRIM_LINK_TARGET is a way to append the parameters for multiple prims into a single list, so only two lists are really needed -- one for open() and one for close() -- and then those functions would each need only a single call to llSetLinkPrimitiveParamsFast() using those two-prim lists.

5. Trivial, but: the state_entry tests whether (owner == NULL_KEY) before calling init(), but init() needs to be called every time state_entry runs. In fact, the owner variable is set in init() and nothing else in the script uses it, so unless something big is planned for it in future, it should just go away.

6. Even more trivial: dLSlide and dRSlide are set once in state_entry. If they're really going to have constant values like that, they could instead be initialized to those values when they're declared as globals near the top of the script.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3186 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...