Anyone who has tried creating an opening door in Second Life will no doubt have found that it is surprisingly tricky. In this post, I’ll describe a way of doing it that lets you build a door which opens, can be linked to other objects (such as a building!), and which will still function correctly when the building that it is linked to is rotated — if you have attempted to create doors before, you will no doubt already be aware of the problems that can arise with each of
these.

Creating a reliable opening door requires a mixture of a specially constructed prim, and a script. Let’s start with the prim.

Create a cube block.

Set the Start Cut parameter to 0.125 and the End Cut parameter to 0.625. You will notice that the pivot centre of the door is now at one edge of the visible part, instead of directly in the middle. This is the key (!) to the way that the door will work — we can now rotate the door very simply, and it will rotate around this hinge point.

Resize the result to something suitable for a door, making sure that you keep the pivot centre on the upright edge of the prim.

Basic door prim

Note that when you texture the door, the number of horizontal repeats will need to be set to 2, because only half of the prim is visible. Once you apply a texture you will this will become obvious, as the following pictures should make clear:

Door with unadjusted texture
Door with adjusted texture

Now for the script. To make sure that the door works correctly regardless of the angle to which it might have been rotated, we must use the Local rotation rather than the global rotation. We will use a variable to keep track of whether the door is open or closed — the only thing to be careful about here is that you must make sure the door is in the closed position at any time when the script is reset.

integer isOpen = FALSE;
float rotateBy = 0.8;
openclose() {
 if (isOpen)
 {
  llSetLocalRot(llEuler2Rot(<0,0,-rotateBy*PI_BY_TWO>)*llGetLocalRot());
  isOpen = FALSE;
 }
 else
 {
  llSetLocalRot(llEuler2Rot(<0,0,rotateBy*PI_BY_TWO>)*llGetLocalRot());
  isOpen = TRUE;
 }
}
default
{
    touch_start(integer total_number)
    {
        openclose();
    }
}

Close the build dialog, and touch the door a couple of times — it should open and close sensibly.

It is now possible to link the door to a building, and the door should continue to work properly. The only thing you must be careful about is that door must not be the root prim. If the door is made the root prim, when it rotates it will rotate the rest of the building with it! If the door is a child prim, it will only rotate itself.

For a more sophisticated door script, check out the Deluxe Door on the LSL Wiki site:

Library Door

An alternative is the sliding door. This doesn’t need a special prim — just size a normal cube into the size you want for the door, and use the script that you will find below (but read the rest of this first).

The slideBy amount is the amount by which the door will slide when it opens. Usually you will want this to be something a little smaller than the width of the door. This should leave part of the door visible, assuming, of course, that it is sliding into another prim.

We don’t need to use local co-ordinates for this door — the position is always local. However, you need to check which direction the door will slide in. This will normally be either the X or Y axis, depending on which is the width of the door. Be careful about rotating the door after adding the script, but before linking the door.

For example, here is a rough draft of a door. As you see, it is aligned so that it should slide along the X-axis (the red arrow).

Basic sliding door

If I rotate the door through 90 degrees, it now needs to slide along the Y-axis (the green arrow) and I will need to change the script accordingly.

Rotated sliding door

Once the door has been linked in place, you can rotate the entire object, and the door will still move in the correct direction in relation to the rest of the object.

Here’s the script, set to move along the X-axis.

integer isOpen = FALSE;
vector originalPos;
float slideBy = 1.5;
init()
{
    originalPos = llGetLocalPos();
    vector size = llGetScale();
    // Set up the amount to move by. Use size.y instead of size.x
    // if you want to slide along the y-axis.
    slideBy = size.x - 0.2;
}
openclose()
{
  if (isOpen)
  {
    llSetPos(originalPos);
    isOpen = FALSE;
  }
  else
  {
    llSetPos(<originalPos.x + slideBy, originalPos.y, originalPos.z>);
    // To move alon the y-axis, use this instead:
    // llSetPos();
    isOpen = TRUE;
  }
}
default
{
    state_entry()
    {
        init();
    }
    on_rez(integer param)
    {
        init();
    }
    touch_start(integer total_number)
    {
        openclose();
    }
    changed(integer change)
    {
        // When the links change, reset the script
        // so that we pick up the changes.
        if (change & CHANGED_LINK)
        {
            llResetScript();
        }
    }
}