scripting:tutorials:level2:functions
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Beide Seiten, vorherige ÜberarbeitungVorherige ÜberarbeitungNächste Überarbeitung | Vorherige Überarbeitung | ||
scripting:tutorials:level2:functions [2023/09/09 09:17] – fritz_98 | scripting:tutorials:level2:functions [2024/05/17 10:02] (aktuell) – fritz_98 | ||
---|---|---|---|
Zeile 2: | Zeile 2: | ||
Für ein lauffähiges Skript ist der korrekte Umgang mit Funktionen essentiell. Einige Funktionen, die Siedler bereitstellt, | Für ein lauffähiges Skript ist der korrekte Umgang mit Funktionen essentiell. Einige Funktionen, die Siedler bereitstellt, | ||
- | |||
---- | ---- | ||
Zeile 25: | Zeile 24: | ||
Es handelt sich dabei nur um eine alternative Schreibweise, | Es handelt sich dabei nur um eine alternative Schreibweise, | ||
- | 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 |
<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 111: | Zeile 110: | ||
=====Mehrere Rückgabewerte===== | =====Mehrere Rückgabewerte===== | ||
+ | |||
+ | Funktionen in Lua können mehr als einen Wert mittels **return** zurückgeben. Die einzelnen Werte müssen dafür durch ein Komma getrennt sein. | ||
+ | |||
+ | Zur Anschauung definieren wir eine Funktion, die die größte Zahl in einem Table findet. Außerdem soll die Funktion den Index dieser Zahl zurückgeben. | ||
+ | <code lua> | ||
+ | function Argmax(_Table) | ||
+ | local MaxIndex = 1 | ||
+ | local Max = _Table[MaxIndex] | ||
+ | for i, Value in ipairs(_Table) do | ||
+ | if _Table[i] > Max then | ||
+ | Max = _Table[i] | ||
+ | MaxIndex = i | ||
+ | end | ||
+ | end | ||
+ | return Max, MaxIndex | ||
+ | end | ||
+ | </ | ||
+ | Für beide Rückgabewerte müssen eigene Variablen definiert werden, ebenfalls durch ein Komma getrennt: | ||
+ | <code lua> | ||
+ | Max, MaxIndex = Argmax{3, 25, 14, 9, 11, 17, 36} | ||
+ | </ | ||
+ | Falls wir den '' | ||
+ | <code lua> | ||
+ | -- Das Maximum wird weiterhin in die Variable Max geschrieben | ||
+ | Max = Argmax{3, 25, 14, 9, 11, 17, 36} | ||
+ | </ | ||
+ | Falls wir **nur** den '' | ||
+ | <code lua> | ||
+ | -- Technisch gesehen ist _ auch nur eine Variable. Sie sollte allerdings nicht benutzt werden, sondern | ||
+ | -- nur einen Platzhalter für nicht benötigte Variablen darstellen | ||
+ | _, MaxIndex = Argmax{3, 25, 14, 9, 11, 17, 36} | ||
+ | </ | ||
+ | |||
+ | 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} } | ||
+ | </ | ||
+ | Der Wert '' | ||
+ | |||
+ | **Wichtig**: | ||
+ | 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 '' | ||
+ | <code lua> | ||
+ | FoundStart, FoundEnd = string.find(" | ||
+ | </ | ||
+ | '' | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ====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. '' | ||
+ | |||
+ | 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, | ||
+ | |||
+ | -- 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], | ||
+ | end | ||
+ | </ | ||
---- | ---- | ||
Zeile 130: | Zeile 201: | ||
werden nur die ersten drei beachtet und addiert, der Rest verworfen. Die Funktion hat keine Möglichkeit, | werden nur die ersten drei beachtet und addiert, der Rest verworfen. Die Funktion hat keine Möglichkeit, | ||
- | Der Nutzen, den man daraus ziehen kann, ist eingeschränkt. Im Artikel zur [[ scripting: | + | Der Nutzen, den man daraus ziehen kann, ist eingeschränkt. Im Artikel zur [[ scripting: |
<code lua> | <code lua> | ||
local Numbers = {3, 25, 14, 9, 11, 17, 36} | local Numbers = {3, 25, 14, 9, 11, 17, 36} | ||
Zeile 138: | Zeile 209: | ||
Dieser Use Case lässt sich aber auch anders (und deutlich besser lesbar) umsetzen und soll hier nur als Beispiel dienen. \\ | Dieser Use Case lässt sich aber auch anders (und deutlich besser lesbar) umsetzen und soll hier nur als Beispiel dienen. \\ | ||
**Hinweis**: | **Hinweis**: | ||
+ | |||
+ | Der interessantere Fall ist der, bei dem zu wenig Argumente übergeben wurden. Jeder Parameter einer Funktion, der nicht mit einer Eingabe belegt wird, ist innerhalb der Funktion **nil**: | ||
+ | <code lua> | ||
+ | function SumOfThree(_A, | ||
+ | print(_A) | ||
+ | print(_B) | ||
+ | print(_C) | ||
+ | return _A + _B + _C | ||
+ | end | ||
+ | |||
+ | SumOfThree(3) | ||
+ | </ | ||
+ | Dieser Aufruf wird '' | ||
+ | |||
+ | Das kann man ausnutzen, um Parameter optional zu machen. Wir modifizieren die Funktion '' | ||
+ | <code lua> | ||
+ | function SumOfThree(_A, | ||
+ | -- nil wird von if wie false interpretiert | ||
+ | -- Wenn _A nil ist, also nicht angegeben wurde, wird es auf 0 gesetzt | ||
+ | if not _A then | ||
+ | _A = 0 | ||
+ | end | ||
+ | | ||
+ | -- Das selbe Prinzip wenden wir bei _B an | ||
+ | if not _B then | ||
+ | _B = 0 | ||
+ | end | ||
+ | | ||
+ | -- Und auch bei _C | ||
+ | if not _C then | ||
+ | _C = 0 | ||
+ | end | ||
+ | | ||
+ | -- So können wir sicherstellen, | ||
+ | return _A + _B + _C | ||
+ | end | ||
+ | |||
+ | -- Gibt nun ohne Fehler das korrekte Ergebnis aus | ||
+ | print(SumOfThree(3)) | ||
+ | print(SumOfThree(3, | ||
+ | </ | ||
+ | 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**: | ||
+ | Diesem Prinzip folgt beispielsweise die aus [[ scripting: | ||
+ | |||
+ | ---- | ||
+ | |||
+ | ====Beispiele im Siedler-Skripting==== | ||
+ | |||
+ | Einige Funktionen, die du schon kennst, machen sich optionale Parameter zunutze. Eine davon ist '' | ||
+ | <code lua> | ||
+ | -- Verbietet den Ausbau zum Kanonenturm für Spieler 1 | ||
+ | ForbidTechnology(Technologies.UP2_Tower, | ||
+ | |||
+ | -- Verbietet ebenfalls den Ausbau zum Kanonenturm für Spieler 1 | ||
+ | ForbidTechnology(Technologies.UP2_Tower) | ||
+ | </ | ||
+ | |||
+ | Wenig überraschend ist '' | ||
+ | <code lua> | ||
+ | function ForbidTechnology(_Technology, | ||
+ | if not _PlayerId then | ||
+ | -- Gibt die Spieler-Id des lokalen menschlichen Spielers zurück (auch im Multiplayer) | ||
+ | -- Dadurch kann im Multiplayer mit einem einzigen Aufruf von ForbidTechnology | ||
+ | -- allen Spielern eine bestimmte Technologie verboten werden | ||
+ | _PlayerId = GUI.GetPlayerID() | ||
+ | end | ||
+ | Logic.SetTechnologyState(_PlayerId, | ||
+ | end | ||
+ | </ | ||
+ | Analog sind auch '' | ||
+ | |||
+ | Ein etwas anderes Beispiel ist die Funktion '' | ||
+ | <code lua> | ||
+ | function AddGold(_PlayerId, | ||
+ | if not _Amount then | ||
+ | _Amount = _PlayerId | ||
+ | _PlayerId = GUI.GetPlayerID() | ||
+ | end | ||
+ | Logic.AddToPlayersGlobalResource(_PlayerId, | ||
+ | end | ||
+ | </ | ||
+ | Bei allen anderen Ressourcen ist das ebenfalls so gelöst. | ||
+ | |||
---- | ---- | ||
=====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, | ||
+ | </ | ||
+ | |||
+ | Es gibt in Lua aber auch eine Schreibweise, | ||
+ | <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, | ||
+ | -- hintereinander! | ||
+ | print(Sum(3, | ||
+ | </ | ||
+ | **Hinweis**: | ||
+ | |||
+ | 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, | ||
+ | end | ||
+ | end | ||
+ | |||
+ | MultiInsert(MyTable, | ||
+ | </ | ||
+ | Nach dem Aufruf hat '' | ||
+ | |||
+ | **Achtung**: | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Im nächsten Kapitel bleiben wir bei Funktionen und versuchen, mit Rekursionen zu arbeiten. | ||
+ | |||
+ | [[ scripting: | ||
+ | [[ scripting: | ||
+ | [[ scripting: |
scripting/tutorials/level2/functions.1694251052.txt.gz · Zuletzt geändert: 2023/09/09 09:17 von fritz_98