Jump to content

drawbridge


Zara Avindar
 Share

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

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

Recommended Posts

I have a script that I've been using on a drawbridge that works great. Then I moved the drawbridge to a new location and the bridge is reorienting itself to North - South whenever it is operated. I'm assuming something is wrong with my math in the orientation function. I'm hoping that someone can pinpoint what it is for me... thank you in advance.

Here's is my orientation function that I'm using...

rotation slerp(rotation source,rotation target,float amount)
{
    return llAxisAngle2Rot(llRot2Axis(target/=source),amount*llRot2Angle(target))*source;
}

Link to comment
Share on other sites

I see the word "target" in there several times... a little info on what the target is a reference to might help, but honestly I think Rolig is the best person for this one. She got that rotation whatsit all sorted out before we were even rezzed.

@Rolig Loon, we summon thee, we need your rotational guidance, yet again, as we are but apprentice scripters~!

I have no doubt you'll get the help you need, just be patient...

Link to comment
Share on other sites

The parameters definitely need to be explained.

I'm not smart enough to know what is wrong with the function just by looking at it, and seeing the input values would be helpful.

Another thing I would probably do (to make it easier to understand even without context) is rewrite the function to take a starting rotation, and a vector to rotate around by X degrees. Return the new rotation based on that. 

Unless that's what's already going on?

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

3 hours ago, Zara Avindar said:

I have a script that I've been using on a drawbridge that works great. Then I moved the drawbridge to a new location and the bridge is reorienting itself to North - South whenever it is operated. I'm assuming something is wrong with my math in the orientation function. I'm hoping that someone can pinpoint what it is for me... thank you in advance.

Here's is my orientation function that I'm using...

rotation slerp(rotation source,rotation target,float amount)
{
    return llAxisAngle2Rot(llRot2Axis(target/=source),amount*llRot2Angle(target))*source;
}

That sounds like a fairly straightforward rotation problem, but I agree with Berksey and Wulfie that it would be a lot easier to address if we could see the script.  What's happening is that you have scripted the drawbridge to rotate in a local reference frame and need to apply a transformation matrix to put it in a regional reference frame.  Typically, that simply involves multiplying the rotation that you have already calculated by the object's regional rotation ( llGetRot() ).  So, for example, if your local rotation is a 90 degree rotation around the object's own Y axis, you'd get the regional rotation from

rotation RegRot = llEuler2Rot(<0.0,PI/2,0.0>) * llGetRot();

That way, regardless of which way the object points, it will still rotate around its own Y axis.  Your slerp function may be necessary in the particular setting you've created, and I suspect that you may be able to get it to do what you want by just adding that little llGetRot step.  Without knowing the full context, though, I can't be sure. Personally, I would opt for a much easier solution if I could.  I suggest spending time pondering http://wiki.secondlife.com/wiki/Rotation . Sooner or later, all LSL scripters end up devoting sleepless nights digesting it and testing its implications.

  • Like 2
Link to comment
Share on other sites

Per everyone's request.... here is the complete script...

// Zara's Drawbridge - v1.1
// by Zara Avindar
 
float openingTime=5.0;      // in seconds
float openingAngle=-50.0;    // in degrees
float autocloseTime=30.0;   // in seconds
integer steps=5;            // number of internal rotation steps
integer world=TRUE;         // align to world or root prim rotation
 
string soundOpen="";
string soundClose="";
 
float omega=0.0;
 
vector axis;
//Change rot to quaternion rotation if changing root rotation
rotation closedRot = ZERO_ROTATION;
rotation openRot;
 
integer swinging;
integer open;
integer myDialogListener;
integer bridgeListener;
 
// Functions
setupDialogListen(integer chan){ // Dialog Menu Listener
    llListenRemove(myDialogListener);
    myDialogListener = llListen(chan,"",NULL_KEY,"");
    llSetTimerEvent(30);
}

sound(string name)
{
    if(llGetInventoryType(name)==INVENTORY_SOUND)
        llTriggerSound(name,1.0);
}
 
openBridge(integer yes)
{
    if(yes)
        llSay (0,"Please wait drawbridge is opening");
        sound(soundOpen);
 
    vector useAxis=axis;
    open=yes;
 
    if(!yes)
        useAxis=-axis;
 
    llSetTimerEvent(openingTime/(float) steps);
    llTargetOmega(useAxis,omega,1.0);
}
 
go()
{
    if(swinging==0)
    {
        if(!open)
        {
            axis=<1.0,0.0,0.0>/llGetRootRotation();
 
            if(world)
                openRot=llGetRot()*llEuler2Rot(<openingAngle,0.0,0.0>*DEG_TO_RAD)/llGetRootRotation();
            else
                openRot=closedRot*llEuler2Rot(<openingAngle,0.0,0.0>*DEG_TO_RAD);
        }
        swinging=steps;
        openBridge(!open);
    }
}

go2()
{
    if(swinging>0)
    {
        swinging--;
        if(swinging!=0)
        {
            float amount=(float) swinging/(float) steps;
            if(open)
                amount=1.0-amount;
            llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,slerp(closedRot,openRot,amount)]);
            return;
        }

        llTargetOmega(axis,0.0,0.0);
        if(open)
        {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,openRot]);
            llSetTimerEvent(autocloseTime);
        }
        else
        {
            llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_ROT_LOCAL,closedRot]);
            sound(soundClose);
            llSetTimerEvent(0.0);
        }
    }
    else // autoclose time reached
    {
        llSay (0,"Please wait drawbridge is closing");
        llSetTimerEvent(0.0);
        openBridge(!open);
        swinging=steps;
    }    
}    
 
rotation slerp(rotation source,rotation target,float amount)
{
    return llAxisAngle2Rot(llRot2Axis(target/=source),amount*llRot2Angle(target))*source;
}
 
default
{
    state_entry()
    {

        swinging=0;
        open=FALSE;
        omega=TWO_PI/360*openingAngle/openingTime;
        llTargetOmega(ZERO_VECTOR,1.0,1.0);
        bridgeListener = llListen(179,"Zara's Drawbridge",NULL_KEY,"");

    }
 
    touch_start(integer dummy)
    {
        if ((swinging==0)&&(!open))
        {
            go();
            llSay(189, "openBridge");
        } else {
            go2();
            llSay(189, "openBridge");
        }
    }

    listen(integer channel, string name, key id, string message)
    {
        if(message == "openBridge")
        {
            if (!open)
            {
                go();
            }else{
                llSay (0,"Please wait drawbridge is closing");
                go();
            }                
        }
    }

 
    timer()
    {
        go2();
    }
}

Link to comment
Share on other sites

After a quick skim (don't have enough time to get in-world to test), on line 63:

if(world)
    openRot=llGetRot()*llEuler2Rot(<openingAngle,0.0,0.0>*DEG_TO_RAD)/llGetRootRotation();

Your angle of rotation is around the X axis (which points from West to East, meaning that your bridge's "hinge" is either on the North or South side as it rotates.
Changing that to <0, openingAngle, 0> would allow the bridge to rotate the other way.

You could also change it to: <1, 0, 0> * openingAngle * DEG_TO_RAD
Just for future reference if you want to write a new function instead.

Pro-tip: Clarity is your future-you's best friend. Leave some comments explaining why you do things the way you do, and pick more specific names for your functions/variables. I have no idea what the difference between "go" and "go2" is until I follow the cycle of calls and read exactly how the functions are implemented. Trust me, you don't want to come back to a 150-300+ line script after weeks/months and having to re-learn what your thought process was.

Consistent coding-style is also something you should probably work on.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

That's Toy Wylie's Smooth Rotating Door Script, not one that you wrote yourself, so be very careful about putting your own name on it and claiming that it's your work.  It's a rather cleverly designed script, using the smooth rotation of llTargetOmega and stepwise rotations provided by llSetRot (or actually the more sophisticated slerp function).  It also gives you the option of defining rotation around the object's local rotation axis or about the regional axis, by setting the "world" parameter to TRUE or FALSE.  In theory, you ought to be able to use it as is to get the effect you want.  I see, though, that you have changed Wylie's original orientation (rotating around the Z axis) to make the door rotate around the X axis instead.  It looks like it ought to work the way it's been modified, but I'd have to poke at it in world to see whether it actually behaves properly. 

  • Like 1
Link to comment
Share on other sites

Thanks for pointing that out to me Rolig.... I was going to write my own and then found this to work from. I copied this from my own copy not the one inworld which gives Toy credit for it and only shows that I altered it.

Wow, I think you're right about the axis too. So if I'm constructing this properly in my head, somehow now it needs to incorporate all 3 axis, (x,y,z), into the slerp function in order to make it work properly. Or am I only dealing with X and Z? The way I interpret it is that X and Y are always E-W and N-S. So if I offset the Z axis say 45 degrees, then the angle that the X,Y axis are moving changes when open, not just the X axis. I'm not sure how to calculate that in a script.

Link to comment
Share on other sites

Let's start from first principles.

I'm assuming your drawbridge is a regular pathcut prim, with the Beginning Cut 0.125 and the End Cut 0.625, linked as a child prim to a root prim that acts as the "hinge". It would work as well, if not better, in a single mesh object with a suitably offset center axis, of course. 

For the sake of simplicity I'm putting this script in the child prim, the drawbridge, though we could put in the root quite easily.

Anyway, the basic down/up movement is this:


float openingTime=5.0;      // in seconds
float fOpeningAngle = -50.0;    // in degrees


integer iLowered;
rotation rArc;
default{
    state_entry()
    {
        
       fOpeningAngle *= DEG_TO_RAD;
       rArc = llEuler2Rot(<0.0,fOpeningAngle,0.0>);
       llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, ZERO_ROTATION * llGetLocalRot()]);//lower the drawbridge to set the correct open position
       llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, rArc * llGetLocalRot()]);//now raise it
    }

    touch_start(integer num_detected)
    {
        rArc.y *= -1.0;//flip the value of the y axis of the arc through which the drawbridge must rotate
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, rArc * llGetLocalRot()]);
        iLowered =!iLowered;//flip the value of iLowered
    }
}

That's pretty straightforward.  

Now, you want to make it move at a controlled speed, or appear to, by first using llTargetOmega to create the illusion of movement and then actually changing the rotation at the end of the llTargetOmega period .    Again for the sake of simplicity, I'm going to let the whole of llTargetOmega complete and then actually rotate the drawbridge the whole way, but you can easily work out for yourself how to split it up into 5 separate movements if that's what you want, and also add an autocloser.   I just want to demonstrate how the rotations work.   

Notice when I'm using " * llGetLocalRot()", which in English means "use the drawbridge prim's local frame of rotational reference to calculate the rotation"



float openingTime=5.0;      // in seconds
float fOpeningAngle = -50.0;    // in degrees
//float autocloseTime=30.0;   // in seconds
float fSpinRate;
float fY = 1.0;
integer iLowered;
rotation rArc;
default{
    state_entry()
    {
       llTargetOmega(<0.0,0.0,0.0>,0.0,0.0);
       fOpeningAngle *= DEG_TO_RAD;
       fSpinRate = fOpeningAngle/openingTime; //the spinrate in llTargetOmega is how many radians the object should appear to rotate in 1 second.
       rArc = llEuler2Rot(<0.0,fOpeningAngle,0.0>);
       llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, ZERO_ROTATION ]);//lower the drawbridge to set the correct open position
       llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, rArc * llGetLocalRot()]);//now raise it
    }

    touch_start(integer num_detected)
    {
        rArc.y *= -1.0;//flip the value of the y axis of the arc through which the drawbridge must rotate
        fY *= -1.0;
        llTargetOmega(<0.0,fY,0.0> * llGetLocalRot(), fSpinRate, 0.1);//make the drawbrdge appear to move nice and smoothly
        llSetTimerEvent(openingTime);//since we divided fOpeningAngle by openingTime, this should give llTargetOmega time to complete the arc by the time the timer fires
        iLowered =!iLowered;//flip the value of iLowered
    }

    timer()
    {
        llSetTimerEvent(0.0);
        llTargetOmega(<0.0,0.0,0.0>,0.0,0.0);//stop the llTargetOmega
        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_ROT_LOCAL, rArc * llGetLocalRot()]); //and actually rotate the drawbridge so people can cross it or not.
        
    }
}

That's the basics, anyway.   

 

  • Like 1
Link to comment
Share on other sites

   Writing a good door or drawbridge script should probably include a function to reset the script and redefine the position and rotation parameters whenever it is moved. Since position is not an integer returned by the changed event, a timer, periodically checking the current position against the last known position might be needed.

 

Link to comment
Share on other sites

1 hour ago, Ivanova Shostakovich said:

Writing a good door or drawbridge script should probably include a function to reset the script and redefine the position and rotation parameters whenever it is moved.

Why do you need to do that?  If you're rotating the drawbridge (or door) using its own frame of rotational reference, I don't see why you would need to bother.     All the door needs to do is move through n degrees (or radians) between the closed and open positions, switching the direction in which it rotates each time.    I don't see what I need to know the position for and I don't see why I need keep resetting things.    

  • Like 1
Link to comment
Share on other sites

Just to clarify... this isn't a medieval drawbridge that you'd find on a castle. This is a marine drawbridge that you'd find over a river or in the middle of a large lake with a road over it so the ships could get through. It has 2 parts each opening in opposite directions. The bridge itself at this point is sculpted attached to a root prim that provides the script and rotation. When any part of the bridge is touched, it tells the other part of the bridge to open. So essentially it's opening from the middle. I'm working on making all of the parts of my dock system into mesh, but haven't gotten to this part yet.

Wulfie's suggestions didn't work.

Thank you for your input Innula... I'm going to work through what you have here and see if I can make it work. I'm assuming that when you were writing this you had in mind that I was using a medieval drawbridge, but I think the principal is still the same and I can use it to try and make it work.

Link to comment
Share on other sites

As elegant as Toy Wylie's script is, it's not truly necessary to go to such complicated lengths to create a smooth operating drawbridge.  You can get a nice, smooth motion by simply making small incremental rotations.  A script like this would work, for example:

integer intSwing =85;
rotation rotSwing;
vector vOffset;
vector gSize;
vector gClosedPos;
rotation gClosedRot;
integer gOpen;
integer gCount;
integer gLsn;

string Motor = "5a33c730-8f52-a720-052a-5b957904c67a";

Swing()
{
    list l = llGetLinkPrimitiveParams(LINK_THIS,[PRIM_POS_LOCAL,PRIM_ROT_LOCAL]);
    vector v = llList2Vector(l,0);
    rotation r = llList2Rot(l,1);
    llSetLinkPrimitiveParamsFast(LINK_THIS,[PRIM_POS_LOCAL,v+(vOffset-vOffset * rotSwing)*r,
        PRIM_ROT_LOCAL,rotSwing*r]);
}

default
{
    state_entry()
    {
        gLsn = llListen(-39118360,"","","Boat");    // Listen for a prompt from an approaching boat
        gSize = llGetScale();
        if (llGetObjectDesc() != "")  // Look for stored positions and rotations in the object Description
        {
            list temp = llParseString2List(llGetObjectDesc(),["~"],[]);
            gClosedPos = (vector)llList2String(temp,0);
            gClosedRot = (rotation)llList2String(temp,1);
        }
        else    // If they aren't there, put the current ones there
        {
            gClosedPos = llGetPos();
            gClosedRot = llGetRot();
            llSetObjectDesc((string)gClosedPos+"~"+(string)gClosedRot);
        }
        rotSwing = llEuler2Rot(<0.0,(float)intSwing/20.0,0.0>*DEG_TO_RAD);  //85 degrees on the y axis
        list temp = llGetLinkPrimitiveParams(LINK_THIS,[PRIM_SIZE]);
        vector size = llList2Vector(temp,0);
        vOffset = <(size.x*-0.5),0.0,(size.z*-0.5)>;    // Offset to make the drawbridge rotate from its edge rather than its center
    }

    listen(integer channel, string name, key id, string message)
    {
        llListenControl(gLsn,FALSE);    // Turn off the listener so that other vessels will not re-trigger the bridge
        llSetTimerEvent(0.1);   //Prepare to change bridge rotationm every 0.1 seconds
        gCount = 0;
        Swing();
        llTriggerSound(Motor,1.0);
    }
    
    changed (integer change)
    {
        if (change & CHANGED_REGION_START)
        {
            llResetScript();
        }
    }
    
    timer()
    {
        ++gCount;
        if (gCount <= 20)   //Start opening
        {
            Swing();
        }
        else if (gCount == 21)  // Bridge is open.  Reverse sense of direction
        {
            rotSwing.s*=-1;
        }
        else if (gCount == 280)   // Wait for a while and then ...
        {
            llTriggerSound(Motor,1.0);
        }            
        else if (gCount > 280 && gCount < 300)   // Start closing the bridge
        {
            Swing();
        }
        else if (gCount == 300)   // And stop when it is closed
        {
            llSetTimerEvent(0.0);
            gCount = 0;
            rotSwing.s*=-1;    // Reverse sense to prepare for the next cycle
            llSetRegionPos(gClosedPos);    // And make a small final movement to be sure that the bridge is actually in its closed position
            llSetRot(gClosedRot);  //  And rotation
            llListenControl(gLsn,TRUE);
        }            
    }        
}

Like Innula, I don't typically post complete scripts here, but I thought it might be useful to illustrate more than one approach.  You'll find other ideas for scripting doors/drawbridges/hinged lids/etc in the pinned thread at the top of this forum.  You could of course set up a pair of drawbridges, triggered simultaneously by the same signal.

Edited by Rolig Loon
  • Like 2
Link to comment
Share on other sites

Just one last post to update this subject....

Thank you so much @Rolig Loon. I was able to use a variation of your script to make everything work the way it's supposed to no matter the z-axis orientation and I gave you the proper credit in the script for your contributions to it. :)

I've also taken @Wulfie Reanimator suggestions to clarify my intentions within the script by utilizing comments and variable names. Thank you for reminding me to keep things clear.

Thank you to everyone else who posted here.... I'm very grateful for your contributions to this discussion.

Link to comment
Share on other sites

If anyone is interested, I had a go at doing the whole thing from one script in the root, using llSetLinkPPFast.   You might need to play with the the starting values of fOpeningAngle and fY (make them positive or negative) depending on your build, but if you want to make a copy of the demo set-up I made to test it, rez three prims, link them together and then drop this script in (doesn't matter in what order they are linked):

default
{
    state_entry()
    {
        llSetLinkPrimitiveParamsFast(LINK_SET,
        [
            PRIM_LINK_TARGET,1,PRIM_SIZE,<1.0, 1.0, 1.000000>,
            PRIM_ROT_LOCAL,<0.0, 0.0, 0.0, 1.000000>, 
            PRIM_TYPE,0,0,<0.0, 1.0, 0.0>,0.0,<0.0, 0.0, 0.0>,<1.0, 1.0, 0.0>,<0.0, 0.0, 0.0>,
            PRIM_LINK_TARGET,2,PRIM_SIZE,<8.000000, 2.000000, 0.100000>,
            PRIM_POS_LOCAL,<-4.125000, 0.0, 1.000000>,
            PRIM_ROT_LOCAL,<0.0, 0.0, 0.0, 1.000000>, 
            PRIM_TYPE,0,0,<0.125000, 0.625000, 0.0>,0.0,<0.0, 0.0, 0.0>,<1.0, 1.0, 0.0>,<0.0, 0.0, 0.0>,
            PRIM_NAME,"Bridge",
            PRIM_DESC,"Right",
            PRIM_LINK_TARGET,3,PRIM_SIZE,<8.000000, 2.000000, 0.100000>,
            PRIM_POS_LOCAL,<3.875000, 0.0, 1.000000>,
            PRIM_ROT_LOCAL,<0.0, 0.0, 1.0, 0.0>, 
            PRIM_TYPE,0,0,<0.125000, 0.625000, 0.0>,0.0,<0.0, 0.0, 0.0>,<1.0, 1.0, 0.0>,<0.0, 0.0, 0.0>,
            PRIM_NAME,"Bridge",
            PRIM_DESC,"Left"
        ]);
        llRemoveInventory(llGetScriptName());
    }
}

It should transform itself into a very simple marine drawbridge as descripted by @Zara Avindar, in the lowered position. 

Then drop this script in the root.   I made it to work on touch, since it's just a simple demo to show how the rotations work, but it would be easy to convert it to work from listener

integer iLeftBridge;
integer iRightBridge;
integer iMode;
string strLeft = "Left";
string strRight = "Right";

float fAutoCloseTime = 10.0;
float fOpeningTime= 5.0;      // in seconds
float fOpeningAngle = 50.0;    // in degrees
//float autocloseTime=30.0;   // in seconds
float fSpinRate;
float fY = 1.0;
integer iOpen;
rotation rArc;
rotation rLeftClosed;
rotation rRightClosed;
rotation rLeftLocal;
rotation rRightLocal;
findPrims(){//identify the two drawbridge prims
    integer counter = 2;
    integer max = llGetNumberOfPrims() + 1;
    do{
        list temp = llGetLinkPrimitiveParams(counter, [PRIM_DESC, PRIM_ROT_LOCAL]);//Examine the link description of each child prim and record the relevant link numbers and rotation in start position (bridge lowered) 
        string str = llList2String(temp, 0);
        rotation rot = llList2Rot(temp,1);
        if(strLeft == str){
            iLeftBridge = counter;
            rLeftClosed = rot;
        }
        else if (strRight == str){
            iRightBridge = counter;
            rRightClosed = rot;
        }
    }
    while (++counter < max);
}

default
{
    state_entry()
    {
        findPrims();
        llTargetOmega(<0.0,0.0,0.0>,0.0,0.0);
        fOpeningAngle *= DEG_TO_RAD;
        fSpinRate = fOpeningAngle/fOpeningTime; //the spinrate in llTargetOmega is how many radians the object should appear to rotate in 1 second.
        rArc = llEuler2Rot(<0.0,fOpeningAngle,0.0>);
    }

    touch_start(integer num_detected)
    {
        if(!iOpen){ //only respond to touches if the bridge is down
            iOpen = TRUE;
            iMode = 0;
            rLeftLocal = llList2Rot(llGetLinkPrimitiveParams(iLeftBridge,[PRIM_ROT_LOCAL]),0);//equivalent to calling llGetLocalRot in the prim itself
            rRightLocal = llList2Rot(llGetLinkPrimitiveParams(iRightBridge,[PRIM_ROT_LOCAL]),0);//equivalent to calling llGetLocalRot in the prim itself
            rArc.y *= -1.0;//flip the value of the y axis of the arc through which the drawbridge must rotate
            fY *= -1.0;
            llSetTimerEvent(fOpeningTime);
            llSetLinkPrimitiveParamsFast(LINK_SET, [
            PRIM_LINK_TARGET,iLeftBridge,PRIM_OMEGA,<0.0,fY,0.0> * rLeftLocal, fSpinRate, 0.1,
            PRIM_LINK_TARGET,iRightBridge,PRIM_OMEGA,<0.0,fY,0.0> * rRightLocal, fSpinRate, 0.1
                ]); 
        }
    }

    changed(integer change)
    {
        if(change & CHANGED_LINK){
            llResetScript();//in order to re-check the numbering
        }
    }

    timer()
    {
  //  llOwnerSay("iMode is "+(string)iMode);
       llSetLinkPrimitiveParamsFast(LINK_SET, [PRIM_OMEGA, <0.0,0.0,0.0>,0.0,0.0]);
       if(0==iMode){
            llSetLinkPrimitiveParamsFast(LINK_SET, [
            PRIM_LINK_TARGET,iLeftBridge, PRIM_ROT_LOCAL, rArc * rLeftLocal,
            PRIM_LINK_TARGET,iRightBridge,PRIM_ROT_LOCAL,rArc * rRightLocal
           ]);//now raise it
            rLeftLocal = llList2Rot(llGetLinkPrimitiveParams(iLeftBridge,[PRIM_ROT_LOCAL]),0);//equivalent to calling llGetLocalRot in the prim itself
            rRightLocal = llList2Rot(llGetLinkPrimitiveParams(iRightBridge,[PRIM_ROT_LOCAL]),0);//equivalent to calling llGetLocalRot in the prim itself
            rArc.y *= -1.0;//flip the value of the y axis of the arc through which the drawbridge must rotate, ready to close it
            fY *= -1.0;
            llSetTimerEvent(fAutoCloseTime);
            ++iMode;
       }
       else if (1==iMode){//start target omega to make the bridge seem to lower
                llSetLinkPrimitiveParamsFast(LINK_SET, [
                PRIM_LINK_TARGET,iLeftBridge,PRIM_OMEGA,<0.0,fY,0.0> * rLeftLocal, fSpinRate, 0.1,
                PRIM_LINK_TARGET,iRightBridge,PRIM_OMEGA,<0.0,fY,0.0> * rRightLocal, fSpinRate, 0.1
                    ]);
                llSetTimerEvent(fOpeningTime);
                ++iMode;
       }
       else if (2 == iMode){
            llSetLinkPrimitiveParamsFast(LINK_SET, [
            PRIM_LINK_TARGET,iLeftBridge, PRIM_ROT_LOCAL, rArc * rLeftLocal,
            PRIM_LINK_TARGET,iRightBridge,PRIM_ROT_LOCAL,rArc * rRightLocal
           ]);//now actually lower it
            llSetTimerEvent(0.0);
            iMode = 0;
            iOpen = FALSE;
       }

    }
}

 

 

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

I left a simple bridge mockup out for one hour, and it seemed to work fine, using the above script. However, a person sitting on the bridge for a few minutes broke it.

I believe it happened because someone opened the bridge while another was sitting, and the bridge ended up stuck in the open position. Upon being clicked again, it opened further, and "closed" in the open position.

So, when people break this bridge, is there a way of fixing it that does not involve right-click, Edit Linked, rotate? Or, is there a way to prevent the breakage in the first place?

Link to comment
Share on other sites

40 minutes ago, PheebyKatz said:

I left a simple bridge mockup out for one hour, and it seemed to work fine, using the above script. However, a person sitting on the bridge for a few minutes broke it.

I believe it happened because someone opened the bridge while another was sitting, and the bridge ended up stuck in the open position. Upon being clicked again, it opened further, and "closed" in the open position.

So, when people break this bridge, is there a way of fixing it that does not involve right-click, Edit Linked, rotate? Or, is there a way to prevent the breakage in the first place?

Assuming you are using Innula's script from a couple posts up, there are many ways to work around that. The simplest way is to remove the changed() event entirely, and manually reset the script if you ever make adjustments to the bridge (which is probably not very often, so it should not be a huge issue).

Other ways could be checking (in the changed() event) if an avatar sat on the object and keeping track of that, but it doesn't have anything to do with the rest of the script and it has its own edge-cases you'd also have to work around. In short, it's going to be confusing to figure out later on or by someone else and I wouldn't recommend it.

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

Yes, taking out the changed event would be simplest.   That or settingPRIM_SCRIPTED_SIT_ONLY. 

Alternatively, if you want to keep the changed event in, and to be able to sit on it when the bridge is down, you could try testing to see if anyone's sitting on it before it starts to open (and either unsitting them or refuse to open until they stand up) and then set PRIM_SCRIPTED_SIT_ONLY to TRUE while it's opening and closing and then back to FALSE when it's back in the closed position.

 

Link to comment
Share on other sites

Another issue, provided I continue using this script or any part of it, is that anyone or anything unfortunate enough to be on the bridge when it begins to open tends to fall through, and anything trying to pass under, such as a ship, tends to get knocked about by the changes in physics. I'll probably have to figure out my own way of doing this, it's okay though, I'm getting used to having to do that lately.

Everything I've ever used any of the rotation or door scripts, etc., from this forum in has ended up broken somehow, usually through the simplest of normal circumstances, and I'm just kind of tired of having to manually edit things back into place. I'll probably just use toggling of alphas and physics and sacrifice the extra LI, like I've had to do with everything else.

Cool effect, but just not practical when all the drawbacks kick in.

Thanks for the effort, anyway.

@Wulfie Reanimator you can save yourself some time and effort in typing, as the Ignore List prevents me from seeing your content now. I took your advice about bad eggs after the name-calling last night. Thanks~

Edited by PheebyKatz
  • Sad 1
Link to comment
Share on other sites

4 hours ago, PheebyKatz said:

Another issue, provided I continue using this script or any part of it, is that anyone or anything unfortunate enough to be on the bridge when it begins to open tends to fall

That shouldn't be happening, since the script doesn't change the bridge's actual rotation until llTargetOmega has completed.   So if you try walking across the bridge while it's opening, then you'll be able to -- though you'll appear to be walking on thin air -- right up until the moment it stops moving and the llSetRot kicks in.    So I don't know how  you managed to fall through it.

You could only fall through it, as far as I can see, if you started trying to cross it before it was fully closed.

I did say it was a proof of concept, to demonstrate how to open and close the bridge from a single script, rather than a finished piece.    Generally, if I want to post something that I've written and tested as a full script, I put it in the Script Library, not here.   Anything here, as far as I'm concerned, is more like something written on a chalkboard  -- it's an example that I hope is correct but I haven't tested it as fully as I would for something I was posting in the Script Library (or selling, of course).

If you're worried about your bridge, it's easy enough to rotate the bridge incrementally as it's opening and closing -- see 

 

Link to comment
Share on other sites

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