User:Daemonika Nightfire/Scripts/Ablaufsteuerung

From Second Life Wiki
Jump to: navigation, search
Home Grundlagen | Funktion | Schalter | Liste | Ablaufsteuerung

Ablaufsteuerung

  • Auch auf dieser Seite verwende ich das gleiche Format wie bei den anderen tutorials. Der OwnerKey und die entsprechende Funktion zum umbenennen des Objects im state_entry dient lediglich der Erkennbarkeit fuer den Inworld Unterricht.

Bedingungen

Bei den Bedingungen handelt es sich im Grunde um Voraussetzungen, welche erfuellt sein muessen, damit die entsprechende Funktion ausgeloest wird.


if

  • Eine einzelne if, ohne weitere Bedingungen in der selben Funktion eignen sich dazu konkrete Voraussetzungen abzufragen. Bei jeder weiteren "Antwort", die nicht diese Bedingung erfuellt, kommt es in diesem Script zu keinerlei sichtbaren Reaktion.
if / Frage
key owner;
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Bedingung 01 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        key user = llDetectedKey(0);
 
        if(user == owner) // Frage
        {
            llSay(0, "Hallo Besitzer.");
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

else if

  • Eine else if setzt das vorhanden sein einer if grundsaetzlich voraus.
  • In dieser Konstelation ist es moeglich 2 und mehr Bedingungen abzufragen. Ein klassisches Beispiel stellt ein konventionelles Menue dar. Hierbei wird ein Button mit einer if und jeder weitere mit einer else if abgefragt.
else if / andere Frage
key owner;
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Bedingung 02 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        key user = llDetectedKey(0);
 
        if(user == owner) // Frage
        {
            llSay(0, "Hallo Besitzer.");
        }
        else if(user != owner) // andere Frage
        {
            llSay(0, "Hallo Fremder.");
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

else

  • Bei der else gilt die gleiche Regel wie bei der else if, auch hier ist das vorhanden sein einer if zwingend ervorderlich.
  • Anders als beim ersten Beispiel (if) dient eine else dazu trotzdem eine Reaktion auszuloesen, auch wenn jede weitere moegliche Bedingung, ausser der vorangegangenen if, als ausschluss Kriterium gewertet wird.
else / alles andere
key owner;
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Bedingung 03 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        key user = llDetectedKey(0);
 
        if(user == owner) // Frage
        {
            llSay(0, "Hallo Besitzer.");
        }
        else // alles andere
        {
            llSay(0, "Hallo Fremder.");
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

Schleifen

Waerend ein Timer im direkten Vergleich einer unendlichen Funktion entspricht, stellen Schleifen eine endliche Form einer sich wiederholenden Funktion dar. Schleifen sind ideal dazu geeignet, Listen abhaengige Funktionen abzuarbeiten, ohne einen weiteren Event auszuloesen.


Folgende Beispiele verwenden ein kuenstliches Limit (limit) und einen Index (i) welcher einem Counter (Zaehlwerk) entspricht. Das limit und der index muessen nicht zwangslaeufig gleich sein. Wir haben 3 verschiedene Moeglichkeiten Schleifen zu erzeugen, als da waere die for, do while & while. Jede dieser Schleifen auf dieser Seite macht genau das gleiche und fuehrt zum selben Ergebnis. Sie begninnen bei 0 und zaehlen jeweils 10x hoch und wiederholen die enthaltene Funktion bis das das Limit erreicht ist.

  • Ich schreibe absichtlich 10x und nicht bis 10 zaehlen, weil das naemlich nicht stimmt.
  • Erklaerung: 10x von 0 an gezaehlt entspricht 9, weil der Anfang des index jeweils mit 0 angegeben ist.
  • Weiterhin achte auf das kleiner als Zeichen < das ist nicht das gleiche wie <=.
  • Das bedeutet, mit < (kleiner als) endet der index nach dem 10. Durchlauf 1 vor dem Limit und mit <= (kleiner gleich) wird bis auf das angegebene Limit gezaehlt entspricht 11 Durchlaeufen.
  • Zusaetzlich macht es auch noch einen unterschiedlich, ob du innerhalb der Anweisung for, do while & while das i vor oder nach die ++ setzt.
  • Die kombination while(i++ < limit); entspricht 11 und die Kombination while(i++ <= limit); zaehlt sogar 12 mal.

Grundsaetzlich spielt es mittlerweile keine Rolle mehr, welche der 3 Schleifen nun schneller ist als die anderen. Seit Mono und seit dem die Server so schnell geworden sind, macht es keinen spuerbaren Unterschied mehr. Im Gegenteil, hin und wieder muss ich die Funktionen sogar kuenstlich drosseln, eben weil es zu schnell ist. So gesehen ist es nur noch reine Geschmackssache, welche Schleife man verwenden moechte.

KBnote.png Note: Beachte das der index-counter in der alternativen Methode nicht in der Anweisung steht und die ++ Zeichen sich dahinter statt davor befinden.

for

  • Bei der einfachen for Schleife sind alle notwendigen Angaben fuer die Anweisung gleich in der ersten Zeile for(start; vergleich; counter)
  • Diese Variante ist sehr weit verbreitet, doch fuehlt sich fuer mich nach einer gezwungenen Funktion an.
for Schleife alternative Methode
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 01 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i; // index
 
        // innerhalb der for Anweisung wird der index auf 0 gesetzt,...
        // festgestellt ob der index kleiner als das limit ist,...
        // und am schluss der index um je 1 erhoeht.
        for(i = 0; i < limit; ++i) 
        {
            llSay(0, (string)i); // gibt den aktuellen index Wert zurueck.
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 01b " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i = 0; // index
 
        // bei dieser Methode wird der index vorher auf 0 gesetzt,...
        // in der Anweisung festgestellt ob der index kleiner als das limit ist.
        for(; i < limit;)
        {
            llSay(0, (string)i);
            i++; // der index erhoeht sich bei jedem Durchgang um 1.
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

do while

  • In der do while Schleife werden die Angaben erst in der letzten Zeile vorgenommen while(counter < limit);
  • Hierbei wird der counter direkt mit dem limit verglichen und hinter der Anweisung befindet sich ein Semikolon.
  • Diese Schleife zaehlt zu meinen Favoriten, weil es auf mich viel klarer strukturiert wirkt.
do while Schleife alternative Methode
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 02 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i = 0; // index
 
        // in dieser Schleife wird erst am Ende die Anweisung erteilt.
        do
        {
            llSay(0, (string)i); // gibt den aktuellen index Wert zurueck.
        }
        while(++i < limit); // index counter in der while Anweisung.
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 02b " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i = 0; // index
 
        do
        {
            llSay(0, (string)i); // gibt den aktuellen index Wert zurueck.
            i++; // index counter innerhalb der Schleife.
        }
        while(i < limit);
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

while

  • Die while Schleife sieht im Grunde genaus so aus wie die do while Schleife.
  • Sie unterscheidet sich lediglich darin, das die while Anweisung gleich am Anfang steht und das do fehlt.
  • Wie in der for Schleife, steht auch hier hinter der Anweisung kein Semikolon.
while Schleife alternative Methode
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 03 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i = 0; // index
 
        // dieses mal steht die while Anweisung mit counter am Anfang
        while(++i < limit)
        {
            llSay(0, (string)i); // gibt den aktuellen index Wert zurueck.
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
key owner;
 
integer limit = 10; // limit
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Schleife 03b " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer i = 0; // index
 
        while(i < limit)
        {
            llSay(0, (string)i); // gibt den aktuellen index Wert zurueck.
            i++; // der index erhoeht sich bei jedem Durchgang um 1.
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

Rueckgabe

  • Text

return

  • Ein return hat verschiedene Verwendungs-Moeglichkeiten, als da waere bestimmte Variablen zurueck zu geben, oder einfach um eine Funktion / Event zu verlaessen.
return als Ruckgabe-Wert
/*
    In diesem Beispiel verwenden wir eine globale Funktion um eine Variable mittels return zurueck zu geben.
    Dabei steht die Anweisung inklusive Variable direkt im llSay Befehl.
    Die Variable wird an die globale Funktion uebergeben und entsprechend ausgewertet.
    Der Wert der dabei entsteht, wird direkt in das Say als Text integriert.
*/
 
key owner;
 
string get_name(key uuid)
{
    return llGetUsername(uuid);
}
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Return 01 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        key user = llDetectedKey(0);
 
        llSay(0, "Hallo " + get_name(user));
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
  • Natuerlich kann man diese Funktion auch zum rechnen verwenden.
integer return float return
key owner;
 
// Ausreichend um ganze Zahlen zu berechnen.
integer rechnen(integer A, integer B)
{
    return A + B;
}
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Return 01b " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        integer num_1 = 5;
        integer num_2 = 2;
 
        llSay(0, "Mathe " + (string)rechnen(num_1, num_2));
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
key owner;
 
// Wenn du aber Komma-Werte erwartest, solltest du besser mit floats rechnen.
float rechnen(float A, float B)
{
    return A / B;
}
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Return 01c " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        float num_1 = 5.0;
        float num_2 = 2.0;
 
        llSay(0, "Mathe " + (string)rechnen(num_1, num_2));
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}
  • Nun ein Beispiel, wie der return; einen Event komplett verlaesst.
  • Zu diesem zweck musste ich mal eine Reihe von Abfragen generieren, um zu verdeutlichen was genau passiert.
return als EXIT
key owner;
 
integer counter = 1;
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Return 02 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        llSay(0, "Touched!");
 
        llSay(0, "teste Bedingung 1");
        if(counter == 1)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 2");
        if(counter == 2)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 3");
        if(counter == 3)
        {
            llSay(0, "counter: " + (string)counter);
            return; // Verlaesst den kompletten Event, ohne nachfolgende Funktionen zu beruecksichtigen.
        }
 
        llSay(0, "teste Bedingung 4");
        if(counter == 4)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 5");
        if(counter == 5)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        counter++;
        if(counter > 5)
        {
            counter = 1;
        }
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}

Sprung

  • Bei der Original Beschreibung fuer den jump habe ich gelesen, das es eine haessliche Funktion sei und man sie nicht nutzen sollte, wenn es sich vermeiden liesse.
  • Das sehe ich etwas anders, schliesslich ist der jump eine tolle Moeglichkeit gewisse Funktionen die sich gegebenenfalls aehneln zu ueberspringen, wenn man nachfolgend dennoch eine aehnliche funktion ausloesen moechte. Beispielsweise ein Untermenue, ohne nachfolgende If vor dem llDialog auszuloesen.
Der jump besteht aus 2 komponenten.
1. jump name; (start)
2. @name;     (ziel)

jump

  • Folgendes Script sieht fast genau so aus, wie das letzte return Beispiel. Doch mit dem jump wird nicht der komplette Event sofort verlassen, sondern an die Stelle gesprungen, wo du das Ziel angibst, es sei denn du setzt das Ziel direkt ans Ende des Events.
  • Saemtliche Funktionen die danach folgen, werden dann noch beruecksichtigt.
jump
key owner;
 
integer counter = 1;
 
default
{
    state_entry()
    {
        owner = llGetOwner();
        llSetObjectName("Jump 01 " + llKey2Name(owner));
    }
 
    touch_start(integer total_number)
    {
        llSay(0, "Touched!");
 
        llSay(0, "teste Bedingung 1");
        if(counter == 1)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 2");
        if(counter == 2)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 3");
        if(counter == 3)
        {
            llSay(0, "counter: " + (string)counter);
            jump Ausgang; // Verlaesst die Funktion und fuehrt en Event an angegebener Stelle fort.
        }
 
        llSay(0, "teste Bedingung 4");
        if(counter == 4)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        llSay(0, "teste Bedingung 5");
        if(counter == 5)
        {
            llSay(0, "counter: " + (string)counter);
        }
 
        // Der jump springt an die individuell angegebene Stelle
        @Ausgang;
 
        counter++;
        if(counter > 5)
        {
            counter = 1;
        }
 
        //@Ausgang;
    }
 
    on_rez(integer Dae)
    {
        llResetScript();
    }
}