scripting:tutorials:level1:common_errors
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
Nächste Überarbeitung | Vorherige Überarbeitung | ||
scripting:tutorials:level1:common_errors [2024/05/16 09:45] – angelegt fritz_98 | scripting:tutorials:level1:common_errors [2024/05/16 14:30] (aktuell) – [Fehler im Mapdesign] fritz_98 | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
======Häufige Fehler====== | ======Häufige Fehler====== | ||
+ | Wahrscheinlich wird dein Skript in seiner ersten Version Fehler enthalten. Damit du diese Fehler schneller einordnen und beheben kannst, sind hier Fehler gelistet, die häufig entstehen. Bei jedem Fehlertyp steht auch beschrieben, | ||
====Syntaxfehler==== | ====Syntaxfehler==== | ||
- | ====Groß/ | + | Syntaxfehler sind Fehler, bei denen dein Skript gegen die " |
+ | |||
+ | Einige Beispiele: | ||
+ | |||
+ | ===Das schließende Anführungszeichen fehlt=== | ||
+ | <code lua> | ||
+ | Message(" | ||
+ | </ | ||
+ | Die Fehlermeldung: | ||
+ | < | ||
+ | unfinished string near `" | ||
+ | </ | ||
+ | |||
+ | ===Falsch verwendete Schlüsselwörter=== | ||
+ | <code lua> | ||
+ | if IsDead(" | ||
+ | Victory() | ||
+ | end | ||
+ | </ | ||
+ | Die Fehlermeldung: | ||
+ | < | ||
+ | `then' expected near `do' | ||
+ | </ | ||
+ | |||
+ | ===Komma im Table vergessen=== | ||
+ | <code lua> | ||
+ | local Briefing = { | ||
+ | { | ||
+ | title = " | ||
+ | text = " | ||
+ | position = GetPosition(" | ||
+ | } | ||
+ | |||
+ | { | ||
+ | title = " | ||
+ | text = "Herr, mir scheint, Ihr habt da ein Komma vergessen!", | ||
+ | position = GetPosition(" | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | Die Fehlermeldung: | ||
+ | < | ||
+ | expected (to close `{' at line 833) near `{' | ||
+ | </ | ||
+ | |||
+ | Achte auf die Zeilenangabe im Debugger und die roten Markierungen in VSC! | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ====Groß-/ | ||
+ | |||
+ | Für Variablennamen wird zwischen Groß- und Kleinschreibung unterschieden. Sich da zu vertippen, wird Fehler verursachen. Zum Beispiel: | ||
+ | <code lua> | ||
+ | function FirstMapAction() | ||
+ | MyCounter = 1 | ||
+ | IncreaseMyCounter() | ||
+ | end | ||
+ | |||
+ | function IncreaseMyCounter() | ||
+ | MyCounter = Mycounter + 1 | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Die Fehlermeldung sieht dabei so aus: | ||
+ | < | ||
+ | attempt to perform arithmetic on global `Mycounter' | ||
+ | </ | ||
+ | |||
+ | Sie drückt damit aus, dass versucht wurde mit einer globalen Variable namens '' | ||
+ | |||
+ | Etwas Ähnliches kann dir auch mit Funktionsnamen passieren: | ||
+ | <code lua> | ||
+ | function FirstMapAction() | ||
+ | MyCounter = 1 | ||
+ | IncreaseMyCounter() | ||
+ | end | ||
+ | |||
+ | function InCreaseMyCounter() | ||
+ | MyCounter = MyCounter + 1 | ||
+ | end | ||
+ | </ | ||
+ | Die Fehlermeldung: | ||
+ | < | ||
+ | attempt to call global `IncreaseMyCounter' | ||
+ | </ | ||
+ | Also wurde in dem Fall versucht, eine nicht existierende Funktion aufzurufen. | ||
+ | |||
+ | Derartige Fehler werden in Visual Studio Code **gelb** unterstrichen. Wenn du mit der Maus über eine gelb hervorgehobene Variable fährst, sollte '' | ||
+ | |||
+ | ===Spezialfall: | ||
+ | |||
+ | In SimpleJobs, wie beispielsweise für [[ scripting: | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ====Copy & Paste==== | ||
+ | |||
+ | Fehler, die durch Copy & Paste entstehen, kommen selbst bei erfahrenen Programmierern immer wieder vor. Sie haben dabei nicht notwendigerweise eine Fehlermeldung zur Folge, sondern resultieren in unerwartetem Verhalten des Spiels. Oft vergisst man, notwendige Änderungen am kopierten Code vorzunehmen. | ||
+ | |||
+ | Angenommen, du hast wie im Tutorial beschrieben, | ||
+ | <code lua> | ||
+ | function VictoryCondition() | ||
+ | if IsDead(" | ||
+ | Victory() | ||
+ | return true | ||
+ | end | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | Weil die '' | ||
+ | <code lua> | ||
+ | function DefeatCondition() | ||
+ | if IsDead(" | ||
+ | Defeat() | ||
+ | return true | ||
+ | end | ||
+ | end | ||
+ | </ | ||
+ | Im Spiel hätte das zur Folge, dass der Spieler nicht verliert, wenn sein Haupthaus fällt. Außerdem kann es passieren, dass die Niederlagemeldung angezeigt wird, wenn er das feindliche Haupthaus zerstört hat. | ||
+ | |||
+ | Anderes Beispiel: Du möchtest zwei gleich starke KI-Spieler für Spieler 2 und Spieler 3 definieren: | ||
+ | <code lua> | ||
+ | MapEditor_SetupAI(2, | ||
+ | MapEditor_SetupAI(2, | ||
+ | </ | ||
+ | In diesem Beispiel wird Spieler 3 nichts machen, weil vergessen wurde, den ersten Parameter mit der Spieler-Id zu ändern. Die Funktion prüft, ob an der angegebenen Position ein Gebäude des angegebenen Spielers steht. Ist das nicht der Fall, bricht die Funktion ab. | ||
+ | |||
+ | Fehler durch Copy & Paste können vermieden werden, indem weniger Code dupliziert wird. Überlege dir, wie du dein Skript formulieren kannst, ohne dich allzu oft zu wiederholen. | ||
+ | |||
+ | \\ | ||
====Variablennamen und Strings==== | ====Variablennamen und Strings==== | ||
- | ====Copy/Paste==== | + | Es kann zu Beginn schwer fallen, Variablennamen und Strings zu unterscheiden, |
+ | |||
+ | Beispielsweise kannst du für jeden einzelnen KI-Spieler eine Funktion definieren, in der die Parameter für diesen KI-Spieler definiert werden: | ||
+ | <code lua> | ||
+ | function CreatePlayer2() | ||
+ | -- ... | ||
+ | end | ||
+ | function CreatePlayer3() | ||
+ | -- ... | ||
+ | end | ||
+ | function CreatePlayer4() | ||
+ | -- ... | ||
+ | end | ||
+ | </ | ||
+ | So aufgebaut ist es können die Funktionen **nicht** in einer Schleife aufgerufen werden, also z.B: | ||
+ | <code lua> | ||
+ | for i = 2, 4 do | ||
+ | CreatePlayer .. i() | ||
+ | end | ||
+ | </code> | ||
+ | Die '' | ||
+ | |||
+ | \\ | ||
====Funktionsname und Funktionsaufruf==== | ====Funktionsname und Funktionsaufruf==== | ||
+ | |||
+ | An verschiedenen Stellen ist es notwendig, Funktionen anzugeben, die beispielsweise als Reaktion auf ein bestimmtes Ereignis ausgeführt werden sollen. Ein häufig auftretendes Anwendungsbeispiel hierfür ist der '' | ||
+ | |||
+ | Die **Zuweisung** einer solchen Funktion darf nicht verwechselt werden mit dem **Aufruf** einer Funktion, der über sich öffnende und schließende Klammern definiert ist. Ein Beispiel: | ||
+ | <code lua> | ||
+ | -- Wir definieren eine Funktion, die eine Entity mit dem Skriptnamen " | ||
+ | -- einer Entity mit dem Skriptnamen " | ||
+ | -- diesem Beispiel " | ||
+ | function MoveDarioToHQ() | ||
+ | Move(" | ||
+ | end | ||
+ | </ | ||
+ | Vergleiche nun die folgenden beiden Briefings: | ||
+ | <code lua> | ||
+ | -- Variante 1 | ||
+ | function CreateBriefingMentor() | ||
+ | local Briefing = { | ||
+ | { | ||
+ | title = " | ||
+ | text = " | ||
+ | position = GetPosition(" | ||
+ | }, | ||
+ | |||
+ | finished = MoveDarioToHQ | ||
+ | } | ||
+ | StartBriefing(Briefing) | ||
+ | end | ||
+ | </ | ||
+ | und | ||
+ | <code lua> | ||
+ | -- Variante 2 | ||
+ | function CreateBriefingMentor() | ||
+ | local Briefing = { | ||
+ | { | ||
+ | title = " | ||
+ | text = " | ||
+ | position = GetPosition(" | ||
+ | }, | ||
+ | |||
+ | finished = MoveDarioToHQ() | ||
+ | } | ||
+ | StartBriefing(Briefing) | ||
+ | end | ||
+ | </ | ||
+ | |||
+ | In Variante 1 wird Dario nach dem Briefing zu seinem Haupthaus gehen. In Variante 2 wird Dario **direkt zu Beginn** des Briefings zum Haupthaus gehen. Das liegt daran, dass im '' | ||
+ | |||
+ | \\ | ||
====Funktion nicht aufgerufen==== | ====Funktion nicht aufgerufen==== | ||
+ | |||
+ | Achte darauf, dass du definierte Funktionen auch an der korrekten Stelle aufrufst. Andernfalls kann der Questablauf unterbrochen werden, weil dafür notwendige Aufrufe nicht stattgefunden haben. Unbenutzte Funktionen werden in VSC nicht angezeigt. | ||
+ | |||
+ | **Tipp**: Unbenutzte //lokale// Variablen werden in VSC blasser dargestellt und sind daher leicht zu finden. | ||
+ | |||
+ | \\ | ||
====SimpleJob nicht beendet==== | ====SimpleJob nicht beendet==== | ||
+ | |||
+ | SimpleJobs werden ab ihrem Start so lange jede Sekunde ausgeführt, | ||
+ | |||
+ | Ein Beispiel: Sobald Dario sich seiner Burg nähert, soll ein Briefing abgespielt werden: | ||
+ | <code lua> | ||
+ | function FirstMapAction() | ||
+ | StartSimpleJob(" | ||
+ | end | ||
+ | |||
+ | -- Das Setup hier ist das gleiche wie beim Beispiel oben zu Funktionsnamen und Funktionsaufrufen | ||
+ | function IsDarioNearHQ() | ||
+ | -- Die Funktion IsNear prüft, ob die beiden Entities höchstens die angegebene Distanz zueinander haben | ||
+ | -- Der SimpleJob fragt also jede Sekunde, ob " | ||
+ | if IsNear(" | ||
+ | -- Ist das der Fall, soll ein Briefing gestartet werden | ||
+ | CreateBriefingDario() | ||
+ | end | ||
+ | end | ||
+ | </ | ||
+ | In diesem Beispiel wird das Briefing gestartet, sobald sich Dario der Burg nähert. Dadurch, dass der Job nie mit '' | ||
+ | |||
+ | \\ | ||
====Parameter verwechselt==== | ====Parameter verwechselt==== | ||
+ | |||
+ | Jedes mal, wenn du Argumente an eine Funktion übergibst, solltest du dir klar machen, in welcher Reihenfolge diese zu übergeben sind. Wenn du [[ scripting: | ||
+ | |||
+ | Leider sind die Parameter in Siedler 5 - Funktionen nicht konsistent definiert. So gibt es zum Beispiel die Funktionen | ||
+ | <code lua> | ||
+ | -- Gib Spieler _PlayerId _Amount Gold-Einheiten | ||
+ | AddGold(_PlayerId, | ||
+ | |||
+ | -- Verbiete Spieler _PlayerId die Technologie _Technology | ||
+ | ForbidTechnology(_Technology, | ||
+ | </ | ||
+ | |||
+ | Bei der einen Funktion steht die '' | ||
+ | <code lua> | ||
+ | AddGold(500, | ||
+ | </ | ||
+ | Das drückt aus, dass du Spieler mit der Id 500 (existiert nicht im Spiel) 2 Gold geben möchtest. Da das nicht möglich ist, wird der Funktionsaufruf wirkungslos bleiben. | ||
+ | |||
+ | Leicht falsch zu bedienen sind Funktionen, die viele Parameter anbieten, wie '' | ||
+ | <code lua> | ||
+ | -- Geplant ist, eine KI der Stärke 2 mit Technologiestufe 0 zu erstellen | ||
+ | MapEditor_SetupAI(2, | ||
+ | </ | ||
+ | Hier wurden die Argumente für '' | ||
+ | |||
+ | \\ | ||
====Logikfehler==== | ====Logikfehler==== | ||
- | ====KI ist inaktiv==== | + | Logikfehler bedeuten, dass du zwar aus programmiertechnischer Sicht alles richtig gemacht hast, im Spiel aber nicht das passiert, was du möchtest. Diese Fehler sind schwieriger zu beheben, da man sich zuvor einen Überblick über das gesamte Skript und den dazugehörigen [[ scripting: |
+ | |||
+ | Beim Ausmerzen von Logikfehlern zahlt es sich aus, im Voraus einen möglichst konkreten Plan ausgearbeitet und [[ scripting: | ||
+ | |||
+ | \\ | ||
+ | |||
+ | ====Fehler im Mapdesign==== | ||
+ | |||
+ | Fehler können auch im Mapdesign geschehen. Vor allem Blocking an der falschen Stelle kann den Mapablauf empfindlich stören, beispielsweise: | ||
+ | * Eine KI rekrutiert Truppen, greift aber trotz feindlicher Gesinnung den Spieler nie an. Häufig ist die Ursache, dass das Gelände auf dem Weg zum Spieler blockiert ist, die KI also gar nicht zu ihm gelangen kann | ||
+ | * Rohstoffschächte sind durch Texturen, Terrainhöhe oder Felsen blockiert, sodass Leibeigene nicht daran arbeiten oder Minengebäude nicht errichtet werden können | ||
+ | * Große Teile des für den Spieler vorbereiteten Bauplatzes können ebenfalls durch Blocking von seiner Startposition getrennt sein und die Map so ungleich schwieriger oder gar unmöglich zu schaffen machen | ||
+ | |||
+ | Für solche Fehler, die nur im Editor behoben werden können, ist das Grid (Shortcut Ctrl + G) das wichtigste Werkzeug. Mit aktiviertem Grid wird blockiertes Terrain rot dargestellt. Halte Ausschau nach Terrainhöhen, | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Zu guter Letzt beschäftigen wir uns im nächsten Kapitel mit dem Balancing einer Karte. | ||
+ | |||
+ | [[ scripting: | ||
+ | [[ scripting: | ||
+ | [[ scripting: |
scripting/tutorials/level1/common_errors.1715852707.txt.gz · Zuletzt geändert: 2024/05/16 09:45 von fritz_98