Jump to content

car door not opening properly


arnellou
 Share

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

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

Recommended Posts

Hello everyone, I have a question about my car door script. The door is not opening properly as it rotates 90 degrees and its pivot point or hinge is in the middle. I tried adjusting the x-axis of the vector open_position variable, but it seems to adjust its position first and then perform the rotation.. Please see the video here.

Could someone please suggest a solution to fix the pivot/hinge and other issues? Any advice or tips would be greatly appreciated. 

Thank you in advance for your help.

 

// config
vector close_position = <-0.570, 0.190, 1.865>;
rotation close_rotation = <0.0, 0.90, 0.0, -1.0>;

vector open_position = <-0.770, 0.190, 1.865>;
rotation open_rotation = <0.00, 0.00, 0.00, 0.00>;

key close_sound = "876d3492-b8b8-7745-f5ae-dc5176ec6105";
key open_sound = "9a076511-9aa8-f50d-e34c-1396a07a66a9";
key lock_sound = "37e8d62e-ba8a-3faf-49cc-7cb9267686da";
key unlock_sound = "37e8d62e-ba8a-3faf-49cc-7cb9267686da";
key chime_sound = "b2aa9559-4e32-8321-09f8-86572fd5bc00";

float close_volume = 1.0;
float open_volume = 1.0;
float lock_volume = 0.5;
float unlock_volume = 0.5;
float chime_volume = 0.5;

integer channel = 0;
integer auto_close = 0;
float movement_time = 1.0;
integer preload_sounds = FALSE;
integer sit_check = FALSE;
list whitelist = [""];

string link_name = "";
vector link_close_position = <0.00000, 0.00000, 0.00000>;
rotation link_close_rotation = <0.00000, 0.00000, 0.00000, 0.00000>;
vector link_open_position = <0.00000, 0.00000, 0.00000>;
rotation link_open_rotation = <0.00000, 0.00000, 0.00000, 0.00000>;
//

integer close_open;
integer handle;
integer link;
vector link_time_position;
rotation link_time_rotation;
integer locked;
integer sitting;
float time;
vector time_position;
rotation time_rotation;

// http://wiki.secondlife.com/wiki/Interpolation/Linear/Vector
vector vLin(vector x, vector y, float t){
    return x*(1-t) + y*t;
}

// http://wiki.secondlife.com/wiki/Slerp
rotation slerp( rotation a, rotation b, float t ) {
   return llAxisAngle2Rot( llRot2Axis(b /= a), t * llRot2Angle(b)) * a;
}

close_or_open()
{
    if(llGetLinkNumber() < 2)
        return;

    if(llGetLocalPos() != close_position)
    {
        llStopSound();

        llResetTime();

        while(llGetTime() < movement_time)
        {
            time = llGetTime() / movement_time;

            time_position = vLin(open_position, close_position, time);
            time_rotation = slerp(open_rotation, close_rotation, time);

            if(link != 0)
            {
                link_time_position = vLin(link_open_position, link_close_position, time);
                link_time_rotation = slerp(link_open_rotation, link_close_rotation, time);
            }

            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POS_LOCAL, time_position, PRIM_ROT_LOCAL, time_rotation]);

            if(link != 0)
                llSetLinkPrimitiveParamsFast(link, [PRIM_POS_LOCAL, link_time_position, PRIM_ROT_LOCAL, link_time_rotation]);
        }

        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POS_LOCAL, close_position, PRIM_ROT_LOCAL, close_rotation]);

        if(link != 0)
            llSetLinkPrimitiveParamsFast(link, [PRIM_POS_LOCAL, link_close_position, PRIM_ROT_LOCAL, link_close_rotation]);

        if(close_sound != "")
            llTriggerSound(close_sound, close_volume);
    }
    else
    {
        if(open_sound != "")
            llTriggerSound(open_sound, open_volume);

        llResetTime();

        while(llGetTime() < movement_time)
        {
            time = llGetTime() / movement_time;

            time_position = vLin(close_position, open_position, time);
            time_rotation = slerp(close_rotation, open_rotation, time);

            if(link != 0)
            {
                link_time_position = vLin(link_close_position, link_open_position, time);
                link_time_rotation = slerp(link_close_rotation, link_open_rotation, time);
            }

            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POS_LOCAL, time_position, PRIM_ROT_LOCAL, time_rotation]);

            if(link != 0)
                llSetLinkPrimitiveParamsFast(link, [PRIM_POS_LOCAL, link_time_position, PRIM_ROT_LOCAL, link_time_rotation]);
        }

        llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_POS_LOCAL, open_position, PRIM_ROT_LOCAL, open_rotation]);

        if(link != 0)
            llSetLinkPrimitiveParamsFast(link, [PRIM_POS_LOCAL, link_open_position, PRIM_ROT_LOCAL, link_open_rotation]);

        if(auto_close != 0)
            llSetTimerEvent(auto_close);

        if(chime_sound != "")
            llLoopSound(chime_sound, chime_volume);
    }
}

find_link()
{
    integer prims = llGetNumberOfPrims();
    integer index;

    while(prims--)
    {
        string name = llGetLinkName(index);

        if(name == link_name)
            link = index;

        index++;
    }
}

default
{
    state_entry()
    {
        llSetMemoryLimit(llGetUsedMemory() + 1024);

        handle = llListen(channel, "", llGetOwner(), "");

        find_link();

        if(preload_sounds == TRUE)
        {
            if(close_sound != "")
                llPreloadSound(close_sound);
            if(open_sound != "")
                llPreloadSound(open_sound);
            if(lock_sound != "")
                llPreloadSound(lock_sound);
            if(unlock_sound != "")
                llPreloadSound(unlock_sound);
            if(chime_sound != "")
                llPreloadSound(chime_sound);
        }
    }

    on_rez(integer start_param)
    {
        llResetScript();
    }

    touch_start(integer total_number)
    {
        key id = llDetectedKey(0);
        string name = llGetUsername(id);

        if(id == llGetOwner())
        {
            close_or_open();

            return;
        }

        if(locked == FALSE)
            close_or_open();
        else if(locked == TRUE)
        {
            integer find = llListFindList(whitelist, [name]);

            if(find != -1)
                close_or_open();
        }
    }

    timer()
    {
        llSetTimerEvent(0.0);

        if(llGetLocalPos() != close_position)
            close_or_open();
    }

    listen(integer channel, string name, key id, string message)
    {
        if(sit_check == TRUE)
            if(sitting == FALSE)
                return;

        message = llToLower(message);

        if(message == "close")
            if(llGetLocalPos() != close_position)
                close_or_open();

        if(message == "open")
            if(llGetLocalPos() != open_position)
                close_or_open();

        if(message == "unlock")
        {
            locked = FALSE;
            llTriggerSound(unlock_sound, unlock_volume);
        }
        if(message == "lock")
        {
            locked = TRUE;
            llTriggerSound(lock_sound, lock_volume);
        }
    }

    changed(integer change)
    {
        if(change & CHANGED_LINK)
        {
            find_link();

            key av = llAvatarOnLinkSitTarget(LINK_ROOT);

            if(av == llGetOwner())
                if(av)
                    sitting = TRUE;
                else
                    sitting = FALSE;
        }
    }
}

 

 

Edited by arnellou
added sourcecode
Link to comment
Share on other sites

This is a common problem with slow-rotating door scripts. I have tried several of the standard approaches myself. The best way to beat it is to redesign the mesh for the door, frankly.  If the mesh is designed with its hinge point at the visual edge of the door, you don't have to go through the business of adjusting both the local position and the local rotation at every time step.

Link to comment
Share on other sites

Try using LlSetPrimitiveParams instead of LlSetPrimitiveParamsFast. You have an inner loop with no delays issuing commands with no rate limit. The system doesn't like that. It tends to result in out of order or dropped updates, or your script being throttled. LlSetPrimitiveParamsFast means "don't wait for completion". Here, you want these updates to happen at a fixed rate. LlSetPrimitiveParams has a 200ms delay, which is reasonable here.

Link to comment
Share on other sites

15 hours ago, SeanMcDonald said:

When building with prims, a trick I've used is to create a hinge prim, link it to the door, then rotate the hinge.

That only works for standalone prims not attached to something else. You can do that for a house, but not a car.

The permanent solution is a real hierarchy, where child prims can have children of their own. See this JIRA. LL gradually seems to be coming around to that, partly because they want to go with glTF import, and glTF assumes there's a hierarchy. Rosedale has said that not having a general prim hierarchy was his biggest design mistake.

There's been discussion of adding pivot points to prims, but it turns out that a full hierarchy is easier to implement, because the viewers already understand a hierarchy.

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
On 4/8/2023 at 12:23 AM, animats said:

That only works for standalone prims not attached to something else. You can do that for a house, but not a car.

Maybe I have a strange case, then.  It's a pair of scripts, but it works well enough for a vehicle I built several years ago.

The door script:

/*
 * Smooth Rotating Linked Door With Hinge
 *
 * By: Lyn Mimistrobell
 * Version: 1.1
 * License: Do whatever you like with it, just don't blame me if you break it :)
 */
 
/*
 * Define the rotation in degrees, using the door prim's local coordinate
 * system
 */
vector      ROTATION            = <122.0, 0.0, 0.0>;
 
/*
 * Define the position of the virtual hinge; usually this is half the door
 * prim's width and thickness
 */
vector      HINGE_POSITION      = <0.0, 0.05, -1.425>;
 
/*
 * Define how fast the door opens, in seconds
 */
float       SECONDS_TO_ROTATE   = 1.0;
 
/*
 * Define after how much time the door should close automatically, in seconds;
 * set to 0.0 to disable autolmatic closing
 */
float       AUTO_CLOSE_TIME     = 10.0;
 
/*
 * Define a sound that plays when the door starts to open; set to NULL_KEY
 * for no sound.
 */
key         SOUND_ON_OPEN       = "e5e01091-9c1f-4f8c-8486-46d560ff664f";
 
/*
 * Define a sound that plays when the door has closed; set to NULL_KEY
 * for no sound.
 */
key         SOUND_ON_CLOSE      = "88d13f1f-85a8-49da-99f7-6fa2781b2229";
 
/*
 * Define the volume of the opening and closing sounds
 */
float       SOUND_VOLUME        = 1.0;
 
/*
 * NORMALLY, THERE IS NO NEED TO CHANGE ANYTHING BELOW THIS COMMENT. IF YOU DO
 * YOU RISK BREAKING IT.
 */
 
integer     gClosed;            // Door state: TRUE = closed, FALSE = opened
rotation    gRotationClosed;    // Initial rotation of the door (closed)
vector      gPositionClosed;    // Initial position of the door (closed)
vector      gRotationPerSecond; // The amount to rotate each second
 
doOpenOrClose() {
    /*
     * Only perform the rotation if the door isn't root or unlinked
     */
    integer linkNumber = llGetLinkNumber();
    if (linkNumber < 2)
        return;
 
    if (gClosed) {
        /*
         * Store the initial rotation and position so we can return to it.
         *
         * Rotating back purely by calculations can in the longer term cause the door
         * to be positioned incorrectly because of precision errors
         *
         * We determine this everytime before the door is being opened in case it was
         * moved, assuming the door was closed whilst being manipulated.
         */
        gPositionClosed = llGetLocalPos();
        gRotationClosed = llGetLocalRot();
 
        /*
         * Play the opening sound and preload the closing sound
         */
        if (SOUND_ON_OPEN)
            llPlaySound(SOUND_ON_OPEN, SOUND_VOLUME);
    }
 
    vector hingePosition = gPositionClosed + HINGE_POSITION * gRotationClosed;
 
    /*
     * Reset the timer and start moving
     */
    llResetTime();
    while (llGetTime() < SECONDS_TO_ROTATE) {
        float time = llGetTime();
        if (! gClosed)
            /*
             * Invert the timer for closing direction
             */
            time = SECONDS_TO_ROTATE - time;
 
        rotation rotationThisStep = llEuler2Rot(gRotationPerSecond * time) * gRotationClosed;
        vector positionThisStep = hingePosition - HINGE_POSITION * rotationThisStep;
        llSetLinkPrimitiveParamsFast(linkNumber, [PRIM_ROT_LOCAL, rotationThisStep, PRIM_POS_LOCAL, positionThisStep]);
    }
 
    /*
     * Set the new state
     */
    gClosed = !gClosed;
 
    if (gClosed) {
        /*
         * Finalize the closing movement
         */
        llSetLinkPrimitiveParamsFast(linkNumber, [PRIM_ROT_LOCAL, gRotationClosed, PRIM_POS_LOCAL, gPositionClosed]);
 
        /*
         * Play the closing sound and preload the opening sound
         */
        if (SOUND_ON_CLOSE)
            llPlaySound(SOUND_ON_CLOSE, SOUND_VOLUME);
        if (SOUND_ON_OPEN)
            llPreloadSound(SOUND_ON_OPEN);
    } else {
        /*
         * Finalize the opening movement
         */
        rotation rotationOpened = llEuler2Rot(ROTATION * DEG_TO_RAD) * gRotationClosed;
        vector positionOpened = hingePosition - HINGE_POSITION * rotationOpened;
        llSetLinkPrimitiveParamsFast(linkNumber, [PRIM_ROT_LOCAL, rotationOpened, PRIM_POS_LOCAL, positionOpened]);
 
        /*
         * Preload the closing sound
         */
        if (SOUND_ON_CLOSE)
            llPreloadSound(SOUND_ON_CLOSE);
 
        /*
         * Set a timer to automatically close
         */
        llSetTimerEvent(AUTO_CLOSE_TIME);
    }
}
 
default {
    state_entry() {
        /*
         * Assume the door is closed when the script is reset
         */
        gClosed = TRUE;
 
        /*
         * These doesn't change unless the script is changed, calculate them once
         */
        gRotationPerSecond = (ROTATION * DEG_TO_RAD / SECONDS_TO_ROTATE);
 
        /*
         * Preload the opening sound
         */
        if (SOUND_ON_OPEN)
            llPreloadSound(SOUND_ON_OPEN);
    }
    touch_start(integer agentCount) {
        doOpenOrClose();
    }
    timer() {
        llSetTimerEvent(0.0);
 
        /*
         * Close the door if it isn't already closed
         */
        if (! gClosed)
            doOpenOrClose();
    }
}

And the hinge script:

default //initially closed
{
  touch_start(integer num_detected) { state open; }
}

state open
{
  state_entry()
  {
    rotation r1 = llEuler2Rot(<122.5,0.0,0.0> * DEG_TO_RAD);
    llSetRot(r1 * llGetRot());    
  }
  touch_start(integer num_detected) { state closed; } 
} 

state closed 
{              
  state_entry()     
  {      
    rotation r2 = llEuler2Rot(<-122.5,0.0,0.0> * DEG_TO_RAD);      
    llSetRot(r2 * llGetRot());    
  }                
  touch_start(integer num_detected) { state open; } 
}

If I were guessing, I'd say that this likely came my way from the Outworldz.com site.  It only uses LSL functions, though, so it should work in SL as well as OS.

Link to comment
Share on other sites

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