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.

Hang Gleiter Flugscript für Opensim mit Bullet Physikengine
#1
Hanggleiter Flugscript für Opensim mit Bullet Physikengine


   

Das Skript wurde unter opensim 09 mit Bullet Physikengine getestet. 
Mit einigen Änderungen der Parameter sollte es auch unter anderen Bedingungen in Opensim laufen.
Für SL Bedarf es größerer Änderungen, vor allem im Berechtigungs System.


Grundlagen von Flugscripten:

- Flugobjekte können Höhe gewinnen und verlieren (Linear Motor ).
- Flugobjekte lenken indem sie seitlich wegdrehen (Angular Motor) und die Nase anheben (Angular Motor ).
- Flugobjekte benötigen eine Startgeschwindigkeit.


Anweisung:

1. Erstellen Sie einen Würfel mit der Größe 4 x 3 x 0,4 m. Dieser dient uns später als Physik RootPrim für die Aufnahme des Scriptes und der  Sitzanimation.

Ändern Sie die Prim-Einstellung von "Touch" auf "auf Objekt sitzen".
Das RootPrim darf nicht Phantom sein sonst geht die Physik Engine nicht! Jedoch wird der später verlinkte Mesh Hanggleiter per Script ohne physikalische Form eingestellt, um die Performance zu erhöhen

2. Fügen Sie eine Sitzanimation in dieses Prim ein. Diese muss "sitzanimation" heissen , oder sie ändern den Namen im Script.
Die Einstellung der Sitzposition findet man im Script an dieser Stelle. Sie sollte an das eigenen Flugobjekt angepasst werden. 
//==== Globale User Variablen
vector      sitzposition = <-0.2, -0.0, -0.12>; // Sitzposition


3. Legen Sie das Skript in das Prim hinein, und resetten es. Nun nehmen Sie Platz. Das Skript macht das Rootprime unsichtbar.
( Verwenden Sie die Steuerung ALT T, um es anzuzeigen. )
Versuchen Sie nun, das Objekt zu fliegen. Der Würfel Box wird als physische Form des Segelflugzeugs verwendet.
Wenn Sie es also für andere Flugobjekte verwenden, müssen Sie die Prims-Größen ändern. Guten Flug!

4. Um ein sichtbares Objekt daran zu linken gehen sie folgendermaßen vor:
Bringen sie das vorhin erstellte Prim auf eine exakte Simposition und exakte Ausrichtung im Winkel.
Den Hanggleiter kann man hier als freies Mesh finden:
https://www.cadnav.com/3d-models/aircraft/



Hinweise zum Flugverhalten:

Das Flugobjekt kennt 2 Gänge: Stehen und Fliegen. 
Die Parameter für den Flugmodus findet man in der Scriptsektion "Flugzeug Konstanten"

Der Leerlauf enspricht dabei immer dem ersten Parameter und soll so belassen werden.

der 2. Parameter entspricht dann dem Flugmodus.
// === FLUGZEUG KONSTANTEN =====

list        getriebeliste = [  0, 35];             // Antriebskraft beim Fliegen: hier aktuell 35

list        lenkgetriebeListe = [0 , 0.4 ];     // Wendigkeit, höhere Werte sind wendiger. Hier 0.4

float      kurvenkraenkung = 5;               // Querneigung beim Kurvenflug, hier 5
float      abfluggeschwindigkeit = 20.0;    // Mindestgeschwindigkeit um Auftrieb zu erhalten. darunter verbleibt man am Boden. Hier 20



Die Bedienung erfolgt mit den Cursortasten sowie Bild AUF/AB

Bild auf- Steigen
Bild ab - Sinken

Corsor auf: beschleunigen und umschalten aus Standmodus in Flugmodus
Cursor ab: Landeanflug einleiten
Cursor links- rechts: lenken

Es gibt einen automatischen Landeanflug der mit der "Pfeil abwärts" Taste ausgelöst wird.
Dieser kann duch drücken der Taste "BILD auf" abgebrochen werden.
Die seitlichen Steuertasten bleiben dabei weiter im Gebrauch.

Bei Flughöhe unter 2 Meter über dem Simboden wird automatisch gelandet und der Standmodus aktiviert.

Das Überfliegen von Simgrenzen in Opensim 0.9x wird unterstützt.

Das Scritp dient insbesondere dem Erlernen des scriptings von physikalischen Fahrzeugen, wie es im Grundlagen Artikel beschrieben wurde.

Dabei ist es neben den Flugrelevanten Teilen noch um ein paar Schmankerl erweitert damit es sofort nutzbar wird.

Parameter 
integer      racemode = TRUE;                  // Zeigt Geschwindigkeits Text an. kann mit FALSE abgeschalten werden


Da dieses Script zum Lernen gedacht ist hier eine ERKLÄRUNG der FUNKTIONEN


init_engine()
verwende ich um die Grundinitialisierungen des Flugscriptes gebündelt aufzurufen. Danach ist das Fahrzeug einsatzbereit.
Wird üblicherweise beim Scriptstart aufgerufen- oder bei Verlassen des Fahrzeuges durch den Piloten weil da ein Scriptreset durchgeführt wird.

gangschaltung(string schalte)
stellt die gesamten Flugparameter je nach Gang ein (hier Standmodus / Flugmodus)
Wird während des Fluges aufgerufen.

init_followCam()
stellt die Position ein aus der ihr das Flugzeug beim Fliegen seht.

set_engine()
stellt die Grundparameter der Physikengine ein. Diese Einstellungen sind verantwortlich wie die Linear Motor Steuerwerte und Angular Motor Steuerwerte verarbeitet werden. Diese Einstellungen sind stark abhängig von der eingesetzten Physikengine. Portiert man das Script nach SL (Havoc Physik engine) oder auf eine ander Opensim Physik engine, so sind hier alle Parameter anzupassen.


default 
ist (immer) der start der Hauptroutine des Scritpes. diese ruft zuerst "state_entry()" auf


state_entry()
ist die erste Initialisietungs Routine die beim Scriptstart ausgeführt wird.
Diese gibt es je "State"- also duchaus mehrfach.
Ein Status wirkt wie eine große Umklammerung/Kapselung aller darin enthaltenen Routinen.
Wird ein Status verlassen, so wird ales darin laufende hinfällig und gestoppt.

state Ground
ist ein weiter Status. Ich verwende den im Flugmodus. 
So lassen sich verschiedene Elemente - wie der Timer und die Tastaturüberprüfung, auf den Flugmodus beschränken.


state_entry()
wieder erste routine die aufgerufen wird-nur diesmal wenn der Status "Ground" gesetzt ist

on_rez(integer param)
prüft ob das Flugobjekt eventuell im flugmodus ins inventar geholt wurde und nun so gerezzt wird. Dann resettet es das Script.

changed(integer change)
if ((change & CHANGED_LINK) == CHANGED_LINK)  detektiert ob sich jemand auf das Flugobjekt setzt oder aufsteht, und führt dann die notwendigen Iniitialisierungen durch.
if ((change & CHANGED_REGION) == CHANGED_REGION) detektiert ob es eine Simgrenzen Überquerung gab.

run_time_permissions(integer perm)
Diese Routine wird aufgerufen wenn das Scritp die Berechtigung angefordert hat Tastatur und Kamerasteuerung zu übernehmen.
Dieses Verhalten ist grob unterschiedlich in SL und Opensim! In Opensim ist diese Rechtefreigabe eigentlich nur "pro forma". Keiner schert sich drum ob sie tatsächlich erfolgte. SL ist hier strikt. Die SL Variante der Rechteholung funktioniert aber in Opensim nicht.


control(key id, integer held, integer change)
Dies ist die Hauptroutine der Fahrzeugsteuerung. Hier erfolgt die Auswertugn von Tastendrücken und der Aufruf der Bearbeitungs Funktionen.
Ebenso erfolgt hier der Aufruf des ANGULAR Motors! Deteils sieht in meinem Grundlagen Artikel.


timer()
Hier erfolgt die Periodische Kraft/Impulsversorgung des Linear Motros


Während des Fluges werden also nur 2 Routinen standig ervwendet:
timer um Vekorkräfte zu erzeugen, und Control um rotations Kräfe zu erzeugen.
Entsprechend wichtig ist das diese beiden Routinen so kurz wie möglich gehalten werden damit das Fahrzeug sich dynamisch anfühlt.
Mit Kürze meine ich aber nicht die Zeilen des Programmcodes, sondern die Anzahl und Aufwändigkeit der Berechungen die darin ablaufen.

Dies kann durch vorab Berechnungen von Teil-und Zwischenergebnissen sowie Initialisierungen vorab deutlich minimiert werden.


Viel Spaß beim Testen


Tron


PS falls sich Fehler eingeschlichen haben sollten gebt bitte Bescheid.


Der Hanggleiter kann als Fertigmodell auch bei mir direkt abgeholt werden in Virtual Africa.
Er befindet sich im Beachshop ( Strohhüte ) auf der Isla Bonita.


Link zu Physik Fahrzeuge Grundlagen 
https://service-silberwelten.de/showthread.php?tid=68


Code:
// P315 Release V1 Hang glider Script für Simcrossing in Opensim 09
// by Tron MCP
// Version 1.0 Stand 29.06.2019
// Creative Commons Version

// feel free to use for your builds.
// The Scritp itself has to stay free of costs and fullperm. The header has to be left unchanged.



//==== Globale User Variablen die ohne Multiposer benötigt werden ====
integer      debug = FALSE;                     // Debug Modus

integer      racemode = TRUE;                   // Zeigt Geschwindigkeits Text an
string       sitzanimation;                      // FahrerAnimation
vector       sitzposition = <-0.2, -0.0, -0.12>; // Sitzposition


// === FLUGZEUG KONSTANTEN =====

list        getriebeliste = [  0, 35];        // Antriebskraft je Gang
list        auftriebsliste = [ 0 , 1];        // Auftrieb je Gang
list        lenkgetriebeListe = [0 , 0.4 ]; // Wendigkeit, höhere Werte sind wendiger
list        gangListe = ["Leerlauf", "Flugmodus"];
float       kurvenkraenkung = 5;
float       abfluggeschwindigkeit = 20.0;    // Mindestgeschwindigkeit um Auftrieb zu erhalten

vector      vel;
float       fahrtgeschwindigkeit;           // aktuelle Fluggeschwindigkeit
      
//==== SONSTIGE GLOBAL VARIABLEN ====

float       wasserstand;
key         pilot;
integer     imflug;
integer     gang;                     // aktuell eingelegter Gang
float       antriebskraft;
float       steigfaehigkeit;
float       lenkansprechverhalten;
integer     ganganzahl;
string      animation;               // aktuell gespielte Animation
integer     landeanflug;


//==== 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()
{
   imflug = FALSE;
   ganganzahl = llGetListLength(getriebeliste);
   llSetSitText("Fliegen");
   vector gSitTarget_Rot = llRot2Euler( llGetRootRotation() ); // SIT TARGET in Anhängigkeit von RootPrim Rotation
   llSitTarget(sitzposition, llEuler2Rot(DEG_TO_RAD * gSitTarget_Rot));
   llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_PHYSICS_SHAPE_TYPE, PRIM_PHYSICS_SHAPE_NONE]);
   llSetLinkAlpha(LINK_THIS, 0.0, ALL_SIDES);   
   llSetLinkAlpha(LINK_ALL_OTHERS, 1.0, ALL_SIDES);
}


gangschaltung(string schalte)
{
   string gangname;

   if (schalte == "Flugmodus") { gang = 1;}  // in Flugmodus schalten   
   else { gang = 0;} // in Leerlauf schalten

   antriebskraft = llList2Float(getriebeliste, gang);
   steigfaehigkeit = llList2Float(auftriebsliste, gang);
   lenkansprechverhalten = llList2Float(lenkgetriebeListe, gang);
   gangname =  llList2String(gangListe , gang);
}


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, 10.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.0,         // (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, <-5, 0, 0>   // <-10,-10,-10> to <10,10,10> METERS
                     ]);
   llForceMouselook(FALSE);
}


set_engine()
{
   //Flugzeug PARAMETER
   llSetVehicleType(VEHICLE_TYPE_AIRPLANE);

   // linear friction
   llSetVehicleVectorParam( VEHICLE_LINEAR_FRICTION_TIMESCALE, <200, 200, 200> );

   // angular friction
   llSetVehicleFloatParam( VEHICLE_ANGULAR_FRICTION_TIMESCALE, 2 );

   // linear motor
   llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0> );
   llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE, 2 );
   llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 1.0 );

   // agular motor
   llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, <0, 0, 0> );
   llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0 );
   llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE, 0.4);

   // hover
   llSetVehicleFloatParam( VEHICLE_HOVER_HEIGHT, 2 );
   llSetVehicleFloatParam( VEHICLE_HOVER_EFFICIENCY, 0 );
   llSetVehicleFloatParam( VEHICLE_HOVER_TIMESCALE, 3 );
   llSetVehicleFloatParam( VEHICLE_BUOYANCY, 0.977 );

   // linear deflection
   llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY, 0 );
   llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 5 );

   // angular deflection
   llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY, 0.1);
   llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 10);

   // vertical attractor
   llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY, 1 );
   llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE, 1 );

   // banking
   llSetVehicleFloatParam( VEHICLE_BANKING_EFFICIENCY, 1);
   llSetVehicleFloatParam( VEHICLE_BANKING_MIX, .5);
   llSetVehicleFloatParam( VEHICLE_BANKING_TIMESCALE, 0.01);

   // default rotation of local frame
   llSetVehicleRotationParam( VEHICLE_REFERENCE_FRAME, <0,0,0,1>);

   // remove these flags
   llRemoveVehicleFlags( VEHICLE_FLAG_NO_DEFLECTION_UP
                         | VEHICLE_FLAG_HOVER_WATER_ONLY
                         | VEHICLE_FLAG_LIMIT_ROLL_ONLY
                         | VEHICLE_FLAG_HOVER_TERRAIN_ONLY
                         | VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT
                         | VEHICLE_FLAG_HOVER_UP_ONLY
                         | VEHICLE_FLAG_LIMIT_MOTOR_UP );
}


default
{
   state_entry()
   {
       vector bootposition = llGetPos();
       bootposition.z = llGround( ZERO_VECTOR );
       wasserstand = llWater( ZERO_VECTOR );
       if( bootposition.z < wasserstand ) { bootposition.z = wasserstand;}
       llSetRegionPos(bootposition + <0,0,0.1>);
       sitzanimation = llGetInventoryName(INVENTORY_ANIMATION, 0);
       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)
           {
               pilot = llAvatarOnSitTarget();
               if (pilot != NULL_KEY)
                   { // wir haben einen Piloten
                       llSetStatus(STATUS_PHYSICS, TRUE);
                       llSetStatus(STATUS_ROTATE_Y,TRUE);
                       llSetStatus(STATUS_ROTATE_Z,TRUE);
                       llSetStatus(STATUS_ROTATE_X,TRUE);
                       set_engine();
                       llRequestPermissions(pilot, PERMISSION_TRIGGER_ANIMATION | PERMISSION_TAKE_CONTROLS | PERMISSION_CONTROL_CAMERA | PERMISSION_TRACK_CAMERA);
                       llSay(0,"Flieger grüß mir die Sonne!\n\r steuer mit Pfeil vorwärts/links/rechts , \n\r kontrollier die Höhe mit Bild auf/ab \n\r lande mit Pfeil runter.");
                       imflug = TRUE; // Flugobjekt fliegt
                       landeanflug = FALSE;
                   }
               else
                   { // Pilot hat Flugobjekt verlassen
                       llSetStatus(STATUS_PHYSICS, FALSE);
                       imflug = FALSE; // Flugobjekt steht
                       init_engine();
                       llStopAnimation( animation );    // entfällt bei Multiposer
                       llPushObject(pilot, <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)
           {
               if(debug) llWhisper(0,"Simgrenze überquert");
               wasserstand = llWater( ZERO_VECTOR );    // Wasserstand der neuen sim ermitteln
           }
   }


   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 = sitzanimation;  // aktuelle Animation merken
           llStartAnimation(animation);
           llSleep(1.5);
       }
   }


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

       if(held & CONTROL_UP)                       //  STEIGFLUG gewählt
           {
               if( fahrtgeschwindigkeit > abfluggeschwindigkeit )
               { 
                   landeanflug = FALSE;   
                   llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft *0.75, 0, fahrtgeschwindigkeit * steigfaehigkeit>);  // STEIGEN
                   AngularMotor.y = -2.5;                                                              // NASE anheben
               }
               else { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft,0,0>); } 
           }

       else if(held & CONTROL_DOWN)                // SINKFLUG gewählt
           {
               llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft *2, 0, - fahrtgeschwindigkeit * steigfaehigkeit>);       // SINKEN
               AngularMotor.y = 3.5;                                                                   // NASE runterdrücken
           }       

       else if (held & CONTROL_FWD)                // weiterhin Vorwärts Gas gegeben
           { llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft,0,0>); }   

       if (~held & change & CONTROL_FWD)              // Auf Vorwärtsflug geschalten
           {
               if (gang < 1)
                   {
                       gangschaltung("Flugmodus");
                       llSetTimerEvent(1.0); // gestartet: nun kontinuierlicher Hoehenverlust und Vortrieb zuschalten
                       llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, <antriebskraft/2 ,0,0>); 
                   }
           }
          
       else if (held & CONTROL_BACK)               // Automatisches Landen gewählt
           {
               if (!landeanflug) llSay(0,"Landung eingeleitet");
               landeanflug = TRUE;
               AngularMotor.y = 1;                                                                     // NASE runterdrücken
           }


       if  (held & CONTROL_ROT_RIGHT)              // Steuerung nach RECHTS erfolgt
       {
           if( fahrtgeschwindigkeit > 3 )                                                              // Einknicken in Kurvenmittelpunkt
           {
               AngularMotor.x += ( lenkansprechverhalten * kurvenkraenkung );                          // ROLLEN rechts
               AngularMotor.y =  AngularMotor.y - ( lenkansprechverhalten * kurvenkraenkung * 0.5);    // NASE anheben
           }
           AngularMotor.z -= lenkansprechverhalten;                                                    // RECHTS DREHEN
       }

       else if (held & CONTROL_ROT_LEFT)           // Steuerung nach LINKS erfolgt
       {
           if( fahrtgeschwindigkeit > 3 )                                                              // Einknicken in Kurvenmittelpunkt
           {
               AngularMotor.x -= ( lenkansprechverhalten * kurvenkraenkung );                          // ROLLEN links
               AngularMotor.y =  AngularMotor.y - ( lenkansprechverhalten * kurvenkraenkung * 0.5);    // NASE anheben
           }
           AngularMotor.z += lenkansprechverhalten;                                                    // LINKS DREHEN
       }
       llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION, AngularMotor);       
   }


   timer()
   {
       llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, < 10 , 0, -8>); // kontinuierlichen Vortrieb von 10 udn Sinken von 8

       vel = llGetVel();
       fahrtgeschwindigkeit = llVecMag(vel); // Geschwindigkeit ermitteln

       vector drachenposition = llGetPos();
       float flughoehe = drachenposition.z - llGround( ZERO_VECTOR );   
       if (flughoehe < 2 )                    // automatisch landen
       {
           llSetTimerEvent(0.0);
           llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION, < 0,0,0>);       
           if( drachenposition.z < wasserstand ) { drachenposition.z = wasserstand;}
           llSetRegionPos(drachenposition + <0,0,0.1>);
           gangschaltung( "Leerlauf");
           llSetText("",<0,0,0>,1.0);
       }
   }
}
Zitieren


Gehe zu:


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