Jump to content
Lolita Erin

Options for Scripting Doors

Recommended Posts

Hello, i have search how to rotate a door, and many samples explain using regular prims and need to cut half or some like that, i need to find a way to rotate a door from floor to up and is mesh, like the basements door the main linked is a vehicle so it moves. thanks for any help

 

cache_4055447204[1].jpg

Share this post


Link to post
Share on other sites

There are two or three standard ways to do it. 

1.  The old "hinge prim" method, in which you link a long skinny prim to the edge of the door as the root prim and then rotate the linkset around it.

2. Plan ahead while you are making the mesh door by including a small, transparent piece that is offset on one side of the door's hinge edge while the visible door itself is offset an equal amount on the other side.  This makes the mesh door behave exactly like the cut prim door that you mentioned.  You'll see a good video tutorial on one way to do it here >>>

.  Then you can use your favorite cut door script.

3. You write a rotation script that calculates the rotation around the edge instead of tthe center of the door.  This is mildly tricky but you'll learn a bit about rotations if you think it through.  Innula Zenovka shows a sample in this thread >>> http://community.secondlife.com/t5/LSL-Scripting/How-do-I-rotate-a-prim-or-linkset-along-an-axis-that-is-not-the/m-p/1835303 that builds on Void Singer's cut door script.

  • Like 1

Share this post


Link to post
Share on other sites

Thank you Rolig, but after i try the samples scripts on the links none of those has the rotation that i need are more like slides from one side to other and i need to rotate the door from botom to top in a arc or cirlular mode, is there any simple short script that do this? thanks again for you time

Share this post


Link to post
Share on other sites

The example I posted, to which Rolig directed you, rotates the door on its Z axis (or it certainly did when I wrote the script).    You'll need to change that axis, probably -- ask, if you need help -- but I'm baffled at how you got it to slide.  

Share this post


Link to post
Share on other sites

Innula, i manage to make the script work and is great but one think is there any way i can open the door sloower? how can i do that? thanks

Share this post


Link to post
Share on other sites
On 3/6/2015 at 8:44 PM, Xiija said:

you could use keyframes or a timer and a step variable?

Yes.  There are many ways to do that.  KFM will give you smooth movement with controllable speed. It has a few major drawbacks, which may be serious in some applications.  First, a KFM script must be placed in the root prim of a linkset, so your door can't be a child prim. Second, KFM will only work in objects that use the Prim Equivalency system, so the door has to either be a mesh door or set to physics shape type CONVEX_HULL. Third, collisions with avatars affect the angular movement of the a KFM controlled object and it may not reach the final rotation. If you can design with those limitations, you can make some imaginative doors with KFM.  Here's a very simple example:

float gfangle = PI_BY_TWO; // angle to turn [radians]. Make negative to open in the opposite direction.
float gftime = 2.0;     //time to open or close door

integer giOpen;
integer giTouched;
rotation gvClosedRot;
float gfnewtime;
list glFrameListOpen;
list glFrameListClose;

float motion_time( float mt)    // Rounds off time units to match frame time
{
    mt = llRound(45.0*mt)/45.0;
    if ( mt > 0.11111111 ) return mt;
    else return 0.11111111;
}

GetKFMRotations()
{
    glFrameListOpen = [];
    glFrameListClose = [];    
    integer maxsteps=(integer)(motion_time(gftime) * 9);
    gfnewtime = maxsteps / 9.0;
    integer i ;
    for  ( i = 0; i < maxsteps ; i++)   // Building the Open KFM list
    {
        glFrameListOpen += [ 
            llEuler2Rot(< gfangle/(float)maxsteps,0,0>),
            gfnewtime/(float)maxsteps
        ];
    }
    gfangle = - gfangle;
    for  ( i = 0; i < maxsteps ; i++)   // Building the Close KFM list
    {
        glFrameListClose += [ 
            llEuler2Rot(< gfangle/(float)maxsteps,0,0>),
            gfnewtime/(float)maxsteps
        ];
    }
}

default
{
    state_entry()
    {
        gvClosedRot = llGetRot();   //Defines the door's "closed" rotation
        GetKFMRotations();  // Calculates KFM lists for open and close rotations
    }
    
    touch_end (integer num)
    {
        if(!giTouched)  // Prevents double touching
        {
            giTouched = TRUE;
            llSetTimerEvent(gfnewtime);
            if (!giOpen)
            {   
                llSetKeyframedMotion( glFrameListOpen, [KFM_DATA,KFM_ROTATION]);
            }
            else
            {
                llSetKeyframedMotion( glFrameListClose, [KFM_DATA,KFM_ROTATION]);
            }                
            giOpen = !giOpen;
        }
    }
    
    timer()
    {
        giTouched = FALSE;
        llSetKeyframedMotion([],[]);    //Stop KFM movement
        if (!giOpen)
        {
            llSetRot(gvClosedRot);  // Corrects for any accumulated KFM errors by forcing "closed" rotation
        }        
        llSetTimerEvent(0.0);
    }
}

 

  • Like 1

Share this post


Link to post
Share on other sites
On 3/6/2015 at 10:21 PM, Lolita Erin said:

Innula, i manage to make the script work and is great but one think is there any way i can open the door sloower? how can i do that? thanks

That's odd.   I just tried to post a reply and it seems to have vanished.  Let's try again.

Sorry for the delay in replying but I missed the question earlier.

There's no ready way to vary the door speed when you use llSetRot or llSetLinkPrimitiveParams* to change the rotation.   The simulator simply snaps the door into the new rotation and interpolates the movement as best it can.

There are various work-rounds for this.  You could move the door in a very fast loop, a degree or so at a time, but I think I'd look for a different door in that case, one that has its pivot point in the center, and then use llTargetOmega to move the door at the desired speed and, on a timer,  llSetLocalRot or llSetLinkPPFast to snap it into place when llTargetOmega had done its stuff.

The move to the new forums chewed up the formatting of my original example, I see, so I'm reposting it here

integer intSwing =90;
rotation rotSwing;
vector vOffset;

default{    

	state_entry(){
		rotSwing = llEuler2Rot(<0.0,0.0,(float)intSwing>*DEG_TO_RAD);  //90 degrees on the z axis       
		vector size = llGetScale();       
		vOffset = <(size.x*-0.5),(size.y*-0.5),0.0>;//open away from someone standing in front of face 2 -- that is, in front of the prim -- hinged on the left.    
	}    

		touch_start(integer total_number){
		list l = llGetPrimitiveParams([PRIM_POS_LOCAL,PRIM_ROT_LOCAL]);
		vector v = llList2Vector(l,0);
		rotation r = llList2Rot(l,1);
		llSetPrimitiveParams([PRIM_POS_LOCAL,v+(vOffset-vOffset * rotSwing)*r,PRIM_ROT_LOCAL,rotSwing*r]);
		
		rotSwing.s*=-1;             
	}
}
 

 

Edited by Innula Zenovka
  • Like 3

Share this post


Link to post
Share on other sites
On 3/18/2017 at 5:48 PM, Innula Zenovka said:

The move to the new forums chewed up the formatting of my original example, I see, so I'm reposting it here

Thanks a bunch! This is exactly what I was looking for.
Worth noting that if the prim holding the script is resized after the script has initiated, the script will have to be reset or it'll rotate all wacky.

Edited by Ananta Infinity
Changed the word "open" to "rotate".

Share this post


Link to post
Share on other sites

Bi-Swing doors -- like the ones you see in a restaurant kitchen or a saloon, for example -- present a different sort of challenge.  Rotating the door itself isn't hard, but figuring out which side of the door an avatar is standing on can be.  One common approach is to use llDetectedTouchFace to determine which face of the door an avatar touched or collided with. That's not always convenient (if you have a mesh door with several faces on the same side of the door, for example), and there are times when you might want to use a sensor instead of a touch or collision event.  The script that I just posted in the LSL Library takes a different approach, using some trigonometry to locate the avatar relative to the door's default direction of swing.

Share this post


Link to post
Share on other sites

It should be obvious -- but might not be -- that a swinging door could also be a drawbridge, a pet door, a gate, a turret, a box lid, or anything that needs to rotate on a hinge -- even a pendulum.  One of the enduring challenges that scripters face with all hinged objects is dealing with local rotation, rather than regional rotation.  Ideally, a door should rotate on its local hinge axis so that it doesn't make any difference how you place the door relative to the region.  In the simplest case, that means writing

              llSetLocalRot(  intended_rotation * llGetLocalRot() );

where intended_rotation is something like llEuler2Rot(<0.0,0.0,PI/2>) for a 90 degree rotation on the object's own Z axis. In Void Singer's Simple Hinge Action script, for example, clicking the door opens or closes it with

touch_end( integer vIntNul ){
         llSetLocalRot( (gRotSwing = (ZERO_ROTATION / gRotSwing)) * llGetLocalRot() );
    }

where the operation gRotSwing = (ZERO_ROTATION / gRotSwing) is her intended_rotation, which reverses its direction of swing each time you click.  ( She could have set gRotSwing.s *= -1 to do the same thing, as in the script that Innula posted above in this thread, but this is a more compact way to do it.)

When you rotate a door in multiple steps, though, or when the door the child prim in a linkset, things can get complicated because it can mean getting the door's local rotation many times.  For example, take a look at 

for a discussion of options for rotating a drawbridge slowly. In particular, look at Innula's elegant reformulation of the approach in Toy Wylie's Smooth Rotating Door script.  For a different "hinged" application , see Dora Gustafson's Pendulum Motion script or her Universal Hinged Motion script, both of which use KFM.

Edited by Rolig Loon

Share this post


Link to post
Share on other sites

Since I can't edit the post above ^^ , I'll add that Innula posted a double door version of the smooth rotating drawbridge script at 

 

  • Thanks 1

Share this post


Link to post
Share on other sites

Are there any door scripting options that do not rely on rotations? Or that can be used without worrying that they will break through use, and leave the door at an open angle when closed? If there is not, and these rotating door scripts all seem to have these same issues, how would one repair the doors afterward? Editing them back into place every time, or having to replace them entirely every time, is inelegant and clunky.

Long question short, is this really the best we have to work with, or is it all just the result of looking in one direction at everything? Does every door script have to treat the door as a real-world door, and make it physically move? And how to fix the issue with doors being stuck at odd angles and having to be replaced when the script breaks?

Share this post


Link to post
Share on other sites

Yes, you can take the vey simple step of making a door that is just a texture on a phantom prim. You can just walk through it. If you visit some of the oldest regions in SL, which haven't been upgraded in years, you can still find doors like that. They used to be very popular. 

Any door these days has to at least look like it's rotating. It's what people expect now. You're right that any design has a potential downside. Scripters need to decide which solution is most appropriate for a setting and then devise ways to minimize or avoid those downsides.

Share this post


Link to post
Share on other sites

That does seem to be the case. No way around it save through an illusion of some sort, and it would have to look right.

Come to think of it, I have seen sliding doors as well, but they have their own problems, I'm sure.

Thank you for your honest attempt at an answer, even if it doesn't fix anything.

Share this post


Link to post
Share on other sites

You're welcome. Sliding doors are indeed another oprion, among others. You can have a lot of fun creating new door designs. If you decide to stick with standard rotating doors and want to avoid the problems you have just identified,  I suggest using Void Singer's simple hinge, referenced above. It is by far the simplest bug-free door script in SL.

Share this post


Link to post
Share on other sites
1 hour ago, PheebyKatz said:

That does seem to be the case. No way around it save through an illusion of some sort, and it would have to look right.

Come to think of it, I have seen sliding doors as well, but they have their own problems, I'm sure.

Thank you for your honest attempt at an answer, even if it doesn't fix anything.

You can also -- if it works with your design have doors that area always open.  I have made a few builds like this and the sold well so that means they are good for SOME folks anyway. Examples would be a store (personally I hate to have to open a door to a store and would just as soon walk through) or a beach cabana or any residence that had a large patio adjacent to the building.  Most folks know that the only privacy you have in SL is from an ORB or a private island. So it isn't like "locking doors" means anything at all. New folks don't understand that of course, so there is that :D. 

 

  • Like 1

Share this post


Link to post
Share on other sites
5 minutes ago, Turokhan Legion said:

just tried this script in one of my builds and it rotates the entire structure?  Is there a way to make the prim with the script only rotate using this method?

It's not clear which script you are referring to, because this is a summary sticky reference thread that presents many options for scripting doors.  In general, though, unless a script was designed to address a particular child prim by name, you should always assume that it belongs in the door itself, not in some other prim in the linkset.  When you place a movement script in the root prim of any linkset, the default assumption is that it is meant to make the entire linkset move.  

Share this post


Link to post
Share on other sites

Turokhan is most likely referencing one of the scripts which moves the entire door linkset, probably by moving the root prim, as a hinge. Best solution I've found for such a script moving your entire build is not to link the door to your build. One of the nice things about building in SL though is that not everything has to actually be nailed together.

So, short answer, if it's made to go in the door hinge, don't link it to the rest of the house or it will treat the house like a door.

Share this post


Link to post
Share on other sites

Imagine a door challenge that triggers most of your greatest scripting insecurities.  The client wants:

    --  Double cafe-style doors  ( visualize a pair of swinging doors into a restaurant kitchen or into a saloon )

    --  Doors must be linked to the building

    --  Doors must respond to both touch and collision

    --  Doors must not react to touch/collision/messages from other doors or other parts of the building

    --  Doors must always swing away from the avatar who touches or collides with them

    --  Doors must have an autoclose

    --  Doors are mesh (so cannot be "cut" ) and were not made with an edge pivot ( so they rotate around their geometric center )

Just be thankful that the client didn't also request slow rotation, although that would be fun to try.

The following script meets those requirements.  The same script is dropped into each of the two doors, with a few VERY SIGNIFICANT DIFFERENCES:

    --  The default swing angle, intSwing, in the second door must be the opposite of the angle in the first door ( so, -90 degrees instead of 90 degrees )

    --  The closed rotation (rClosed) and position (vClosed) must be the actual local rotation and position of each door when closed.  You'll have to measure those and hard code them into each script.  ( I know, there are ways around this, but this is easiest, believe me.)

    --  The definition of the hinge offset ( vOffset = <0.0,(size.y *= -0.5),0.0> ) in state_entry must be reversed in the second door's script, to put the hinge on the opposite side.

Note that this door is designed to be thin in its X dimension and to rotate on its Z axis.  Modifying it for other configurations is relatively trivial.

Note also that the user has to provide the swing angle, intSwing, and the autoclose time, fTime_to_close, both of which could be read in from a Description field (but aren't).

Finally, please be sure that the two doors have exactly the same unique name, so that they do not listen to other doors or talkative objects in the linkset.

This script combines features of other door scripts in this sticky thread, particularly the one described by Innula Zenovka.

// Cafe-style Double Doors

integer intSwing =90;   // Angle of swing, in degrees
integer iRev;
integer iTouched;

rotation rClosed = <0.00000, 0.00000, 0.00000, 1.00000>;    // Local rotation when closed. Measure this during setup.
rotation rotSwing;

vector vClosed =  <5.00794, 3.30038, 1.35212>;              // Local position when closed. Measure this during setup.
vector vOffset;

float fClosed;
float fTime_to_close = 8.0;     // Time until autoclose, in seconds

string strMyName;

Swing()     // Makes the door rotate
{
    list l = llGetPrimitiveParams([PRIM_POS_LOCAL,PRIM_ROT_LOCAL]);
    vector v = llList2Vector(l,0);
    rotation r = llList2Rot(l,1);
    llSetPrimitiveParams([PRIM_POS_LOCAL,v+ (vOffset  - vOffset *rotSwing)*r,PRIM_ROT_LOCAL,rotSwing*r]);
    rotSwing.s*=-1;     // Reverse the direction, ready for next swing   
}    

default
{
    state_entry()
    {
        strMyName = llGetLinkName(LINK_THIS);   // Identify this door and therefore its pair with the same name
        llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POS_LOCAL, vClosed,PRIM_ROT_LOCAL, rClosed]);    //Close door
        rotSwing = llEuler2Rot(<0.0,0.0,(float)intSwing>*DEG_TO_RAD);  //Angle of swing on the z axis. in radians       
        vector size = llGetScale();    // Get the size of the door
        
// This next line must be different for the second door, to put its hinge on the opposite edge   
        vOffset = <0.0,(size.y *= -0.5),0.0>;     // Calculate offset from door center to the hinge edge
        
// So, for the second door, remove the minus sign in size.y:
//        vOffset = <0.0,(size.y *= 0.5),0.0>;     // Calculate offset from door center to the hinge edge

        fClosed = llRot2Angle(rClosed);   // Calculate local closed rotation angle in radians.
    }
    
    on_rez(integer startup)
    {
        llResetScript();
    }
    
    touch_start(integer num)
    {
        vector AvPos = llDetectedPos(0)/llGetRot(); // Where is the toucher, relative to the building?
        vector MyPos = llGetPos()/llGetRot(); // Where is the door, relative to the building?
        if (AvPos.x < MyPos.x) // Toucher's X  position is greater than the door's
        {
            llMessageLinked(LINK_ALL_OTHERS,1,"swing",NULL_KEY);    // Signal the other door
            rotSwing.s *= -1;   // Reverse the swing direction
            iRev = TRUE;        // And set a flag to remember which way the door is swinging
        }
        else    // Toucher's X position is less than the door's
        {
            llMessageLinked(LINK_ALL_OTHERS,0,"swing",NULL_KEY);    // Signal the other door
        }            
        rotation lRot = llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0); // Door's local rotation
        if ( llFabs ( llRot2Angle(lRot) - fClosed ) > 0.1 ) // Is the door even slightly ajar?
        {
            rotSwing.s *= -1;       // Reverse direction
            llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POS_LOCAL,vClosed,PRIM_ROT_LOCAL,rClosed]);    //Close door
            llSetTimerEvent(0.0);
        }
        else    // Door is closed
        {    
            llSetTimerEvent(fTime_to_close);   // Set the timer to close it
            Swing();    // Go ahead and open it now
        }
    }
    
    collision_start(integer num)
    {
        if (!iTouched ) // Don't allow extra accidental collisions
        {
            // Same code as in the touch_start event, but without link messages to the other door
            // Most people will hit both doors anyway, and including link messages here makes the doors really wonky
            iTouched = TRUE;
            vector AvPos = llDetectedPos(0)/llGetRot(); 
            vector MyPos = llGetPos()/llGetRot(); 
            if (AvPos.x < MyPos.x) 
            {
                rotSwing.s *= -1;
                iRev = TRUE;
            }
            rotation lRot = llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0);
            // Do not react to collisions if the door is more than slightly ajar
            if ( llFabs ( llRot2Angle(lRot) - fClosed ) < 0.1 )
            {
                llSetTimerEvent(fTime_to_close);
                Swing();
            }
        }
    }

    link_message(integer from, integer iCode, string message, key id)
    {
        if ( llGetLinkName(from) == strMyName)  //Only react to link messages from the other door
        {
            if (message == "swing")
            {
                if ( iCode == 1 )   // Toucher's X  position is greater than the door's 
                {
                    rotSwing.s *= -1;   // Reverse swing direction
                    iRev = TRUE;        // And set a flag to remember which way the door is swinging
                }   
                rotation lRot = llList2Rot(llGetLinkPrimitiveParams(LINK_THIS,[PRIM_ROT_LOCAL]),0);
                if ( llFabs ( llRot2Angle(lRot) - fClosed ) > 0.1 ) // Is the door even slightly ajar?
                {
                    rotSwing.s *= -1;       // Reverse swing direction
                    llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POS_LOCAL,vClosed,PRIM_ROT_LOCAL,rClosed]);    //Close door
                    llSetTimerEvent(0.0);
                }
                else   // Door is closed
                {    
                    llSetTimerEvent( fTime_to_close );   // Set the timer to close it
                    Swing();    // Go ahead and open it now
                }
            }
        }
    }
    
    timer()
    {
        llSetTimerEvent(0.0);   // Kill the timer
        Swing();                // Swing the door
        if (iRev)               // If the flag  was set to mark swing direction toward the +X side ...
        {
            iRev = FALSE;       // Unset the flag
            rotSwing.s *= -1;   // Reverse swing direction
        }
        iTouched = FALSE;       // Allow the door to sense collisions again
    }             
        
}


 Afterthought:

How do you get the local rotation and position of a door in a linkset?  Like this:

default
{
    touch_start(integer total_number)
    {
        llSay(0, "Local Rot = " + (string)llGetLocalRot());
        llSay(0,"Local Pos = " + (string)llGetLocalPos());
    }
}

That's a handy scriptlet to have in your toolbox anyway.  Drop it into any linkset temporarily for instant gratification.
 

Edited by Rolig Loon
  • Thanks 1

Share this post


Link to post
Share on other sites

An "easy" trick you can use to determinate on which side of the door the user is, without going into complicated maths is to use a sensor with a half-sphere detection area pointed in one of the doorframe directions.

When the user touch the door, fire a sensor sweep with their uuid:

If they are detected by the sensor it means they are on side A, if no_sensor fires they are probably on side B.

Edited by Kyrah Abattoir

Share this post


Link to post
Share on other sites
3 hours ago, Kyrah Abattoir said:

An "easy" trick you can use to determinate on which side of the door the user is, without going into complicated maths is to use a sensor with a half-sphere detection area pointed in one of the doorframe directions.

When the user touch the door, fire a sensor sweep with their uuid:

If they are detected by the sensor it means they are on side A, if no_sensor fires they are probably on side B.

It doesn't have to be super complicated math!

vector avatar_direction = llVecNorm(avatar_position - llGetPos()) / llGetRot();

And then you just check if avatar_direction.x is positive or negative.

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...