Jump to content

Working a drawbridge with counterbalance


Vladamir Bearsfoot
 Share

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

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

Recommended Posts

I am trying to rig the drawbridge so that I have a control that is supposed to operate the bridge, but I have no clue on how to do that. I have a door script in the cylinder that is operating the door. I have seen other doors and such operate with a switch of some sort in order to open or close the door in a way that does not all anyone to operate unless they are moving the switch. Any suggestions on how I should proceed?drawbridge6_001.pngdrawbridge7_001.pngdrawbridge8_001.png

Link to comment
Share on other sites

It's hard to be specific without knowing what you mean by "moving a switch", but generically this is just a matter of putting your script in the root prim (your cut-prim door itself or the hinge prim, if present), and then designating a specific prim in the linkset as your switch.  You don't need to click your drawbridge to raise or lower it.  You could click any prim that it's attached to  -- a lever, a secret panel, a doorbell .....

integer gIntSwing = 90;/*//-- use -# to reverse the direction of swing, eg. -90; --//*/rotation gRotSwing;integer switch_prim = 2;   //Or whatever the prim # of your switch is.default{    state_entry(){        gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD> );    }        touch_end( integer vIntNul ){         if (llDetectedLinkNumber(0) == switch_prim){              llSetLocalRot( (gRotSwing = (ZERO_ROTATION / gRotSwing)) * llGetLocalRot() );         }    }}

 

 This is Void Singer's simple hinge action.

 

 

Link to comment
Share on other sites

this is a hatch script from somewhere using Key frames.

you can mod it from touch to a listen or link message...play with the variables

but beware of stack heap  when changing "steps"

 

you can rez a box, flatten it, and put this script in it ...will go from

flat to 90 deg up hinged on the -X  lower edge

_______________________________________

 

float angleEnd = -PI_BY_TWO;
float speed=0.2; // m/S
float steps=4.0; // number of Key Frames
float step=0.0;
list KFMlist=[];
vector V;
integer open=TRUE;
vector basePos;
rotation baseRot;
 
float motion_time( float mt)
{
    mt = llRound(45.0*mt)/45.0;
    if ( mt > 0.11111111 ) return mt;
    else return 0.11111111;
}
 
default
{
    state_entry()
    {
        llSetMemoryLimit(0x2000);
        llSetPrimitiveParams([PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_CONVEX]);
        basePos = llGetPos();
        baseRot = llGetRot();
        vector v1 = 0.5*llGetScale()*llGetRot();
        rotation deltaRot = llEuler2Rot(< 0.0, angleEnd/steps, 0.0>);
        while ( step < steps )
        {
            V = v1*llAxisAngle2Rot(llRot2Left(llGetRot()), angleEnd*step/steps);
            V = v1*llAxisAngle2Rot(llRot2Left(llGetRot()), angleEnd*(step+1.0)/steps) - V;
            KFMlist += [V, deltaRot, motion_time(llVecMag(V)/speed)];
            step += 1.0;
        }
    }
    touch_end( integer n)
    {
        
        basePos = llGetPos();
        baseRot = llGetRot();
        
        llSetKeyframedMotion( [], []);
        if ( open )
        {
            llSetPrimitiveParams([PRIM_POSITION, basePos, PRIM_ROTATION, baseRot]);
            llSetKeyframedMotion( KFMlist, []);
        }
        else
        {
            llSetKeyframedMotion( KFMlist, [KFM_MODE, KFM_REVERSE]);
        }
        open = !open;
       
    }
    on_rez( integer n) { llResetScript(); }
}

__________________________________

Link to comment
Share on other sites


Rolig Loon wrote:

It's hard to be specific without knowing what you mean by "moving a switch", but generically this is just a matter of putting your script in the root prim (your cut-prim door itself or the hinge prim, if present), and then designating a specific prim in the linkset as your switch.  You don't need to click your drawbridge to raise or lower it.  You could click any prim that it's attached to  -- a lever, a secret panel, a doorbell .....
integer gIntSwing = 90;/*//-- use -# to reverse the direction of swing, eg. -90; --//*/rotation gRotSwing;integer switch_prim = 2;   //Or whatever the prim # of your switch is.default{    state_entry(){        gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD> );    }        touch_end( integer vIntNul ){         if (llDetectedLinkNumber(0) == switch_prim){              llSetLocalRot( (gRotSwing = (ZERO_ROTATION / gRotSwing)) * llGetLocalRot() );         }    }}

 

 This is
.

 

 

Hi Rolig:)

Thank you for posting this - trying out the scripts posted here is always educational. 

I wondered what change I'd need to make to this script to move all of the linkset EXCEPT for the switch prim. Maybe that isn't possible though... and one would have to use a remote trigger from another unlinked prim?

Emma :)

Link to comment
Share on other sites

That's not quite as easy, Emma.  If you put this script into the linkset (where the switch is the root prim), the door and prim 2 will rotate around their own local Z axes....

integer gIntSwing = 45;/*//-- use -# to reverse the direction of swing, eg. -90; --//*/rotation gRotSwing;integer door_prim = 3;   //Or whatever the prim # of your door is.default{    state_entry(){        gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD> );    }        touch_end( integer vIntNul ){        if(llDetectedLinkNumber(0) == 1){            llSetLinkPrimitiveParamsFast(door_prim, [PRIM_ROT_LOCAL,(gRotSwing = (ZERO_ROTATION / gRotSwing)) * llGetLocalRot() ]);            llSetLinkPrimitiveParamsFast(2, [PRIM_ROT_LOCAL,gRotSwing * llGetLocalRot() ]);        }    }}

 What I suspect you want to do, though, is to rotate all prims (except the root prim) around the door's Z axis.  I can't get in world at the moment to do that and I don't trust myself to do it correctly in my head.

Link to comment
Share on other sites

A switch is indeed what I am trying to make. The script that I have in my bridge is in the root prim, but I am guessing either I will have to modify that script, or replace it entirely as I don't see anything about switch_prim in there. How is it that you name a switch, change the object name to "2" in the example you show? As you can tell, scripting is not my strong point.

Link to comment
Share on other sites

@Emma  -- The answer is easy and hard at the same time.  The easy part is that you can change the rotation axis by just changing the order of the arguments in

gRotSwing = llEuler2Rot( <0.0, 0.0, (float)gIntSwing * DEG_TO_RAD> );

It's now rotating on the Z axis.  If you want it to rotate on X, just change it to

gRotSwing = llEuler2Rot( <(float)gIntSwing * DEG_TO_RAD,0.0,0.0> );

 The hard part is that you can't cut a standard cube parallel to the X axis, so there's no way to make a normal door rotate around that apparent edge.  You have two choices, therefore.  One is to use the door as designed (rotating around its Z axis) but turn the local Z axis so that it's horizontal.  That's what I suggested to the OP.  The more elegant solution is to make a mesh door and include a tiny transparent element that is placed strategically so that the visible edge that you want to make the hinge coincides with the X-axis.  Then you can use my second formulation, above.  That's the easiest way to make a good mesh door, BTW.  See

.

 

Link to comment
Share on other sites

While I would certainly normally recommend following Rolig's advice about turning the cut prim or using the method shown in the video to offset a mesh door, here's how to offset the rotation of the prim without cutting it, should you need to do that (someone gives you a mesh door that's not been offset, for example).

This presupposes you've called the prim you want to move, "drawbridge" and that the script in in the prim you want to touch in order to move the drawbridge prim.   It also presupposes you want the drawbridge's apparent hinge to be the edge between sides 0 and 1 (which is probably the case with an unrotated prim).

 

integer drawbridgePrim;integer myLinkNumber;rotation x90;vector offset;vector size;default{    state_entry()    {        myLinkNumber = llGetLinkNumber();        integer max = llGetNumberOfPrims();        do {            list li = llGetLinkPrimitiveParams(max,[PRIM_NAME,PRIM_SIZE]);            if("drawbridge"==llToLower(llList2String(li,0))){                size = llList2Vector(li,1);                drawbridgePrim = max;            }        }        while (--max);        x90 = llEuler2Rot(<90.0,0.0,0.0>*DEG_TO_RAD);//90 degrees on the x axis        offset = <0.0,(size.y*-0.5),(size.z*0.5)>;//pivot on the edge between sides 0 and 1 of a box prim    }    changed(integer change)    {        if (change & CHANGED_LINK || change & CHANGED_SCALE){            llResetScript();        }    }    touch_start(integer total_number)    {        if(llDetectedLinkNumber(0)==myLinkNumber){            list l = llGetLinkPrimitiveParams(drawbridgePrim,[PRIM_POS_LOCAL,PRIM_ROT_LOCAL]);            vector LocalPos = llList2Vector(l,0);            rotation LocalRot = llList2Rot(l,1);            llSetLinkPrimitiveParamsFast(drawbridgePrim,[PRIM_POS_LOCAL, LocalPos +(offset-offset*x90)*LocalRot,                PRIM_ROT_LOCAL,x90*LocalRot]);            x90=ZERO_ROTATION/x90;        }    }}

 

Link to comment
Share on other sites

Innula's suggestion is another possible solution.  It accomplishes the same task by using a bit more math and has the advantage that it doesn't require you you work with a cut prim as the door.  Her calculations do that by offseting the rotation axis to the edge of the prim.  So, now you have a selection of methods to play with. :smileyhappy:

Link to comment
Share on other sites

  • 3 weeks later...

Well, got around to looking at this tonight, and giving it a try. Instead of swinging up and down, it swung right to left. I am guessing that is because the main prim is a cylinder so it is turning it that way? Sorry I have not been around, just really busy lately. Perhaps the original script that is in there I should show? I believe that is a freebie from one of the big teaching places. I will look tomorrow and post what it is so(if I allowed).

Link to comment
Share on other sites

Okay, sorry for the delay, been busy. Here is the script I have in the drawbridge.

 

// ==========================================================================
// Basic Door Script
// Original Script By Unknown
// Modifications made by Zanlew Wu 01-Apr-2003
//
//============================================
// Declare global constants.
//
integer SW_OPEN = FALSE; // used to signify door swinging open
integer SW_CLOSE = TRUE; // used to signify door swinging closed
integer SW_NORMAL = FALSE; // used to signify a normal swing
integer SW_REVERSE = TRUE; // used to signify a reverse swing
//
// Note that it is hard to call a given swing outward or inward as that has
// a lot to do witht he rotation and/or orientation of the door, which
// swing direction is correct/desired, and whether you are referring to the
// swing from the "out" side of the door or the "in" side of the door. It
// was easier by convention to call the swings normal and reverse.

//============================================
// Declare global fields.
//
key gfOwnerKey; // Owner of the elevator object
integer gfDoorClosed; // Current state of the door (Open, Closed)
integer gfDoorSwing; // Deteremines which way the door swings (In, Out)

//============================================
// gmInitFields
//
gmInitFields()
{
//
// Get the owner of the door.
//
gfOwnerKey = llGetOwner();

//
// Close doors by default.
//
gfDoorClosed = TRUE;

//
// Set the door swing.
//
gfDoorSwing = SW_NORMAL;

return;
}
//
// End of gmInitVars
//============================================

//============================================
// gmSwingDoor
//
gmSwingDoor(integer direction)
{
//-----------------------
// Local variable defines
//
rotation rot;
rotation delta;
float piVal;

//
// First thing we need to do is decide whether we are applying a
// negative or positive PI value to the door swing algorythm. The
// positive or negative makes the difference on which direction the door
// swings. Additionally, since we allow the doors to modify their swing
// direction (so the same door can be placed for inward or outward
// swing, we have to take that into account as well. Best to determine
// that value first. The rest of the formula does not change regardless
// of door swing direction.
//
// So we have two variables to pay attention to: open/close and swing
// in/out. First we start with open/close. We will presume the
// following:
// SW_OPEN: +PI
// SW_CLOSE: -PI
// This also presumes that the door has a standard swing value of
// SW_NORMAL.
//
// A door that has had it's swing changed would have those values
// reversed:
// SW_OPEN: -PI
// SW_CLOSE: +PI
//
// The variable passed into this method determines if the intent were
// to open the door or close it.
//
// The global field gfDoorSwing will be used to modify the PI based on
// whether the door normally swings in or out.
//
if (direction == SW_OPEN)
{
//
// Ok, we know the door is opening. Assign a +PI value to piVal.
//
piVal = PI/4;
//
// Now check to see if the door has it's swing reversed.
//
if (gfDoorSwing == SW_REVERSE)
{
//
// Yep, it's reversed and we are opening the door, so replace
// piVal with a -PI value.
//
piVal = -PI/4;
}
} else
{
//
// So we know we are closing the door this time. Assign a -PI value
// to piVal.
//
piVal = -PI/4;
//
// Now check to see if the door has it's swing reversed.
//
if (gfDoorSwing == SW_REVERSE)
{
//
// Yep, it's reversed and we are closing the door, so we need to
// assing a +PI value to piVal.
//
piVal = PI/4;
}
}

//
// This formula was part of the original script and is what makes
// the door swing open and closed. This formula use a Pi/-Pi to
// move the door one quarter-circle in total distance.
//
// The only change I've made to this function is to replace the hard-
// coded PI/-PI values with a variable that is adjusted
// programmatically to suit the operation at hand.
//
rot = llGetRot();
delta = llEuler2Rot(<0,0,piVal> );
rot = delta * rot;
llSetRot(rot);
llSleep(0.25);
rot = delta * rot;
llSetRot(rot);

return;
}
//
// End of gmSwingDoor
//============================================

//============================================
// gmCloseDoor
//
// The close command is used to close doors. If the doors are
// locked, the doors cannot be closed. (Note: presumably, this
// script does not allow doors to be opened AND locked at the same
// time). If the doors are already closed, they cannot be
// re-closed. These checks will be made before performing a door
// close operation. Once the door is successfully closed, the
// door's state will be updated.
//
gmCloseDoor()
{
//
// First let's check to see if the door is already closed. If it
// is, let the user know.
//
if (gfDoorClosed == TRUE)
{
//
// Yep, it was already closed.
//
llSay (0, "This door is already closed.");
return;
}

//
// Now we generate the proper sound for the door closing.
//
llTriggerSound("Door close", 1.0);

//
// Now we call the method gmSwingDoor with the SW_CLOSE argument (since
// we are closing the door.
//
gmSwingDoor(SW_CLOSE);

//
// Now that the door is closed, set the door's state.
//
gfDoorClosed = TRUE;

return;
}
//
// End of gmCloseDoor
//============================================

//============================================
// gmOpenDoor
//
// The open command is used to open the doors. If the doors are
// locked, the doors cannot be opened. If the doors are already
// opened, they cannot be re-opened. These checks will be made
// before performing a door open operation. Once the door is
// successfully opened, the door's state will be updated.
//
gmOpenDoor()
{
//
// First let's check to see if the door is open already. If it is,
// let the user know.
//
if (gfDoorClosed == FALSE)
{
//
// Yep, it was already open.
//
llSay (0, "This door is already open.");
return;
}

//
// Now we generate the proper sound for the door closing.
//
llTriggerSound("Door open", 1.0);

//
// Now we call the method gmSwingDoor with the SW_OPEN argument (since
// we are opening the door.
//
gmSwingDoor(SW_OPEN);

//
// Now that the door is opened, set the door's state.
//
gfDoorClosed = FALSE;
return;
}
//
// End of gmOpenDoor
//============================================


//============================================
// Default State
//
// This is the state that is automatically bootstrapped when the object
// is first created/rez'd, or the world or environment resets.
//
default
{
//
// state_entry() is the first method executed when the state it resides
// in is run. So State A, B, and C all can have state_entry methods,
// and if they do, they are run when their respective states are called
// and or executed.
//
state_entry()
{
//
// Perform global field initialization
//
gmInitFields();

//
// We are listening for two different commands. This script is set
// up to accept spoken commands only from the object owner.
//
llListen(0, "", "", "open");
llListen(0, "", "", "close");
}

listen(integer channel, string name, key id, string msg)
{
//-----------------------
// Local variable defines
//
string operName;
string ownerName;

//
// Ideally, we want the door only to work on spoken commands
// from the owner. To accomplish this task, we need to check the
// id of the owner and the person issuing the command to see if
// they match.
//
// Alternately, commands can be issued from the control panel,
// which can be used by anyone. Later on, it will be presumed that
// access to the control panel will be controlled.
//

//
// First get the string names of the owner and the operator so they
// can be compared.
//
operName = llKey2Name(id);
ownerName = llKey2Name(gfOwnerKey);

//
// First we check the owner.
//
if (ownerName != operName)
{
//
// Nope, not a match.
//
llTriggerSound("Door knock", 0.2);
llSay(0, "Voice command access is for owner only.");
return;
}

//----------------------------------------
// OPEN DOOR
//
if(msg == "open")
{
gmOpenDoor();
}

//----------------------------------------
// CLOSE DOOR
//
if (msg == "close")
{
gmCloseDoor();
}
}

touch_start(integer i)
{
//
// This is the same code as the UNLOCK, OPEN and CLOSE DOOR
// code. For reasons of brevity, I have removed the comments
// from this copy of the code.
//
if (gfDoorClosed == FALSE)
{
llTriggerSound("Door close", 1.0);
gmSwingDoor(SW_CLOSE);
gfDoorClosed = TRUE;
return;
} else
{
llTriggerSound("Door open", 1.0);
gmSwingDoor(SW_OPEN);
gfDoorClosed = FALSE;
return;
}
}
}

Link to comment
Share on other sites

Well, here is what I see for my Drawbridge, root prim and such. It is three parts, the cylinder and the two boxes. When I used the demo it only moved the door piece, not the counter balance. I had added a small box much like you had in the demo as the switch. I thought that when it was activated that it would rotate the cylinder and all parts would move with it. If there is a way I could understand how scripting works a little better, I think I could see what everyone means. Hope you understand how much of a novice I am now.

 

 

drawbridge.jpg

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3982 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...