Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Chest and hinged lid headache

Solomon Devoix
Used Register
Join date: 22 Aug 2006
Posts: 496
12-08-2006 06:41
Okay, I'm building a chest and I want the top to actually pivot open, not just disappear from the "closed" position and reappear in the "open" position... in other words, NOT using the "make two copies of the lid, keep one invisible at all times" option. Oh, it's one of those chests with a curved lid, like a pirate chest... I used a slightly flattened half cylinder.

I got that to work... I created another long, thin cylinder to be the "hinge", positioned it along one edge of the half-cylinder that's the lid, and made the "hinge" the root prim so when it rotates, it swings the lid along with it. Fine and dandy.

Problem: if anyone moves the chest, the lid (and hinge) stay behind, because the main chest is one object (2 prims: hollow box main body and one that's a bottom) and the lid & hinge combo is a seperate object. And of course if I link them, then either the lid won't rotate, or the entire chest rotates (depending on which prim is the root prim).

I fooled around with all kinds of solutions... and none of them were satisfactory, mainly because they didn't work properly.

Finally I hit on the idea of having all four pieces linked into a single object... when someone opens or closes the chest (by clicking on the lid) a script in the main body of the chest breaks the links between the prims, the "hinge" script links the lid to the hinge, the hinge rotates, and then the script in the main body links the hinge & lid object back into the main body. This way, the hinge and lid are a seperate object only when opening or closing... at all other times the chest is a single linkset, so it can be grabbed and moved as a unit, with the lid open or closed.

Once again, I got this to work... but!

Before the lid starts moving (to open or close), and after it's done moving... it sort of does a little flip/twist motion. Every. Frickin'. Time. And I have NO idea why. It's driving me bonkers!

Initially I suspected that the process of breaking the links between the prims, and/or creating links, might be responsible, but I don't think so. The prim that forms the bottom (legs) of the chest also gets relinked to the main body of the chest after the links are broken, and IT doesn't do any funny flipping around.

I wish there were a way to capture this in a short animation so I could demonstrate it... it would only need to be roughly 3 seconds long... but at the moment I don't have a way to do that. So the above description will have to do.

I'll include the code of the scripts below, just in case I'm doing something wrong... but I've altered the way it does things six ways from Sunday, and STILL have the SAME [censored] flip/twist every time...!

Edit: Okay, I figured it out. Linking the hinge & lid COMBO back to the main body causes the twist/flip behavior for some reason; if I have the hinge script break the link to the lid when it's done moving, and have the main body relink to both the hinge and the lid SEPERATELY, there's no funny stuff. So now I just have to live with the built-in 1 second delay before the lid opens or closes after it's been clicked on.

So... does anyone have any idea why linking in a linkset, instead of individual prims, causes them to momentarily rotate wildly before settling down back into the position they had before being linked in?


The script in the main body of the chest:
CODE

key lidkey = "";
key hingekey = "";
key legkey = "";

integer channel = 23456;

store_keys()
{
integer i = 0;
integer num = llGetNumberOfPrims();
string name = "";
key id = "";

for(i=1; i< (num + 1); i++)
{
name = llGetLinkName(i);
id = llGetLinkKey(i);
if(name == "ChestHinge")
hingekey = id;
else if(name == "ChestLid")
lidkey = id;
else if(name == "ChestLegs")
legkey = id;
}
llMessageLinked(LINK_SET, 0, "LIDKEY", lidkey); // so the hinge can link to it
}

lid_touched()
{
if ((llGetPermissions() & PERMISSION_CHANGE_LINKS))
{
store_keys();
llBreakAllLinks(); // split it up
llCreateLink(legkey, TRUE); // put the legs back on
llSay(channel,"FLIP"); // tell the lid to open or close
}
}

get_perms()
{
if (!(llGetPermissions() & PERMISSION_CHANGE_LINKS))
{
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
llMessageLinked(LINK_SET, 0, "GETPERMS", ""); // tell the hinge to also get permissions
}
llListen(channel,"","","");
}

default
{
state_entry()
{
get_perms();
}

on_rez(integer num)
{
get_perms();
}

run_time_permissions(integer perm)
{
if (perm & PERMISSION_CHANGE_LINKS)
{
store_keys();
llListen(channel,"","","");
}
}

listen(integer channel, string name, key id, string message)
{
if((id == hingekey) && (message=="DONE"))
llCreateLink(hingekey, TRUE); // link hinge & lid combo back into main object
}

link_message(integer sender_num, integer num, string str, key id)
{
if(str == "START") // the lid's been touched, so start the process to open or close it
lid_touched();
}
}



The script in the hinge:
CODE

integer channel = 23456;
key lidkey = "";
integer Open = FALSE;

get_perms()
{
if (!(llGetPermissions() & PERMISSION_CHANGE_LINKS))
llRequestPermissions(llGetOwner(), PERMISSION_CHANGE_LINKS);
llListen(channel,"","","");
}

default
{
state_entry()
{
get_perms();
}

on_rez(integer num)
{
get_perms();
}

listen(integer channel, string name, key id, string message)
{
if(message == "FLIP")
{
llCreateLink(lidkey, TRUE); // link the lid to the hinge (this prim)

if(Open)
{
llSetRot((llEuler2Rot(<0,0,-PI/2>)* llGetRot() ));
Open = FALSE;
}
else
{
llSetRot((llEuler2Rot(<0,0,PI/2>)*llGetRot()));
Open = TRUE;
}

llSay(channel, "DONE");
}

if(message == "GETPERMS")
get_perms();
}

link_message(integer sender_num, integer num, string str, key id)
{
if(str == "LIDKEY") // get and store the UUID of the lid
lidkey = id;
}
}


And just for completeness' sake, the tiny little script from the lid:
CODE

integer channel = 23456;

default
{
state_entry()
{
}

touch_start(integer touched)
{
llMessageLinked(LINK_SET,0,"START","");
}

}
Tiarnalalon Sismondi
Registered User
Join date: 1 Jun 2006
Posts: 402
12-08-2006 07:58
Has nothing to do with your script I'm afraid, it sounds like you found the best solution though.

What you described happens whenever you link 2 linksets together due to the root prim change when you linked the lid and hinge back to the chest.

You'll get the same effect anytime there's a root prim change in a linkset unless you unlink it first.
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
12-08-2006 12:44
alternately to breaking and creating links, could you not just use setprimparams to move the lid to its new position and rotation? Easy peasy.
_____________________
Solomon Devoix
Used Register
Join date: 22 Aug 2006
Posts: 496
12-08-2006 13:32
From: Kage Seraph
alternately to breaking and creating links, could you not just use setprimparams to move the lid to its new position and rotation? Easy peasy.

Not from where I'm standing it's not easy. For one thing... rotating the lid would rotate it around its GEOMETRIC center, not cause it to rotate around one edge so that it "swings up" like a real chest does.

If you have a suggestion as to how to go about doing that, so I don't have to mess with breaking & creating links, I'd be very grateful!
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
12-08-2006 14:11
From: Solomon Devoix
Not from where I'm standing it's not easy. For one thing... rotating the lid would rotate it around its GEOMETRIC center, not cause it to rotate around one edge so that it "swings up" like a real chest does.


To paraphrase the tautology, you are uttering a true fact. llSetLocalRot does in fact rotate the child prim about itself, not by the parent object. It's an important point to keep in mind for applications like this.

And that's why I suggested using llSetPrimParams to rotate and move the lid between open and closed states. With that function both ops are updated to the client simultaneously, and so the lid apprears to rotate properly on the edge once you specify the required open/closed rotations and positions.

to wit:
CODE

integer open = FALSE;

rotation open_rot = <w1,x1,y1,z1>;
rotation close_rot = <w2,x2,y2,z2>;

vector open = <x1,y1,z1>;
vector close = <x2,y2,z2>;

//...

touch_start(integer severed_head)
{
if(open)
{
llSetPrimitiveParams([PRIM_POSITION, close, PRIM_ROTATION, close_rot]);
open = !open;
}
else
{
llSetPrimitiveParams([PRIM_POSITION, open, PRIM_ROTATION, open_rot]);
open = !open;
}
}


Or something like that. I use this exact technique to dynamically update the geometries in my current vehicle project and it pretty much works like a charm. Of course, it's a hassle to get all the rotations and positions initially, but usually smooth sailing from there.

Another alternative might be to use this scriptlet or do a scripting tips forum search on "offset rotation" as this particular question has come up a number of times.

Finally, the quote in your profile... is that from Dune...? I think...?
_____________________
Jeremy Bender
anachronistic iconoclast
Join date: 12 Aug 2006
Posts: 99
12-08-2006 14:33
I don't have any code right now, but if you make the lid of the chest so that it is "cut" by 50%, when you rotate it, it will appear to be rotating on one edge. (I think you use 0.125 and 0.675 (0.625?) as "cut" parameters.) All the pieces can be linked together and the lid rotated on touch using a script.

If it's part of a linked set you will probably have to use llGetLocalRot() to rotate the lid and probably have to take into account the rotation (if any) of the chest as well, but it would be a lot simpler script than the one you are using.

This won't work unless the lid is a single prim however and it has to be of a shape that half of a given prim shape would be okay. In other words if its a cube it will work fine, but other shapes maybe not.
WindyWeather Vanalten
Registered User
Join date: 27 Nov 2006
Posts: 53
Yep. That works....
12-08-2006 15:19
Just made a hinged box. Here is the script. Of course you might like to key frame this with a timer, but the built in SL delay and smoothing don't look too bad.

BTW, note the cut B and E that gives me a lid with hinge on the edge.
Gee wouldn't it be cool to be able to export the object and attach it here.
Anyway, you can visit the box and try it out. I'll leave it on my lawn for a while at:
Naiad(158,189.23). I'll even mark it so you can take a copy and play with it.


wwv

CODE


rotation gInitialRot;
vector gInitialPos;
integer frame;
float openAngle = PI_BY_TWO;
integer open = FALSE;

// assume that the lid was closed initially
closeLid()
{
llSetLocalRot(gInitialRot);
open = FALSE;
}

// open lid locally
openLid()
{
vector phi = llRot2Euler(gInitialRot);
phi.z +=openAngle;
rotation newRot = llEuler2Rot( phi );
llSetLocalRot( newRot );
open = TRUE;
}


default
{
state_entry()
{
gInitialRot = llGetLocalRot();
gInitialPos = llGetPos();
}

touch_start(integer total_number)
{
if ( open )
{
closeLid();
}
else
{
openLid();
}
}
timer()
{
}
}

// path cut for edge hinge is approximately
// B 0.654 E .880
//


Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
12-08-2006 16:01
Windy,

use llSetLocalRot and getLocalRot, not llSetRot, as it calculates the rotation while taking into account the object's preexisting rotation.
_____________________
Lazink Maeterlinck
Registered User
Join date: 8 Nov 2005
Posts: 332
12-08-2006 16:22
you can also do this with trig properties if you want and llSin and llCos. It'll save you a prim :)