Samstag, 7. Juni 2014

global.lua - Helperfile für oft wiederkehrende Codestellen

Voraussetzung: "Der Einstieg in lua“
Es gibt so manche Aufgaben, die einem ziemlich oft bei der Programmierung begegnen, bzw. man denkt "Diesen Teil müsste man doch abkürzen" können.
So ist z.B die Ausgabe eines Textes mit oder ohne Bild eine recht komplexe Sache wenn man die MessageBox direkt in lua schreiben möchte.
Vorallem wenn nach dem Klick auf OK noch eine weitere Aktion folgen soll.

Auch das Ersetzen von Variablen in Strings (z.B. bei der Übersetzung deines Cartridges in verschiedene Sprachen ist eine Sache, die man nicht bei jedem neuen Wherigo neu schreiben möchte.

Abbildung 1: Einbinden des globales Codes
Zu diesem Zwecke habe ich mir angewöhnt eine global.lua Datei anzulegen, die ich im überordneten Ordner aller Wherigo liegen habe und die von jedem WIG-Projekt genutzt werden kann.
Ein Beispiel:
  • Im Ordner C:\Wherigos liegt die Datei global.lua
  • Im Ordner C:\Wherigo\MeinTestWherigo liegt dann die Projektdatei test.urwigo
  • Im Ordner C:\Wherigo\MeinZweiterWherigo liegt dann entsprechend zweiterWIG.urwigo
Beide Cartridges, sowohl test.urwigo als auch zweiterWIG.urwigo verwenden global.lua aus dem übergeordneten Ordner


Abbildung 2: Auszug aus _cartridge.lua (enthalten im gwz Archiv)
Beim "Bauen" des cartrigdes bzw. beim Erstellen des gwz Archives spielt der Pfad dann keine Rolle mehr, da der Inhalt der externen lua-Datei in die _cartridge.lua hineinkopiert wird

Abbildung 3: Boolean als Text oder Zahl
Nun aber zu den Methoden an sich. Den Anfang machen die Boolean Werte. Dabei ist es mir für debug Zwecke oft hilfreich, wenn der Wert als Zahl oder String zurückgegeben wird, da eine Konkatenation in lua mit verschiedenen Datentypen Probleme bereitet.
"Raetsel 1 geloest: " .. myBoolVar führt zu einem Laufzeitfehler da hier string und boolean nicht miteinander verknüpft werden kann.
"Raetsel 1 geloest: " .. bts(myBoolVar) hingegen funktioniert, da nun zwei Strings verknüpft werden. Die Ausgabe lautet dann "Raetsel 1 geloest: true"
Dass getBoolAsString als bts (boolToString) abgekürzt ist bzw. dass es mal value und mal condition heißt ist historisch gewachsen. Kein guter Stil, wie ich zugeben muss, aber eine Methode umbenennen wird im nachhinein schwierig, da man auch alle Aufrufe der Methode in zahlreichen Wherigo-Projekten anpassen muss.
Also lieber gleich sinnvolle Namen verwenden.

Die dritte Methode wählt zufällig true bzw. false, abhängig von einer Wahrscheinlichkeit.
Bsp: Bei meinem Fußball-Wherigo Heimspiel soll die gegnerische Mannschaft nur in einem von drei Fällen ein Tor schießen.
getRandomBool(33) löst diese Aufgabe. math.random(100) liefert eine Ganzzahl zwischen 1 und 100, also 5, 41, 87 ...
Ist diese Zahl kleiner als unsere Vorgabe 33 wird true zurück geliefert, ansonsten false. Korrekterweise müsste es kleiner gleich heißen, da nicht von 0 bis 99 sondern von 1 bis 100 gezählt wird.


Abbildung 4: Ausgaben vereinfachen
Im zweiten Block geht es um die Ausgabe in Form von MessageBoxen. Da die ersten drei Methoden nur Convenience-Wrapper für die vierte sind, beginnen wir auch bei letzerer in Zeile 38.
Hier wird eine MessageBox aufgebaut, die mit dem übergebenen Text m und einem optionalen Bildchen med gefüllt wird.
Als Callback wird der Teil bezeichnet, der ausgeführt werden soll, wenn der Spieler auf OK gedrückt hat.
Hier wird es jetzt spannend. Lua unterstützt nämlich hier das Konstrukt einer "closure". D.h. es wird eine Methode cf definiert (Zeile 35), die erst dann ausgeführt wird, wenn der MessageBox danach zumute ist.
Woraus besteht aber die Methode cf? Zunächst hat sie einen Parameter action. Ist dieser Parameter null, so geschieht ... rein gar nix. Ich konnte diesen Fall noch nie beobachten. Wahrscheinlich ein Sicherheitscheck, falls man die MessageBox nicht mit "OK", sondern mit dem Back-Button des Smartphones verlässt.
Ruft hingegen die MessageBox die Methode cf(anAction) mit einem Not-Null-Parameter auf, so wird die zweite innere Methode fun (wieder eine closure) ausgeführt.
Was aber ist denn fun ? fun wird von außen definiert, z.B. in Zeile 29, wo der Befehl "Zeige Mainscreen" übergeben wird. Auch hier gilt, in Zeile 29 wird Wherigo.ShowScreen(Wherigo.MAINSCREEN) nur definiert, aber noch nicht ausgeführt. Dies passiert erst, wenn der Spieler in der MessageBox (z.B. "Gehe nun zum Final") auf "OK" drückt.
Achtung: Vergesst nicht bei der Definition der Methode die Schlüsselwörter function() und end. Ansonsten habt ihr keine closure definiert, sondern es wird direkt der Mainscreen angezeigt!
Jetzt wird sich der gewiefte Leser/Entwickler denken "Wozu brauche ich den action Parameter?". Dieser dient theoretisch dazu weitere Informationen an die aufrufende Methode zu übergeben. Man könnte ne Zahl oder einen String reinschreiben. Trotz längerer Studie des von Urwigo kompilierten Codes konnte ich aber stets nur den action ~= nil Vergleich finden.
Man kann allerdings einer MessageBox mehrere Buttons geben und damit einen Quasi-Input generieren. Über action (enthält "Button1" bzw. "Button2") kann man dann unterscheiden welcher Button gedrückt wurde. Ein sinnvolles Szenario wäre "Du bist an der Zone Goldbergwerk angekommen. Die bereits abgebauten Goldklumpen wandern hiermit in dein Inventar", Button1 = "OK", Button2 = "Nachricht zukünftig nicht mehr anzeigen"

Abbildung 5: Debug-Ausgaben, Wegpunkt-Mittelung und String-Operationen
Nun aber genug der komplexen closure-Theorie. Zum Abschluss etwas leichtere Kost.
calcCenterZonePoint liefert euch die GPS-Koordinate, die genau zwischen point1 und point2 liegt. Ist ganz praktisch um die Hälfte der Laufstrecke oder den Mittelpunkt eines Fußballfeldes zu bestimmen.
printTable gibt beim debuggen den Wert einer Tabelle aus. Da jedes "Objekt" in lua als Tabelle definiert ist, kann das schon mal ganz hilfreich sein.
Die Werte einer Zone (Name, Koors, ob aktiv oder nicht...) sind ebenfalls als Tabelle gespeichert und können über getmetatable() abgerufen werden. Als Ergebnis seht ihr beim Debuggen alle Infos über eure Zone.

Zum Schluss noch ein Beispiel für Substitution. Hier wird in einem String "Gehe zur Zone #1# und warte", "Schmiede" der Wert "Gehe zur Zone Schmiede und warte" gebildet. Hilfreich bei Mehrsprachigkeit eures Wherigos.

1 Kommentar:

  1. Wäre es möglich, dass du deine global.lua veröffentlichst um Tipparbeit zu sparen?

    AntwortenLöschen