Benutzer-Werkzeuge

Webseiten-Werkzeuge


scripting:tutorials:level2:functions

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.

Link zu der Vergleichsansicht

Beide Seiten, vorherige ÜberarbeitungVorherige Überarbeitung
Nächste Überarbeitung
Vorherige Überarbeitung
scripting:tutorials:level2:functions [2023/09/09 11:51] fritz_98scripting:tutorials:level2:functions [2024/05/17 10:02] (aktuell) fritz_98
Zeile 24: Zeile 24:
 Es handelt sich dabei nur um eine alternative Schreibweise, die Funktionalität bleibt die gleiche. Es handelt sich dabei nur um eine alternative Schreibweise, die Funktionalität bleibt die gleiche.
  
-Das gleiche Prinzip funktioniert auch, wenn ein Table als einziger Parameter erwartet wird. Wir definieren eine Funktion, die eine Person etwas sagen lässt:+Das gleiche Prinzip funktioniert auch, wenn ein Table als einziger Parameter erwartet wird. Wir definieren eine Funktion, die eine Person etwas sagen lässt und belassen es Optional, ob der Sprecher oder die Aussage angegeben werden. Dazu benutzen wir ein Table als Paramter und wenden einen kleinen Trick anUm herauszufinden, welche Informationen gegeben wurden, fragen wir (indirekt), ob sie **nil** sind. In Lua ist jede Variable, bevor sie definiert wird, **nil**. Demzufolge sind alle undefinierten Variablen **nil**.
 <code lua> <code lua>
 -- _WhoAndWhat ist ein Table, das eine Person und einen Text enthalten kann, aber nicht muss -- _WhoAndWhat ist ein Table, das eine Person und einen Text enthalten kann, aber nicht muss
Zeile 143: Zeile 143:
 </code> </code>
  
 +Abschließend können wir auch alle Rückgabewerte automatisch in ein Table fassen, indem wir geschweifte Klammern um den Funktionsaufruf setzen:
 +<code lua>
 +MaxResults = { Argmax{3, 25, 14, 9, 11, 17, 36} }
 +</code>
 +Der Wert ''Max'' findet sich in ''MaxResults[1]'' und der Wert ''MaxIndex'' in ''MaxResults[2]''.
 +
 +**Wichtig**: Wenn die Anzahl der Rückgabewerte einer Funktion bekannt ist, sollte man immer die Variante über die Definition der einzelnen Variablen wählen. Sie ist performanter und macht es für einen Leser direkt ersichtlich, welche und wie viele Variablen entstehen. Der Umweg über das Table ist vor allem nützlich, wenn man die Anzahl der Rückgabewerte **nicht kennt**. \\
 +Ein Beispiel für den letzteren Fall wird im Abschnitt zum Siedler-Skripting beleuchtet.
 +
 +Lua selbst stellt auch Funktionen mit mehreren Rückgabewerten zur Verfügung. Die Funktion ''string.find'' durchsucht einen String nach dem ersten Vorkommen eines gegebenen Substrings. Zurückgegeben werden der erste und der letzte Index des gefundenen Stringabschnitts:
 +<code lua>
 +FoundStart, FoundEnd = string.find("HelloWorld", "oWo")
 +</code>
 +''FoundStart'' ist ''5'' und FoundEnd ''7'', da der Teil des Strings, auf den die Suche zutrifft, am fünften Buchstaben beginnt und am siebten endet.
 +
 +----
 +
 +====Beispiele im Siedler-Skripting====
 +
 +Eine Funktion, die beim Siedler-Skripten häufig verwendet wird, ermittelt die Gebäude oder Einheiten eines bestimmten Typs des Spielers. ''Logic.GetPlayerEntities(_PlayerId, _EntityType, _Amount)'' gibt höchstens ''_Amount'' [[ scripting:tutorials:level1:place_entities#exkursentity-id_vs_skriptname |Entity-Ids]] von Spieler ''_PlayerId'' vom Typ ''_EntityType'' zurück. Wenn der Spieler weniger als ''_Amount'' Entities des gesuchten Typs besitzt, werden entsprechend weniger EnitityIds zurückgegeben. Wir haben hier also genau den Fall, dass eine Funktion viele Rückgabewerte hat, deren Anzahl aber nicht immer gleich ist.
 +
 +Darüber hinaus ist der erste Rückgabewert keine EntityId, sondern die Anzahl der gefundenen Ids!
 +
 +In diesem Beispiel wollen wir 5 kleine Wohnhäuser von Spieler 1 zum Brennen bringen:
 +<code lua>
 +-- Maximal 5, potentiell 0 Entities im Table
 +local Player1Residences = { Logic.GetPlayerEntitites(1, Entities.PB_Residence1, 5) }
 +
 +-- Die Iteration soll bei Index 2 beginnen, da an Index 1 keine EntityId, sondern die Anzahl der
 +-- gefundenen Häuser enthält
 +-- Die Iteration endet bei Player1Residences[1] + 1, da die Anzahl der gefundenen Häuser plus
 +-- jede einzelne EntityId zusammen die Länge der Liste bestimmen
 +-- Wenn keine Häuser gefunden wurden, ist Player1Residences[1] + 1 = 0 + 1 = 1
 +-- Das bedeutet, dass mit i = 2, 1 der Block in der Schleife nie betreten wird
 +for i = 2, Player1Residences[1] + 1 do
 +    -- Setze die Lebenspunkte herab, sodass das Haus zu brennen beginnt
 +    SetHealth(Player1Residences[i], 25)
 +end
 +</code>
  
 ---- ----
Zeile 162: Zeile 201:
 werden nur die ersten drei beachtet und addiert, der Rest verworfen. Die Funktion hat keine Möglichkeit, auf die Argumente zuzugreifen. Allerdings wird **kein** Fehler angezeigt! Darauf zu achten, einer Funktion nicht zu viele Argumente zu übergeben, wird dem Programmierer überlassen. werden nur die ersten drei beachtet und addiert, der Rest verworfen. Die Funktion hat keine Möglichkeit, auf die Argumente zuzugreifen. Allerdings wird **kein** Fehler angezeigt! Darauf zu achten, einer Funktion nicht zu viele Argumente zu übergeben, wird dem Programmierer überlassen.
  
-Der Nutzen, den man daraus ziehen kann, ist eingeschränkt. Im Artikel zur [[ scripting:tutorials:level2:lua_library |Lua-Standardbibliothek]] wird die Funktion ''unpack'' beschrieben, mit der ein numerisches Table ([[ scripting:tutorials:level1:tables#tables_als_listen |Liste]]) "ausgepackt" wird. Die Funktion gibt jeden Eintrag im Table einzeln als Rückgabewert aus (siehe auch den Abschnitt oben über mehrere Rückgabewerte). ''unpack'' kann also dazu benutzt werden, die Inhalte eines numerischen Tables einzeln als Argumente zu übergeben. Mit der Funktion ''SumOfThree'' können so die ersten drei Zahlen in so einem Table addiert werden:+Der Nutzen, den man daraus ziehen kann, ist eingeschränkt. Im Artikel zur [[ scripting:tutorials:level2:lua_library |Lua-Standardbibliothek]] wird die Funktion ''unpack'' beschrieben, mit der ein numerisches Table ([[ scripting:tutorials:level1:tables#tables_als_listen |Liste]]) "ausgepackt" wird. Die Funktion gibt jeden Eintrag im Table einzeln als Rückgabewert aus (siehe auch den Abschnitt [[ scripting:tutorials:level2:functions#mehrere_rueckgabewerte |oben]] über mehrere Rückgabewerte). ''unpack'' kann also dazu benutzt werden, die Inhalte eines numerischen Tables einzeln als Argumente zu übergeben. Mit der Funktion ''SumOfThree'' können so die ersten drei Zahlen in so einem Table addiert werden:
 <code lua> <code lua>
 local Numbers = {3, 25, 14, 9, 11, 17, 36} local Numbers = {3, 25, 14, 9, 11, 17, 36}
Zeile 213: Zeile 252:
 Auch hier ist wieder zu beachten, dass zu wenige Argumente nicht per se als Fehler gelten und als Problemursache häufig versteckt auftreten. In unserem Beispiel mit der Summe können damit aber alle Parameter optional gemacht werden, sodass die nicht zwingend besetzt werden müssen. Auch hier ist wieder zu beachten, dass zu wenige Argumente nicht per se als Fehler gelten und als Problemursache häufig versteckt auftreten. In unserem Beispiel mit der Summe können damit aber alle Parameter optional gemacht werden, sodass die nicht zwingend besetzt werden müssen.
  
-**Achtung**: Auf diese Weise solltest du höchstens **einen** Parameter als optional definieren. Bedenke, dass in unserem Beispiel für die Angabe von ''_C'' **zwingend** die Angabe von ''_B'' notwendig ist. Es lassen sich demnach keine Parameter "überspringen". Wenn du mehrere optionale Parameter anbieten willst, solltest du den Parameter als Table definieren (siehe auch das Beispiel ''SaySomething'' aus dem Abschnitt oben über verkürzte Funktionsaufrufe). Dadurch bekommt jeder Parameter einen Namen und kann unabhängig von allen anderen angegeben werden. \\+**Achtung**: Auf diese Weise solltest du höchstens **einen** Parameter als optional definieren. Bedenke, dass in unserem Beispiel für die Angabe von ''_C'' **zwingend** die Angabe von ''_B'' notwendig ist. Es lassen sich demnach keine Parameter "überspringen". Wenn du mehrere optionale Parameter anbieten willst, solltest du den Parameter als Table definieren (siehe auch das Beispiel ''SaySomething'' aus dem Abschnitt [[ scripting:tutorials:level2:functions#verkuerzte_funktionsaufrufe |oben]] über verkürzte Funktionsaufrufe). Dadurch bekommt jeder Parameter einen Namen und kann unabhängig von allen anderen angegeben werden. \\
 Diesem Prinzip folgt beispielsweise die aus [[ scripting:tutorials:level1:enemy_ai#setupplayerai |Ebene 1 bekannte Funktion]] ''SetupPlayerAi'', die viele Optionen für die Definition eines KI-Spielers bietet, die unabhängig voneinander gewählt werden können. Diesem Prinzip folgt beispielsweise die aus [[ scripting:tutorials:level1:enemy_ai#setupplayerai |Ebene 1 bekannte Funktion]] ''SetupPlayerAi'', die viele Optionen für die Definition eines KI-Spielers bietet, die unabhängig voneinander gewählt werden können.
  
Zeile 259: Zeile 298:
  
 =====Beliebig viele Parameter===== =====Beliebig viele Parameter=====
 +
 +In manchen Situationen ist es nützlich, eine Funktion mit beliebig vielen Parametern aufrufen zu können. Die Funktion soll dann einfach mit allen Parametern, die sie bekommt, arbeiten.
 +
 +Ein Beispiel dafür kann eine Funktion sein, die aus allen Zahlen, die sie als Argumente erhält, eine Summe bildet. Auf herkömmlichem Weg kann man nur eine endliche Menge an Parametern definieren, die jederzeit überschritten werden kann. Zwangsläufig muss der Weg über Tables führen, die beliebig groß sein können:
 +<code lua>
 +function Sum(_Numbers)
 +    local Result = 0
 +    for _, Number in ipairs(_Numbers) do
 +        Result = Result + Number
 +    end
 +    return Result
 +end
 +
 +print(Sum{3, 25, 14, 9, 11, 17, 36})
 +</code>
 +
 +Es gibt in Lua aber auch eine Schreibweise, die automatisch alle Argumente, die der Funktion übergeben werden, in ein Table gibt. Dazu schreibt man statt dem Argument drei Punkte (''...''). Alle an diesem Platzhalter gegebenen Argumente sind innerhalb der Funktion in einem Table namens ''arg'' verfügbar:
 +<code lua>
 +function Sum(...)
 +    local Result = 0
 +    for _, Number in ipairs(arg) do
 +        Result = Result + Number
 +    end
 +    return Result
 +end
 +
 +-- Beachte den Unterschied zu oben: Hier wird kein Table als Argument überreicht, sondern einfach alle Zahlen
 +-- hintereinander!
 +print(Sum(3, 25, 14, 9, 11, 17, 36))
 +</code>
 +**Hinweis**: In der Lua-Demo muss ''arg'' durch ''{...}'' getauscht werden, da Siedler noch mit einer alten Lua-Version läuft.
 +
 +Das lässt sich auch mit festen Parametern kombinieren. In der folgenden Beispielfunktion wollen wir in ein bestehendes Table alle angegebenen Werte einfügen:
 +<code lua>
 +MyTable = {3, 25, 14}
 +
 +function MultiInsert(_Table, ...)
 +    for _, Value in ipairs(arg) do
 +        table.insert(_Table, Value)
 +    end
 +end
 +
 +MultiInsert(MyTable, 7, "t", 0, "Spinat", 9999)
 +</code>
 +Nach dem Aufruf hat ''MyTable'' 8 Einträge, wurde also um alle Werte, die der Funktion übergeben wurden, erweitert.
 +
 +**Achtung**: Die Parameter können in diesem Fall nicht umgekehrt angegeben werden (also nicht ''MultiInsert(..., _Table)''! Die Funktion kann beim Aufruf nicht wissen, welche Argumente zu ''...'' und welche zu ''_Table'' gehören. Deshalb besteht generell die Regel, dass zuerst die festen/notwendigen Parameter angegeben werden müssen, bevor man die Funktion für beliebig viele weitere Parameter mit ''...'' "öffnet".
 +
 +----
 +
 +Im nächsten Kapitel bleiben wir bei Funktionen und versuchen, mit Rekursionen zu arbeiten.
 +
 +[[ scripting:tutorials:level2:loops| Voriges Kapitel: Weiteres zu Schleifen ]] \\
 +[[ scripting:tutorials:level2:recursion | Nächstes Kapitel: Rekursionen ]] \\
 +[[ scripting:tutorials:level2:functions | Zurück nach oben ]]
scripting/tutorials/level2/functions.1694260316.txt.gz · Zuletzt geändert: 2023/09/09 11:51 von fritz_98