a tale of Wyverns, Dragons and Ponies

Arrr, Treasure Chest!!!

May 26th, 2008 Posted in Isle of Wyrms

Make a Treasure Chest for the upcoming aquatically themed Isle of Wyrms Summer Festival. The idea being that the hatchies can hunt down the treasure chests, click them and the chest will open to reveal the treasure (and give the hatchie a gift).

Open Treasure Chest

The treasure chest itself is based on a stripped down version (from about 16 prims to 3) of Daryth’s treasure chest from one of her building kits. To save prims I decided to move the chest lid instead of having 2 chest lids and swapping them using alpha transparency. The issue with this is that setting location and rotation of a prim in SL can be a headache inducing exercise. SL uses quaternions to specify rotations. Although there are a number of transformation functions to switch to more commonly known units.

Preparation

The first step is to reshape the treasure chest to the desired size. In my example the body of the chest is a box of 1.024 m width x 0.512 m depth and x 0.368 m height. The lid of the box is a linked cylinder of the same dimensions, but cut so that only half a cylinder is present.

The next step is to find the local position of the lid prim in both the open and closed positions. Rather than have the treasure chest learn the position, similar to how the Timeless Linked Door works, I am hardcoding the positions (which means it will be sensitive to resizing of the whole object).

I use the following script to get the rotation and position of the lid. Note the rotation is returned as a vector in Euler co-ordinates and in radians.

// This reads back the Local Pos and Rot when touched
default {
    touch_start(integer total_number) {
        llOwnerSay("Rot = "+(string)llRot2Euler(llGetLocalRot()));
        llOwnerSay("Pos = "+(string)llGetLocalPos());
    }
}

Since I am hardcoding these, I could actually use a raw Rotation and therefore not need to convert the units. I have left this extra conversion in so that I can tweak the values at a later stage (tweaking in Euler is much easier than tweaking in Quaternion).

Local vs Global

The prim position and rotation setting commands have differing behaviors depending on how they are used. In this case, I am going to put the script in the lid and move it when touched, therefore I need to set the local position and rotation. To do this I need to make sure the lid is a child prim and not the root prim. If you move and rotate the root prim, it will move and rotate the whole object (global).

llSetRot() essentially works in the global co-ordinates (and it’s an offset for a child prim), so in this case I use llSetLocalRot() as that is always a rotation with respect to the root prim. llSetPos() always works as an offset of the roots prims position for a child prim, therefore it is ok.

However, if you use these two commands to move the lid, the movement is jerky. This is because both functions cause the script to sleep 0.2 seconds. A technique to get around this is to use llSetPrimitiveParams() and set both the rotation and position at the same time. For llSetPrimitiveParams(), the rotation command is the same as llSetRot(). Therefore we have to deal with converting this to a local rotation. I sought the LSL Potal for some wisdom, and this advice could be found:

“If you are trying to set the rotation of a child prim relative to the root prim then divide the local rotation by the root rotation.”

Final Script

The final script goes into the lid of the treasure chest and looks a little like this:

// Treasure Chest Script
// On Touch, this swaps from open to closed and visa versa
// Constants for Treasure Lid Position
vector rotClosed = <-1.57083, -0.00000, -0.00000>;
vector posClosed = < 0.00000,  0.00000,  0.18400>;
vector rotOpen =   <-1.57000,  0.00000,  1.57000>;
vector posOpen =   < 0.23610,  0.00000,  0.43744>;
// Global variables
integer chestOpen = FALSE;

// Lid movement function
moveChestLid (rotation rot, vector pos) {
    rot /= llGetRootRotation();
    llSetPrimitiveParams([PRIM_ROTATION, rot, PRIM_POSITION, pos]);
}

default {
    on_rez(integer start_param) { llResetScript(); }
    touch_start(integer total_number) {
        // Swap between positions
        if (chestOpen == TRUE) { // set closed
            chestOpen = FALSE;
            moveChestLid(llEuler2Rot(rotClosed),posClosed);
        } else { // set open
            chestOpen = TRUE;
            moveChestLid(llEuler2Rot(rotOpen),posOpen);
        }
    }//end touch_start
}

Finishing Touches

There are a number of final touches that can be added to the final treasure chest fairly easily:

  • trigger a particle effect when the box opens (and shut it off when the box closes)
  • automatically close the box after a certain length of time
  • give one (or more) inventory item(s) when the box is opened (although remember that you can only detect the avatar that touched the chest in the touch_start event)

Final Treasure Chest with Particles

You must be logged in to post a comment.