This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm whether you accept or reject these cookies being set.

A cookie will be stored in your browser regardless of choice to prevent you being asked this question again. You will be able to change your cookie settings at any time using the link in the footer.

Jetski Script für Opensim und Bullet Physik
#1
Jetski Script für Opensim und Bullet Physik


Hier ein weiteres Beispiel meiner Scripte als Schulungskurs zu dem bereits geposteten Grundlagenkurs für Fahrzeuge.

Dieses baut auf dem im Hanggleiter Script bereits erklärten Grundlagen auf. Links siehe am Artikelende.
Ich werde daher diese Grundlagen hier weglassen.


Diesmal gehts es um Wasserfahrzeuge mit Motorantrieb.

Hier die Grundlagen für Fahrzeugsteuerung:

- Das Fahrzeug bewegt sich auf Wasser Level.
- Es ist träge was Beschleunigung und Abbremsung angeht
- Beschleunigung und Bremsen quittiert es mit Neigung von Bug und Heck.
- Lenken quittiert es mit Eintauchen der Innenecke. (Kurvenkränkung)
- Es hat 1 Rückwärtsgang, einen Leerlaufgang, und 4 Vorwärts Gänge
- Das Lenkverhalten ist abhängig vom eingelegten Gang, ebenso die Motorkraft

Eine Anlehnung der Motorkraft an die Motordrehzahl wäre mit lieber gewesen, aber hätte die Berechnungsschleife stärker belastet.
Letzendlich wäre dann das Reaktionsverhalten schlechter geworden. Also habe ich mich zu diesem Kompromiss durchgerungen.


Steuerung:


Die Steuerung erfolgt wie immer mit den 4 Cursortasten sowie Bild AUF/AB

Bild Auf/Ab      dient der Gangschaltung
Pfeil Auf           gibt Gas und schaltet aus dem Leerlauf in den 1. Gang
Pfeil Ab            Bremst


Das Fahrzeug ist für Simwechsel unter Opensim >=  0.9x geeignet.
Man darf aber beim Simwechsel keine anderen Scripte Tragen die einen Reset durchführen und sich die Steuerungstasten danach holen.
Dieses ist bei einigen AOs der Fall.

Die Verwendung einer anderen Physikengine in Opensim ist machbar, lediglich die Motorparameter müssen dann neu ermittelt werden.
In SL funktioniert dieses Script ohne Änderungen nicht.

Das Fahrzeug erwartet 2 Animation - je eine für Vorwärtsfahrt und Rückwärtsfahrt.

Ab einer gewissen Mindestgeschwindigkeit werden Heckwellen Parikel (Gischt) erzeugt.
Die vorgesehene Textur UUID ist im Script zu ändern.
Wird keine (gültige) eingetragen wird weisser Schaum als Default verwendet.


Als Ergänzung zu dem Fahrzeug eignet sich das Beifahrer Sitz Script das ich bereits hier veröffentlicht habe.

Als Basis für die Fahrzeug Erstellung wird wieder ein Prim erwartet das als rootprim dieses Script , und die beiden Animationen trägt.
Das verlinkte Meshfahrzeug wird wieder per Script Phantom gemacht. 
Das Rootprim darf jedoch nicht per Hand auf Phantom gesetzt werden, sonst funktioniert die physische Bewegung nicht mehr.

Weitere Infos zu Fahrzeugen findet ihr im Grundlagen Artikel sowie im Hanggleiter.
https://service-silberwelten.de/showthread.php?tid=68
https://service-silberwelten.de/showthread.php?tid=69


Viel Spaß


Tron

Code:
// P304S V11 Jetski Script für Simcrossing in Opensim 09 by Tron CC0
// Aktualisiert 02.2021
// Heckwelle , neue Gangschaltung mit Leerlauf, neue Kinematik
// 2.2021 Partikel Textur vorladen auf Fahrzeugprim,  damit diese sofort angezeigt wird

//==== Globale User Variablen die ohne Multiposer benötigt werden ====
integer      racemode = FALSE;                  // Zeigt Text an
string       vorwaertsAnim = "Jetskifahrer";   // FahrerAnimation, entfällt bei Multiposer
string       rueckwaertsAnim = "Jetskirueck";   // FahrerAnimation, entfällt bei Multiposer
vector       sitzposition = <0.220, -0.0, 0.75>;  // Sitzposition, entfällt bei Multiposer



// === BOOTSTYP KONSTANTEN =====

list        getriebeliste = [ -5 , 0, 10, 30, 50, 70 ]; // Vortriebskraft des Linear Motors je Gang
list        lenkgetriebeListe = [-1.0, 0 , 1.0, 1.3, 1.1, 1.0 ];  // Lenkkraft des Angular Motors je Gang ,höhere Werte sind wendiger
list        gangListe = ["Rückwärts","Leerlauf","1. Gang","2. Gang","3. Gang","4. Gang"];  // Namensgebung für Gänge
float       kurvenkraenkung = 0.8;  // Seitliches Eintauchen in Kurven : Jetski 0.8, Rennboot 0.6, Yacht 03

//==== SONSTIGE GLOBAL VARIABLEN ====


key         kapitan;
integer     bootfaehrt;
integer     gang;                     // aktuell eingelegter Gang
float       antriebskraft;
float       lenkansprechverhalten;
integer     ganganzahl;
string      animation;               // aktuell gespielte Animation
integer     heckwelle = FALSE;       // aktueller Zusand der Partikel Heckwelle


vector vel;
float  fahrtgeschwindigkeit;  // Geschwindigkeit   

//==== E N D   G L O B A L   V A R I A B L E   D E C L A R A T I O N ====


init_engine()
{
integer lauf;
    bootfaehrt = FALSE;
    ganganzahl = llGetListLength(getriebeliste);
    llSetSitText("Fahrer");
    vector gSitTarget_Rot = llRot2Euler( llGetRootRotation() ); // SIT TARGET in Anhängigkeit von Boot Rotation
    llSitTarget(sitzposition, llEuler2Rot(DEG_TO_RAD * gSitTarget_Rot));
   
    lauf =2;
    do
    {
        llSetLinkPrimitiveParamsFast(lauf, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);   
        lauf++;
    } while (lauf <10);
   //llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
}


gangschaltung(string schalte)
{
    string gangname;

    if (schalte == "Leerlauf") { gang = 1;} // in Leerlauf schalten
    else if (schalte == "Rückwärts") { gang = 0;  llSleep(0.5);} // Rückwärts Gang einlegen
    else if (schalte == "Vorwärts") { gang = 2;  llSleep(0.5);}  // in 1. Gang schalten
    else if (schalte == "+") { gang += 1;}  // in höheren Gang schalten
    else { gang -= 1; }    // schalte in niedrigeren Gang

    antriebskraft = llList2Float(getriebeliste, gang);
    lenkansprechverhalten = llList2Float(lenkgetriebeListe, gang);
    gangname =  llList2String(gangListe , gang);
    llWhisper(0, gangname );

    if (gang == 0)        // Rückwärtsfahrt
        {
            llStopAnimation(animation);
            animation = rueckwaertsAnim; // Merker für aktuelle Animation setzten
            llStartAnimation(animation);
        }
    else  // Stehen oder vorwärts
        {
            llStopAnimation(animation);
            animation = vorwaertsAnim;   // Merker für aktuelle Animation setzten
            llStartAnimation(animation);
        }
   
    if (gang < 2){heckwellenpartikel(FALSE); llSetTimerEvent(0.0); }
    else llSetTimerEvent(1.0);  // Partikelüberwachung
}


init_followCam()
{
    llSetCameraParams([
                       CAMERA_ACTIVE, 1,                 // 0=INACTIVE  1=ACTIVE
                       CAMERA_BEHINDNESS_ANGLE, 2.5,     // (0 to 180) DEGREES
                       CAMERA_BEHINDNESS_LAG, 0.3,       // (0 to 3) SECONDS
                       CAMERA_DISTANCE, 3.0,             // ( 0.5 to 10) METERS
                       CAMERA_PITCH, 12.0,               // (-45 to 80) DEGREES
                       CAMERA_POSITION_LOCKED, FALSE,    // (TRUE or FALSE)
                       CAMERA_POSITION_LAG, 0.5,         // (0 to 3) SECONDS
                       CAMERA_POSITION_THRESHOLD, 0.0,   // (0 to 4) METERS
                       CAMERA_FOCUS_LOCKED, FALSE,       // (TRUE or FALSE)
                       CAMERA_FOCUS_LAG, 0.0,            // (0 to 3) SECONDS
                       CAMERA_FOCUS_THRESHOLD, 0.0,      // (0 to 4) METERS
                       CAMERA_FOCUS_OFFSET, <-3, 0, 1>   //  METERS
                      ]);
    llForceMouselook(FALSE);
}


set_engine()
{
    llSetVehicleType(VEHICLE_TYPE_BOAT);

// default rotation of prim
    llSetVehicleRotationParam(VEHICLE_REFERENCE_FRAME, <0.00000, 0.00000, 0.00000, 0.00000>);

// linear motor
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_TIMESCALE, 2.0);  // Anlaufzeit bis volle Geschwindigkeit
    llSetVehicleFloatParam(VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 2.0); // Zeit des Ausgleitens in vorwärts Richtung bis Stillstand
    llSetVehicleVectorParam(VEHICLE_LINEAR_FRICTION_TIMESCALE, <1.0,1.0,10.0> );
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 1.10);  // Einfluss auf Abrutschen an Hindernissen 1000 gut für Surfer
    llSetVehicleFloatParam(VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 1.00);
    

// angular motor
    llSetVehicleVectorParam(VEHICLE_ANGULAR_FRICTION_TIMESCALE, <1.0,1000.0,1000.0> );
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0.20);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 0.10);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.10);
    llSetVehicleFloatParam(VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 10.00);

// somewhat bounscy vertical attractor
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 0.5);
    llSetVehicleFloatParam(VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 2.00);

// hover
   llSetVehicleFloatParam(VEHICLE_HOVER_HEIGHT, 0.15 );  // Eintauchtiefe des Bootes im Stand
   llSetVehicleFloatParam(VEHICLE_HOVER_EFFICIENCY, 0.5 );
   llSetVehicleFloatParam(VEHICLE_HOVER_TIMESCALE, 1.0 );
   llSetVehicleFloatParam(VEHICLE_BUOYANCY, 1.0 );

// weak negative damped banking
    llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 1.0 );
    llSetVehicleFloatParam( VEHICLE_BANKING_MIX, 1.0 );
    llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 0.5 );
    
// remove these flags
    llRemoveVehicleFlags( VEHICLE_FLAG_HOVER_TERRAIN_ONLY
        | VEHICLE_FLAG_LIMIT_ROLL_ONLY
        | VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT);
// set these flags
    llSetVehicleFlags( VEHICLE_FLAG_NO_DEFLECTION_UP
      //  | VEHICLE_FLAG_HOVER_WATER_ONLY
      //  | VEHICLE_FLAG_HOVER_UP_ONLY  // verhindert wieder Eintachen im Wasser nach Sprung
        | VEHICLE_FLAG_LIMIT_MOTOR_UP );
}


heckwellenpartikel(integer sollsichtbar)
{
    if (sollsichtbar)
    {
        llParticleSystem(  // Heckwelle einschalten
        [
            PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_ANGLE_CONE,
            PSYS_SRC_BURST_RADIUS,1,
            PSYS_SRC_ANGLE_BEGIN,PI/2,
            PSYS_SRC_ANGLE_END,PI/2 + 0.01,
            PSYS_SRC_TARGET_KEY,llGetKey(),
            PSYS_PART_START_COLOR,<1.000000,1.000000,1.000000>,
            PSYS_PART_END_COLOR,<1.000000,1.000000,1.000000>,
            PSYS_PART_START_ALPHA,.7,
            PSYS_PART_END_ALPHA,0,
            PSYS_PART_START_GLOW,0,
            PSYS_PART_END_GLOW,0,
            PSYS_PART_BLEND_FUNC_SOURCE,PSYS_PART_BF_SOURCE_ALPHA,
            PSYS_PART_BLEND_FUNC_DEST,PSYS_PART_BF_ONE_MINUS_SOURCE_ALPHA,
            PSYS_PART_START_SCALE,<2.50000,2.500000,0.5000000>,    // viel Gischt**
            PSYS_PART_END_SCALE,<2,2, 0.000000>,
            PSYS_SRC_TEXTURE,"3a7ea058-e486-4d21-b2e6-8b47462bb45b",
            PSYS_SRC_MAX_AGE,0,
            PSYS_PART_MAX_AGE,6,
            PSYS_SRC_BURST_RATE,0.01,
            PSYS_SRC_BURST_PART_COUNT,1,
            PSYS_SRC_ACCEL,<0.000000,0.000000,-1.00000>,
            PSYS_SRC_OMEGA,<0.000000,0.000000,0.000000>,
            PSYS_SRC_BURST_SPEED_MIN,0.6,
            PSYS_SRC_BURST_SPEED_MAX,0.6,
            PSYS_PART_FLAGS,0
                | PSYS_PART_INTERP_COLOR_MASK
                | PSYS_PART_INTERP_SCALE_MASK
                | PSYS_PART_BOUNCE_MASK
                | PSYS_PART_EMISSIVE_MASK
        ]);
        heckwelle = TRUE;
    }
    else
    {
        llParticleSystem([]);  // Heckwelle ausschalten
        heckwelle = FALSE;
    }
}


default
{
    state_entry()
    {
        llSetLinkTexture(LINK_THIS,"3a7ea058-e486-4d21-b2e6-8b47462bb45b", ALL_SIDES);  // Partikeltextur auf roortprim vorladen damit es sofort angezeigt wird
        vector bootposition = llGetPos();
        bootposition.z = llGround( ZERO_VECTOR );
        float wasserstand = llWater( ZERO_VECTOR );
        if( bootposition.z < wasserstand ) { bootposition.z = wasserstand;}
        else {llSay(0,"Rezz mich im Wasser!");}
        llSetRegionPos(bootposition + <0,0,0.1>);
        init_engine();
        state Ground;
    }
}


state Ground
{
    state_entry() { llSetText("",<0,0,0>,1.0);}


    on_rez(integer param) { llResetScript();}


    changed(integer change)
    {
        if ((change & CHANGED_LINK) == CHANGED_LINK)
            {
                kapitan = llAvatarOnSitTarget();
                if (kapitan != NULL_KEY)
                    { // wir haben einen Kapitän
                        llSetStatus(STATUS_PHYSICS, TRUE);
                        llSetStatus(STATUS_ROTATE_Y,TRUE);
                        llSetStatus(STATUS_ROTATE_Z,TRUE);
                        set_engine();
                        llRequestPermissions(kapitan, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA | PERMISSION_TRACK_CAMERA);
                        bootfaehrt = TRUE; // Boot fährt
                    }
                else
                    { // Kaptiän hat Boot verlassen
                        llSetStatus(STATUS_PHYSICS, FALSE);
                        bootfaehrt = FALSE; // Boot steht
                        init_engine();
                        llStopAnimation( animation );
                        heckwellenpartikel(FALSE);
                        llPushObject(kapitan, <3,3,21>, ZERO_VECTOR, FALSE);
                        llReleaseControls();
                        llClearCameraParams();
                        llSetCameraParams([CAMERA_ACTIVE, 0]);
                        if(racemode) { llSetText("",<0,0,0>,1.0); }
                        llResetScript();
            }
        }

        if ((change & CHANGED_REGION) == CHANGED_REGION)
            {
                llWhisper(0,"Simgrenze überquert");
            }
    }


    run_time_permissions(integer perm)
    {
        if (perm)
        {
            gangschaltung("Leerlauf"); // im Leerlauf starten
            llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_DOWN | CONTROL_UP | CONTROL_RIGHT | CONTROL_LEFT | CONTROL_ROT_RIGHT | CONTROL_ROT_LEFT, TRUE, FALSE);
            init_followCam();
            llStopAnimation("sit");
            animation = vorwaertsAnim;  // aktuelle Animation merken
            llStartAnimation(animation);
            llSleep(1.5);
        }
    }


    control(key id, integer held, integer change)
    {
        if(bootfaehrt == FALSE){return;}
        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);    // Geschwindigkeit
        vector AngularMotor;
        if(racemode) llSetText( (string)fahrtgeschwindigkeit + " kmh",<1,1,1>,1.0);

// in höheren Gang schalten
        if(held & change & CONTROL_UP) { if (gang < (ganganzahl -1)) gangschaltung("+"); }

// in niedrigerne Gang schalten
        if(held & change & CONTROL_DOWN) { if (gang > 0) gangschaltung("-"); }

// weiterhin Vorwärts Gas geben
        if (held & CONTROL_FWD)
        {
           if (gang < 2) gangschaltung("Vorwärts");
           else llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft,0,0>);
        }
       
// Rückwärts schalten       
        if (held & change & CONTROL_BACK)
        {
            if ((fahrtgeschwindigkeit < 0.5 ) && (gang > 0)) { gangschaltung("Rückwärts");}      
        } 

// weiterhin Rückwärts fahren oder Bremsen
        if (held & CONTROL_BACK)
        {
            if (gang > 1) {llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0>);}  // Bremsen
            else if (gang == 0) // Rückwärts fahren
            {
                llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft, 0, 0>);
                llSetCameraParams([CAMERA_BEHINDNESS_ANGLE,-45.0]);
                llSetCameraParams([CAMERA_DISTANCE,8.0]);
            }
        }

// RECHTS lenken
        if  (held & CONTROL_ROT_RIGHT)
        {
           if(( gang > 1) && (fahrtgeschwindigkeit > 0.1 ))  // Einknicken in Kurvenmittelpunkt
            {
                AngularMotor.x += ( lenkansprechverhalten * kurvenkraenkung );
                AngularMotor.y -= ( lenkansprechverhalten * kurvenkraenkung );
            }
            else
            {
                AngularMotor.x = 0; // nicht einknicken bei Rückwärtsfahrt
                AngularMotor.y = 0;
            }       
            AngularMotor.z -= ( lenkansprechverhalten);
            if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft/2, 0, 0>);
        }

// LINKS Lenken
        if (held & CONTROL_ROT_LEFT)
        {
           if(( gang > 1) && (fahrtgeschwindigkeit > 0.1 ))  // Einknicken in Kurvenmittelpunkt
            {
                AngularMotor.x -= ( lenkansprechverhalten * kurvenkraenkung );
                AngularMotor.y -= ( lenkansprechverhalten * kurvenkraenkung );
            }
            else
            {
                AngularMotor.x = 0;
                AngularMotor.y = 0;
            }                       
            AngularMotor.z += ( lenkansprechverhalten);
            if(fahrtgeschwindigkeit < 1.0) llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft/2, 0, 0>);
        }
        
        llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, AngularMotor);  // Lenkkraft an Angular Motor übergeben
    }
   
   
    timer()
    {
        vel = llGetVel();
        fahrtgeschwindigkeit = llVecMag(vel);    // Geschwindigkeit   
        if(fahrtgeschwindigkeit > 5) { if(!heckwelle) heckwellenpartikel(TRUE);}  // Heckwelle anschalten
        else {if (heckwelle) heckwellenpartikel(FALSE);}
    }
}
Zitieren


Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste