Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
05-02-2005 06:15
I pored throught the scripting tips, library, and wiki, and I haven't been able to find an open-source example of a stateful vehicle (one that has, for example, a hover mode / flight mode / etc.). So naturally I took a hoverboard script and a plane script and tried to staple them together by putting each one in it's own state and stringing them together with listen commands. However, the controls behave oddly once I do this. The linear controls seem to be have properly for each state, but the angular controls don't work for either state.
I can't figure out the problem, since I didn't do anything differently between the angular controls for one state or the other. Anyone have a (working) open source multimode vehicle I could crack open to learn?
I'll post the gimp-tastic script I'm trying to cobble together as well.
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
05-02-2005 06:21
// Simple airplane script example
// THIS SCRIPT IS PUBLIC DOMAIN! Do not delete the credits at the top of this script!
// Nov 25, 2003 - created by Andrew Linden and posted in the Second Life scripting forum // Jan 05, 2004 - Cubey Terra - minor changes: customized controls, added enable/disable physics events // Somewhat later - Kage Seraph tries to staple two open source vehicles into one // Feel free to copy, modify, and use this script.
// Always give credit to Andrew Linden and all people who modify it in a readme or in the object description.
//the first state is a conventional airplane, the second is a more helicpter-like mode of motion. switch between them with "hover" or "fly" on channel 0
//here we define global variables for use in each of the two states. Not elegant but it should in theory work just fine // assumes that the root primitive is oriented such that its // local x-axis points toward the nose of the plane, and its // local z-axis points toward the top float speed=0; float high=30; float turn=5; float lift=0; integer sit = FALSE; integer vertoff = FALSE; integer adecayoff = FALSE; integer ldecayoff = FALSE; string Vname; key avatar; // control flags that we set later integer gAngularControls = 0; integer gLinearControls = 0;
// we keep track of angular history for more responsive turns integer gOldAngularLevel = 0;
// the linear motor uses an accumulator model rather than keeping track // of the linear control level history vector gLinearMotor = <0, 0, 0>;
default { on_rez(integer bettersmegthandead) { llResetScript(); llSetStatus(STATUS_PHYSICS, FALSE); //CUBEY - ensure that physics are disabled when plane is rezzed so it doesn't fly off }
state_entry() { //we just defined these globally above, but we set them to nil explicitly here in case we arrive in the default state from hovering. gAngularControls = 0; gLinearControls = 0; gOldAngularLevel = 0; gLinearMotor = <0, 0, 0>;
llSay(0,"entering flight mode"); llListen( 0, "", llGetOwner(), "" ); llSetSitText("Fly"); llCollisionSound("", 0.0);
// the sit and camera placement is very shape dependent // so modify these to suit your vehicle llSitTarget(<0.6, 0.0, 0.20>, ZERO_ROTATION); llSetCameraEyeOffset(<-10.0, 0.0, 2.0> ); llSetCameraAtOffset(<3.0, 0.0, 1.0> );
llSetVehicleType(VEHICLE_TYPE_AIRPLANE);
// weak angular deflection llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.1); llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 1.0);
// strong linear deflection llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1.0); llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 0.2);
// somewhat responsive linear motor llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 0.5); llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 20);
// somewhat responsive angular motor, but with 3 second decay timescale llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0.5); llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 3);
// very weak friction //llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000.0, 1000.0, 1000.0> ); // CUBEY - original line llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <200, 20, 20> ); // CUBEY - increased friction llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1000.0, 1000.0, 1000.0> );
llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.65); // almost wobbly - CUBEY - increased from .25 to improve stability llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1.5); // mediocre response
llSetVehicleFloatParam(VEHICLE_BANKING_EFFICIENCY, 0.4); // medium strength llSetVehicleFloatParam(VEHICLE_BANKING_TIMESCALE, 0.1); // very responsive llSetVehicleFloatParam(VEHICLE_BANKING_MIX, 0.95); // more banking when moving
// hover can be better than sliding along the ground during takeoff and landing // but it only works over the terrain (not objects) //llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 3.0); //llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.5); //llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 2.0); //llSetVehicleFlags(VEHICLE_FLAG_HOVER_UP_ONLY);
// non-zero buoyancy helps the airplane stay up // set to zero if you don't want this crutch llSetVehicleFloatParam(VEHICLE_BUOYANCY, 0.2);
// define these here for convenience later // CUBEY - modified these as per Shadow's prefs gAngularControls = CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_BACK | CONTROL_FWD; gLinearControls = CONTROL_UP | CONTROL_DOWN;
}
changed(integer change) { if (change & CHANGED_LINK) { key agent = llAvatarOnSitTarget(); if (agent) { if (agent != llGetOwner()) { // only the owner can use this vehicle llSay(0, "You aren't the owner -- only the owner can fly this plane."); llUnSit(agent); llPushObject(agent, <0,0,10>, ZERO_VECTOR, FALSE); } else { // clear linear motor on successful sit gLinearMotor = <0, 0, 0>; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor);
//llSetStatus(STATUS_PHYSICS, TRUE); llSetVehicleFloatParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, 1000.0); llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1000.0); llRequestPermissions(agent, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS); } } else { // stop the motors gLinearMotor = <0, 0, 0>; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor); llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, gLinearMotor);
// use friction to stop the vehicle rather than pinning it in place //llSetStatus(STATUS_PHYSICS, FALSE); llSetVehicleFloatParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, 1.0); llSetVehicleFloatParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, 1.0);
// driver is getting up llReleaseControls(); llStopAnimation("sit"); llSetStatus(STATUS_PHYSICS, FALSE); //CUBEY - turn off physics to make sure the parked plane can't be moved } }
}
run_time_permissions(integer perm) { if (perm) { llStartAnimation("sit"); llTakeControls(gAngularControls | gLinearControls, TRUE, FALSE); llSetStatus(STATUS_PHYSICS, TRUE); //CUBEY - enable physics when avatar sits } }
control(key id, integer level, integer edge) { // only change linear motor if one of the linear controls are pressed vector motor; integer motor_changed = level & gLinearControls; if (motor_changed) { if(level & CONTROL_UP) //CUBEY { if (gLinearMotor.x < 0) { gLinearMotor.x = 0; } else if (gLinearMotor.x < 30) { gLinearMotor.x += 5; } motor_changed = TRUE; } if(level & CONTROL_DOWN) //CUBEY { if (gLinearMotor.x > 0) { gLinearMotor.x = 0; } else if (gLinearMotor.x > -30) { gLinearMotor.x -= 5; }; motor_changed = TRUE; } llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, gLinearMotor); }
// only change angular motor if the angular levels have changed motor_changed = (edge & gOldAngularLevel) + (level & gAngularControls); if (motor_changed) { motor = <0,0,0>; if(level & (CONTROL_RIGHT|CONTROL_ROT_RIGHT)) { // add roll component ==> triggers banking behavior motor.x += 10; } if(level & (CONTROL_LEFT|CONTROL_ROT_LEFT)) { motor.x -= 10; } if(level & (CONTROL_BACK)) // CUBEY { // add pitch component ==> causes vehicle lift nose (in local frame) motor.y -= 8; } if(level & (CONTROL_FWD)) // CUBEY { motor.y += 8; } llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, motor); } // store the angular level history for the next control callback gOldAngularLevel = level & gAngularControls; }
listen( integer channel, string name, key id, string message ) { if( message == "hover") { //llReleaseControls(); This is apparently automatic? state hover; }
}
}
state hover {
listen( integer channel, string name, key id, string message ) { if( message == "fly") { //Remove all the flags //llReleaseControls(); llRemoveVehicleFlags(-1); state default; }
} state_entry() { llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS); llListen( 0, "", llGetOwner(), "" ); llWhisper(0,"hovering"); llSetCameraEyeOffset(<-10.0, 0.0, 3.0>); llSetCameraAtOffset(<0.0, 0.0, 0.0>); llSetVehicleType(VEHICLE_TYPE_AIRPLANE); llSetVehicleFlags(VEHICLE_FLAG_HOVER_UP_ONLY); // linear friction llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <1000, .1, 1000> ); //1000,2,0.5 // angular friction llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, <.1, .1, .1> ); // linear motor llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0> ); llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE, 0.1 ); llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 1 ); // angular motor llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, <0, 0, 0> ); llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, 5 ); llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 5 ); // hovering llSetVehicleFloatParam( VEHICLE_HOVER_HEIGHT, 3 ); llSetVehicleFloatParam( VEHICLE_HOVER_EFFICIENCY, 1.0 ); llSetVehicleFloatParam( VEHICLE_HOVER_TIMESCALE, 0 ); llSetVehicleFloatParam( VEHICLE_BUOYANCY, 1.0 ); // linear deflection llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1 ); llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 10 ); // angular deflection llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 1 ); llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 10 ); // vertical attractor llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, .1 ); llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 2 ); // banking llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, .3 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 0 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, .1 );//1000 // default rotation of local frame llSetVehicleRotationParam( VEHICLE_REFERENCE_FRAME, <0, 0, 0, 1> ); // remove these flags llRemoveVehicleFlags( VEHICLE_FLAG_HOVER_WATER_ONLY | VEHICLE_FLAG_HOVER_TERRAIN_ONLY | VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT | VEHICLE_FLAG_LIMIT_ROLL_ONLY | VEHICLE_FLAG_LIMIT_MOTOR_UP); } changed(integer change) {
avatar = llAvatarOnSitTarget(); string name=llKey2Name(avatar); if(change & CHANGED_LINK) { if(avatar == NULL_KEY) { // You have gotten off llSetTimerEvent(0.0); //llStopSound(); //llMessageLinked(LINK_ALL_CHILDREN, 0, "stop", NULL_KEY); llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, FALSE); llReleaseControls(); //llStopAnimation("motorcycle_sit"); sit = FALSE; //llPushObject(llGetOwner(), <0, 2, 7>, <0,0,0>, TRUE); llSetStatus(STATUS_PHYSICS, FALSE); state default; } } }
run_time_permissions(integer perms) { if(perms & (PERMISSION_TAKE_CONTROLS)) { llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT | CONTROL_UP | CONTROL_DOWN, TRUE, FALSE); //llMessageLinked(LINK_ALL_CHILDREN, 0, "rotor", NULL_KEY); //llLoopSound("jet0",0.7); llSetTimerEvent(0.2); } else { llUnSit(avatar); } } control(key id, integer level, integer edge) { vertoff = FALSE; adecayoff = FALSE; ldecayoff = FALSE; if ((level & CONTROL_FWD) && (level & CONTROL_BACK)) { ldecayoff = TRUE; speed=0; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <speed,0,lift>); } if (level & CONTROL_FWD) { //llMessageLinked(LINK_ALL_OTHERS,0,"forward",""); //llWhisper(0,"forward"); ldecayoff = TRUE; if(speed > 6) { speed = 6; } else { speed += 0.8; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <speed,0,lift>); } if (level & CONTROL_BACK) { ldecayoff = TRUE; if(speed < -4) { speed = -4; } else { speed -= 0.7; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <speed,0,lift>); } if (level & CONTROL_ROT_RIGHT) { adecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <turn*4,0,0>); } if (level & CONTROL_ROT_LEFT) { adecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <-turn*4,0,0>); //llMessageLinked(LINK_ALL_OTHERS,0,"left",""); } if (level & CONTROL_RIGHT) { ldecayoff = TRUE; if(speed < -4) { speed = -4; } else { speed -= 0.7; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,speed,lift>); } if (level & CONTROL_LEFT) { ldecayoff = TRUE; if(speed > 4) { speed = 4; } else { speed += 0.7; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,speed,lift>); } if (level & CONTROL_UP) { ldecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,0,high/4>); } if (level & CONTROL_DOWN) { ldecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,0,-(high/6)>); } if (vertoff) { llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0 ); llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1000 ); llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 0 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 0 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 1000 );//1000 } if (!vertoff) { llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, .1 ); llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 2 ); llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, .5 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 0 );//0 llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, .1 );//1000 } if (adecayoff) { llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 300 ); llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, <6,6,6> ); } if (!adecayoff) { llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, .2 ); llSetVehicleVectorParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, <.1, .1, .1> ); } if (ldecayoff) { llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 30 ); llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <1, 6, 6> ); } if (!ldecayoff) { llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 3 ); llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <1, 2, .05> ); }
} timer() { llSetStatus(STATUS_PHYSICS, TRUE); }
}
|
Jeffrey Gomez
Cubed™
Join date: 11 Jun 2004
Posts: 3,522
|
05-02-2005 11:09
Glaring Error #1, in state hover: if (level & CONTROL_ROT_RIGHT) { adecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <turn*4,0,0>); } if (level & CONTROL_ROT_LEFT) { adecayoff = TRUE; llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, <-turn*4,0,0>); //llMessageLinked(LINK_ALL_OTHERS,0,"left",""); } if (level & CONTROL_RIGHT) { ldecayoff = TRUE; if(speed < -4) { speed = -4; } else { speed -= 0.7; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,speed,lift>); } if (level & CONTROL_LEFT) { ldecayoff = TRUE; if(speed > 4) { speed = 4; } else { speed += 0.7; } lift= speed * 0.01; llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0,speed,lift>); } I would probably not do it this was due to how I use my keyboard. It should "work," but make sure you're pressing the right button. By contrast, the first state uses both CONTROL_~ and CONTROL_ROT_~. Second, make sure you're calling all the right initialization stuff in state 2. I'm too lazy to check each one, since I don't use vehicle code all that often anymore, but that could be another problem. Me? I'm a purist. I've been toying with llMoveToTarget/llRotLookAt vehicles instead. 
_____________________
---
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
05-02-2005 11:36
Hey Jeffrey, thanks for the speedy reply! I guess I'm not sure I recognize the mistake you note in the first part of your response? If you're referring to the fact that control_right and control_rot_right perform different functions, that is intentional (feature, not bug, haha!); I want the vehicle when in hover mode be able to strafe and rotate just as an av can.
I'll recheck the hover state vehicle initialization junk again.
Holler if ya see any goofs of mine that specifically bork the angular controls. =)
|
Kage Seraph
I Dig Giant Mecha
Join date: 3 Nov 2004
Posts: 513
|
05-03-2005 16:45
Figured it out... The problem was a missing llSetStatus(STATUS_ROTATE_X | STATUS_ROTATE_Y | STATUS_ROTATE_Z, TRUE); call. With that set to false it is no wonder why the angular controls were busted. =D
|