Jump to content

Is it possible to drive the rotation of a child object, without effecting the root, if the whole object is physical?


CatgirlKat149
 Share

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

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

Recommended Posts

Hello! I'm fairly new to scripting in SL and am currently working on a flying airship-type vehicle using modifiable pre-existing scripts. Part of the plan was to have turrets that are rooted to the ship itself that move with the camera movement of a user, not necessarily the driver. The issue I am having is this: The turret script works properly to rotate the child (which houses the script) when linked with the root, as long as it is not physical. If the object becomes physical, as is the case with the airship when it is flying, the turret script then rotates the whole object (both root and children). I would only like the child object to rotate based on camera movement, even if the entire object is physical. 

The turret script allows an object to be rotated through the same rotation as the person who clicked the object's camera.

The airship's script turns the airship physical during flight

Turret Script:

key toucher;
string toucherS;
float SPEED         = 40.0;         
integer LIFETIME    = 7;            
float DELAY         = 0.2;          
vector vel;                          
vector pos;                         
rotation rot;                       
integer in_use;
integer have_permissions = FALSE;   
integer armed = TRUE;               
fire()
{
    
        rot = llGetRot();               
        vel = llRot2Fwd(rot);           
        pos = llGetPos();               
        pos = pos + vel;                
        pos.z += 0.0;                   
        vel = vel * SPEED;              
        llTriggerSound("shoot", 1.0);
        llRezObject("bullet", pos, vel, rot, 1); 
}
default
{
    state_entry()
    {
       in_use = FALSE;        
    }
    touch_start(integer total_number)
    {
        if(in_use == FALSE)
        {
            toucher = llDetectedKey(0);
            llRequestPermissions(toucher, PERMISSION_TAKE_CONTROLS|PERMISSION_TRIGGER_ANIMATION);   
            llSetText("Requesting Permissions", <1,1,1>, 1); 
        }
        if(in_use == TRUE) 
        {
            if(llDetectedKey(0) == toucher)
            {
            llReleaseControls();
            llSensorRemove();
            llSetRot(<-0.00000, -0.00000, 0.70711, 0.70711>);
            llSetText("", <1,1,1>, 1); 
            in_use = FALSE;
            }
        }              
    }
    sensor(integer sense)
    {
        rotation k = llDetectedRot(0);
        llRotLookAt(k, .1, .1);
    }
    no_sensor()
    {
        llReleaseControls();
        llSensorRemove();
        llSetRot(<-0.00000, -0.00000, 0.70711, 0.70711>);
        llSetText("", <1,1,1>, 1); 
        in_use = FALSE;
    }
    run_time_permissions(integer perm)
    {
        if(perm)
        {
            llSetText("", <1,1,1>, 1);
            llTakeControls(CONTROL_ML_LBUTTON, TRUE, FALSE);
            llSensorRepeat("", toucher, AGENT, 20, TWO_PI, .1);
            llSetText("Current User: "+llKey2Name(toucher), <1,1,1>, 1);
            in_use = TRUE;
        }
        else
        {
            in_use = FALSE;
            llSetText("", <1,3,1>, 1);
        }
    }
    control(key name, integer levels, integer edges) 
    {
        if ((levels & CONTROL_ML_LBUTTON) == CONTROL_ML_LBUTTON) 
        {
            fire();
        }
    }
    
}
    
// END //

Airship Script:

// SoloFlight
// by Solo Mornington

// This script is based on the HC-1 flight script by illume Skallagrimson
// but VERY HEAVILY MODIFIED. :-)

// we only have a position for the sit target, no rotation. it is assumed that
// this script is in the root prim of a zero-rotation object.
vector gSitTarget = <2.01, 0.002, 9.005>;
string gSitText = "Fly away"; // Text to show in the pie menu for sitting

string gAnimationName; // this will be the first animation in inventory
string gLoopSound = "tugboat"; // the sound to loop during flying.
key gPilot = NULL_KEY; // who's flying? (distinct from passengers)

// these are values for the vehicle motors
// they'd more properly be state-scope variable for state flying.
//  https://jira.secondlife.com/browse/SVC-3297
vector linear;
vector angular;
float water_offset = 1.6;

// Defining the Parameters of the normal driving camera.
// This will let us follow behind with a loose camera.
list gDriveCam =[
        CAMERA_ACTIVE, TRUE,
        CAMERA_BEHINDNESS_ANGLE, 0.0,
        CAMERA_BEHINDNESS_LAG, 0.5,
        CAMERA_DISTANCE, 2.0,
        CAMERA_PITCH, 05.0,
        CAMERA_FOCUS_LAG, 0.05,
        CAMERA_FOCUS_LOCKED, FALSE,
        CAMERA_FOCUS_THRESHOLD, 0.0,
        CAMERA_POSITION_LAG, 0.5,
        CAMERA_POSITION_LOCKED, FALSE,
        CAMERA_POSITION_THRESHOLD, 0.0,
        CAMERA_FOCUS_OFFSET, <0,0,0>];

// lists of which prims are legs and wings, so we can do special effects
list gWingPrims;
list gLegPrims;

setVehicle()
{
    llCollisionSound("", 0.0);
    llSetVehicleType(VEHICLE_TYPE_AIRPLANE);
    // linear friction
    llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <100.0, 100.0, 100.0>);
    // uniform angular friction
    llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1.0);
    // linear motor
    llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>);
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, .5);
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 1.0);
    // angular motor
    llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <0.0, 0.0, 0.0>);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, .4);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 2.0);
    // hover
    llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 0.0);
    llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0);
    llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0);
    llSetVehicleFloatParam(VEHICLE_BUOYANCY, 1.0);
    // linear deflection
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0.5);
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.0);
    // angular deflection
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.25);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 100.0);
    // vertical attractor
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.75);
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.0);
    // banking
    llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 0.0);
    llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 1.0);
    llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 360.0);
    // default rotation of local frame
    llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.0, 0.0, 0.0, 1.0>);
    // removed vehicle flags
    llRemoveVehicleFlags(VEHICLE_FLAG_NO_DEFLECTION_UP
                        | VEHICLE_FLAG_HOVER_WATER_ONLY
                        | VEHICLE_FLAG_HOVER_TERRAIN_ONLY
                        | VEHICLE_FLAG_HOVER_UP_ONLY
                        | VEHICLE_FLAG_LIMIT_MOTOR_UP
                        | VEHICLE_FLAG_LIMIT_ROLL_ONLY);
    // set vehicle flags
    llSetVehicleFlags(VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT);
}

loadLegAndWingPrims()
{
    gWingPrims = [];
    gLegPrims = [];
    integer i;
    list params;
    // use llGetObjectPrimCount() so we don't include seated avatars.
    integer count = llGetObjectPrimCount(llGetKey());
    for (i=1; i<=count; ++i)
    {
        params = llGetLinkPrimitiveParams(i, [PRIM_DESC]);
        string desc = llList2String(params, 0);
        if (desc == "leg") gLegPrims += [i];
        if (desc == "wing") gWingPrims += [i];
    }
}

newAnimationCheck()
{
    // we might have a new animation in inventory
    // and if we do, stop the old one and play the new one.
    if (gPilot != NULL_KEY)
    {
        llStopAnimation(gAnimationName);
        gAnimationName = llGetInventoryName(INVENTORY_ANIMATION, 0);
        llStartAnimation(gAnimationName);
        return;
    }
    gAnimationName = llGetInventoryName(INVENTORY_ANIMATION, 0);
}

primAlpha(list prims, float alpha)
{
    // set prims to be transparent
    integer i;
    integer count = llGetListLength(prims);
    for (i=0; i<count; ++i)
    {
        llSetLinkAlpha(llList2Integer(prims, i), alpha, ALL_SIDES);
    }
}

wingFlapAlpha()
{
    integer i;
    integer count = llGetListLength(gWingPrims);
    for (i=0; i<count; ++i)
    {
        if (llFrand(1.0) > 0.5)
            llSetLinkAlpha(llList2Integer(gWingPrims, i), 0.7, ALL_SIDES);
        else
            llSetLinkAlpha(llList2Integer(gWingPrims, i), 0.3, ALL_SIDES);
    }
}

default
{
    state_entry()
    {
        // load up the exception prims
        loadLegAndWingPrims();
        // some basic initializations
        gPilot = NULL_KEY;
        newAnimationCheck();
        llSitTarget(gSitTarget, ZERO_ROTATION);
        llSetSitText(gSitText);
        state atRest;
    }
}

state atRest
{
    // state atRest is the state we should be in when the vehicle is at rest
    // just sitting there, as in we just rezzed it, or the avatar stood up from it.
    // mainly this state is responsible for starting the flying sequence when
    // the owner sits on the vehicle.
    state_entry()
    {

        // nobody flying the thing...
        gPilot = NULL_KEY;
        // hide the wings and show the legs
        primAlpha(gWingPrims, 0.0);
        primAlpha(gLegPrims, 1.0);
        // turn off vehicle stuff.
        llSetStatus(STATUS_PHYSICS, FALSE);
        // TODO: make the vehicle right itself.
        // let the whole object know we're at rest.

    }

    changed(integer what)
    {
        // Whenever an av sits on or stands up from an object, it is treated as if it
        // were being linked or unlinked.
        // Unfortunately, there are a whole bunch of other things that cause CHANGED_LINK
        // as well, so we have to allow for them.
        // Things that can cause CHANGED_LINK: 1) linking in new prims, 2) unlinking prims
        // 3) avatars sitting, 4) avatars unsitting
        if (what & CHANGED_LINK)
        {
            // are there *any* seated avatars?
            if (llGetNumberOfPrims() != llGetObjectPrimCount(llGetKey()))
            {
               // we have seated avs, so let's find the sit target one
            key agent = llAvatarOnSitTarget();
            if(llSameGroup(agent))
            {
                    gPilot = agent;
                    // ask politely for permission do to stuff.
                    // These will be automatically granted.
                    llRequestPermissions(agent,PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_TRACK_CAMERA | PERMISSION_CONTROL_CAMERA);
                }
                if(llSameGroup(agent) != TRUE)
                // sit target agent is not the owner
                {
                    llUnSit(agent);
                    llWhisper(0,"Only the Kumiho Family can drive this vehicle.");
                }
            }
            else
            // there are no seated avatars...
            {
                if (gPilot != NULL_KEY)
                {
                    // since there are no seated avs, but we still know about
                    // the pilot, they must have just stood up.
                    // we need to release controls and do other cleanup
                    llSetTimerEvent(0);
                    llReleaseControls();
                    llClearCameraParams();
                    llStopLookAt();
                    llStopAnimation(gAnimationName);
                    gPilot = NULL_KEY;
                    llMessageLinked(LINK_ALL_OTHERS, 0, "stop", NULL_KEY);
                }
            }
        }
        if (what & CHANGED_INVENTORY)
        {
            // someone might have dropped in a new animation
            newAnimationCheck();
        }
    }

    run_time_permissions(integer perm)
    {
        // to be correct, we really should check the perms and make sure we
        // got the ones we need. but this will usually work:
        if (perm) state flying;
    }

    on_rez(integer foo) { state default; }
}

state flying
{
    // state flying assumes we have permission to take controls, run animations,
    // and control the camera.
    state_entry()
    {
        // hide the legs, show the wings...
        primAlpha(gLegPrims, 0.0);
        wingFlapAlpha();
        // play the flying sound
        llLoopSound(gLoopSound, 1.0);
        llSetTimerEvent(0.05);
        llTakeControls( CONTROL_FWD |
            CONTROL_BACK |
            CONTROL_LEFT |
            CONTROL_RIGHT |
            CONTROL_ROT_LEFT |
            CONTROL_ROT_RIGHT |
            CONTROL_UP |
            CONTROL_DOWN |
            CONTROL_LBUTTON |
            CONTROL_ML_LBUTTON,
            TRUE, FALSE);
        setVehicle();
        llSetCameraParams(gDriveCam);
        llStartAnimation(gAnimationName);
        vector current_pos = llGetPos();
        llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, current_pos.z);
        llSetStatus(STATUS_PHYSICS, TRUE);
        // let the rest of the object know we're flying
        llMessageLinked(LINK_ALL_OTHERS, 0, "flying", NULL_KEY);
    }

    changed(integer what)
    {
        // Whenever an av sits on or stands up from an object, it is treated as if it
        // were being linked or unlinked.
        // Unfortunately, there are a whole bunch of other things that cause CHANGED_LINK
        // as well, so we have to allow for them.
        // Things that can cause CHANGED_LINK: 1) linking in new prims, 2) unlinking prims
        // 3) avatars sitting, 4) avatars unsitting
        if (what & CHANGED_LINK)
        {
            // are there *any* seated avatars?
            if (llGetNumberOfPrims() == llGetObjectPrimCount(llGetKey()))
            {
                // there are no seated avatars...
                if (gPilot != NULL_KEY)
                {
                    // since there are no seated avs, but we still know about
                    // the pilot, they must have just stood up, so let's rest.
                    state atRest;
                }
            }
        }
        if (what & CHANGED_INVENTORY)
        {
            newAnimationCheck();
        }
    }

    // The control event is what we get when the user mashed down the keys
    // we asked about in llTakeControls().
    control(key id, integer levels, integer edges)
    {
        if(llGetStatus(STATUS_PHYSICS)!=TRUE)
            llSetStatus(STATUS_PHYSICS, TRUE);

        if ((edges & levels & CONTROL_UP)) {
            linear.z += 12.0;
        } else if ((edges & ~levels & CONTROL_UP)) {
            linear.z -= 12.0;}
        if ((edges & levels & CONTROL_DOWN)) {
            linear.z -= 12.0;
        } else if ((edges & ~levels & CONTROL_DOWN)) {
            linear.z += 12.0;}
        if ((edges & levels & CONTROL_FWD)) {
            linear.x += 14.0;
        } else if ((edges & ~levels & CONTROL_FWD)) {
            linear.x -= 14.0;}
        if ((edges & levels & CONTROL_BACK)) {
            linear.x -= 14.0;
        } else if ((edges & ~levels & CONTROL_BACK)) {
            linear.x += 14.0;}
        if ((edges & levels & CONTROL_LEFT)) {
            linear.y += 8.0;
        } else if ((edges & ~levels & CONTROL_LEFT)) {
            linear.y -= 8.0;}
        if ((edges & levels & CONTROL_RIGHT)) {
            linear.y -= 8.0;
        } else if ((edges & ~levels & CONTROL_RIGHT)) {
            linear.y += 8.0;}
        if ((edges & levels & CONTROL_ROT_LEFT)) {
            angular.z += (PI / 180) * 55.0;
            angular.x -= PI * 4;
        } else if ((edges & ~levels & CONTROL_ROT_LEFT)) {
            angular.z -= (PI / 180) * 55.0;
            angular.x += PI * 4;}
        if ((edges & levels & CONTROL_ROT_RIGHT)) {
            angular.z -= (PI / 180) * 55.0;
            angular.x += PI * 4;
        } else if ((edges & ~levels & CONTROL_ROT_RIGHT)) {
            angular.z += (PI / 180) * 55.0;
            angular.x -= PI * 4;
        }
         if ((edges & levels & CONTROL_ML_LBUTTON))
         {
          llMessageLinked(LINK_ALL_OTHERS, 0, "fire", NULL_KEY);
         }

    }

    timer()
    {
        wingFlapAlpha();
        if (llGetAgentInfo(gPilot) & AGENT_MOUSELOOK)
        {
          vector rot = llRot2Euler(llGetCameraRot());
          llRotLookAt(llEuler2Rot(<0,0,rot.z>),0.1,1);
        }
        else
        {
         llStopLookAt();
        }
        vector vel = llGetVel();
        float water = llWater(vel * 0.05);
        float ground = llGround(vel * 0.05);
        if (water > ground)  {  // above water
             vector MahPos = llGetPos();
             if (MahPos.z < water+water_offset){
                 llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.5);
                 llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 0.1);
                 llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, water + water_offset);
             }
             else {
                 llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0);
                 llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0);
             }
        }
        else { // above ground
             llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.0);
             llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 350.0);
        }

        llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, linear);
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, angular);
    }

    state_exit()
    {
        // we need to release controls and do other cleanup
        llStopSound();
        llSetTimerEvent(0);
        llStopLookAt();
        llReleaseControls();
        llClearCameraParams();
        llStopAnimation(gAnimationName);
        llMessageLinked(LINK_ALL_OTHERS, 0, "stop", NULL_KEY);
    }

    on_rez(integer foo) { state default; }
}

//END//
Link to comment
Share on other sites

It's always hard to modify someone else's script.  It takes you almost as long as it would to write your own from scratch, and then you've inherited someone else's ideas about how it ought to work.  Still, it's instructive to see what another scripter did.  We can learn from each other.  ;)

The partial answer to your immediate challenge is that the turret script is using llSetRot instead of changing the turret's local rotation, relative to the ship.  You can either use llSetLocalRot or, better, use llSetLinkPrimitiveParamsFast (with its PRIM_ROT_LOCAL parameter), which does not have a built-in delay.   The more serious challenge, as you have discovered, is that once you make the ship physical, none of those functions will work.  In a physical object, you'll want to use llRotLookAt, which will take a bit of work.

  • Like 1
Link to comment
Share on other sites

The 'obvious' workaround is to set the object non-physical before doing the child prim rotation, and set it back to physical afterwards*, although that's playing with fire a bit, and not something I'd recommend a novice scripter try and debug.

*I would either try to do it as all one llSLPPF call, or failing that, add a short sleep (or use the non-fast llSLPP ) after the call to turn non-physical, and increase the interval on the timer (sensor in the OP) accordingly.

Link to comment
Share on other sites

The problem here is the llRotLookAt function in the sensor() event. That does only work in child prims when it's non-physical. llSetLocalRot() and PRIM_ROT_LOCAL will work in child prims even if the object is set physical. It might be not recommended to do that while physical, but I never had a problem with doing just that actually.

If you replace llRotLookAt(k, ,1, .1) with llSetLocalRot(k / llGetRootRotation()) in the sensor() event, the turet should work even when the vehicle is physical.

However, since this is just detecting the rotation of the avatar who touched the turret, I don't know what the purpose of this script is actually. When that gunner Avatar is seated on the vehicle as well, it would have to rotate the seated AV in order to rotate the turret. There is nothing in this turret script that would take the avatars camera into account actually.

  • Thanks 1
Link to comment
Share on other sites

1 hour ago, arton Rotaru said:

There is nothing in this turret script that would take the avatars camera into account actually.

I could be remembering wrong, but I thought rotations were reported fairly accurately for avatars in mouselook.

Link to comment
Share on other sites

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