Variablen und Objekte

Originalversion: metamorphium
Datum: 21. 8. 2005
Voraussetzung: Installiertes WME Development Kit
Deutsche Übersetzung: Bernhard Ungerer aka Sumoraner (25.09.2008)

Willkommen zu meinem ersten Tutorial. Es beschreibt die Arbeit mit Variablen und Objekten in der WME-Scriptsprache. Da dieses Thema essenziell für die Spieleerstellung ist starte ich mit etwas Theorie.

Lass es mich zuerst einfach erklären: Stell dir vor Variablen sind eine Art Container, geschaffen um Informationen darin abzulegen. Welche Art von Informationen du darin sammelst bleibt dabei ganz dir überlassen. WME-Script ist diesbezüglich sehr anspruchslos, darum stellt es dir universelle Variablen zur Verfügung, in denen du speichern kannst was du möchtest (in der Computerterminologie nennt sich das "dynamischer Typ"). Wir werden dies nun einmal näher betrachten. Starte deinen WME Project Manager und erstelle ein neues Projekt. Meines nenne ich ObjectsTutorial.

Wie du siehst gibt es im Ordner Scenes eine neue Szene namens Room. Starte gleich mal das neue Projekt mit F5. Es wird ein grüner Bildschirm mit Molly in der Mitte angezeigt. Mit Alt+F4 schließt du das Fenster auch gleich wieder und schon können wir daran arbeiten. Gehe in dein Projekt-Verzeichnis und öffne die Datei scene_init.script, zu finden in data/scenes/Room/scr/scene_init.script.

Eine Variable wird entweder mit var oder Global deklariert. Dies bestimmt den Bereich, in dem eine Variable gültig ist. Mehr dazu später.

Ignoriere erst mal, was in der Datei bereits eingetragen ist und füge folgenden Code direkt unter der Zeile #include "base.inc" ein:

var my_variable;      //Die erste lokale Variable ist deklariert

Ich sprach davon, dass es nur einen einzelnen Variablentyp gibt in dem du alles ablegen kannst, was du in deinem Script benötigst. Das werden wir gleich einmal ausprobieren. Ach ja, füge ab sofort alle Beispiele am Ende der Datei scene_init.script ein, dadurch wird diese größer und größer und du erhältst eine schöne Referenz in der du bei Bedarf nachschlagen kannst.

my_variable = 1;                   // Zuerst erhält unsere Variable einen Zahlenwert 
my_variable = my_variable * 500;   // Damit eine nummerische Operation anwenden 
Game.Msg(my_variable);             // Den Wert der Variable (eine Zahl) ausgeben 
 
my_variable = "Hallo Welt";        // Nun weisen wir unserer Variable Text zu 
Game.Msg(my_variable);             // Zugewiesenen Text aus der Variable ausgeben

Wenn du diesen Test ausführst kannst du sehen, dass alles prächtig funktioniert. Eine Variable kann jeden Werttyp enthalten kann, den du ihr zuweist. Ausserdem kannst du den enthaltenen Typ, der in deiner Variablen abgelegt ist, jederzeit ändern. Da du dies nun weißt gehen wir gleich zu etwas anspruchsvollerem über: Arrays.

Im Grunde ist ein Array ein Feld aus (gleichnamigen) Variablen und unterstützt uns bei der Zugriffs-Automation. Um diesen Job zu verdeutlichen verwenden wir erneut unsere nette Variable von eben. Hier also der schnelle (nicht objektorientierte) Weg ein einfaches Array zu erzeugen:

// Jede Variable wird durch eine Zahl, beginnend bei 0, indexiert  
// Das solltest du dir unbedingt merken 
my_variable[0] = "Heute ist Mittwoch";  
my_variable[1] = "Morgen ist ebenfalls Mittwoch";  
my_variable[2] = "Jeden Tag ist Mittwoch";

Nun könnten wir Game.Msg(my_variable[0]); usw. verwenden um den Inhalt der Variablen auszugeben, wir gehen jedoch den eleganteren Weg und erstellen hierfür eine Programmschleife:

for (var a = 0; a < 3 ; a = a+1) 
{ 
  Game.Msg(my_variable[a]); // Index [a] der Variable erhält, Dank der **for**  
                            // Schleife, als Wert eine Zahl von 0 bis 2 
}

Du kannst das Gelernte jetzt erneut ausprobieren, indem du das WME-Projekt ausführst. Sobald du zurück kommst, werden wir ein komplexeres Thema behandeln.

…™

Ok. Du bist offensichtlich wieder zurück und ich gehe davon aus, du Bescheid weißt wie diese wichtigen Dinge funktionieren, darum gleich weiter im Text. Zu Beginn sprach ich kurz über die beiden Schlüsselworte varund global. Das sind wichtige Schlüsselelemente für das erfolgreiche Erstellen von Scripten. Grundsätzlich deklarierts du durch Verwendung dieser beiden Schlüsselworte den Gültigkeitsbereich einer Variable. Die lokale Variable ist in einem einzigen Script gültig → jenen, in dem du sie deklarierst. Die Gültigkeit der globalen Variable reicht über das gesamte Spiel. Wenn du möchtest, dass sich dein Spiel später daran erinnert, was in einem Script vorgefallen ist, dann musst du eine globale Variable verwenden. Wir werden dies in einem Beispiel näher betrachten.

Öffne das Script mit dem Namen game.script, zu finden in in data/scripts und füge unter den "Include"-Zeilen folgenden Code ein:

  global my_global = "Hi, ich bin deine globale Variable!";

Gehe dann zurück zu scene_init.script und ergänze folgendes:

global my_global; 
Game.Msg(my_global);

!!Das ist wichtig!! Wenn du globale Variablen verwenden möchtest, MUSST du diese in jedem Script deklarieren, in dem sie vorkommen. Andernfalls wird es nicht funktionieren und es kommt zu Fehlermeldungen während des Kompilierens. Gleich werde ich dir erläutern, wie ich mit globalen Variablen umgehe.
Also, für die Akten: Wir erstellten eine globale Variable in game.script und vergaben dafür einen Wert. Dann gaben wir diesen Wert über die Datei scene_init.script am Bildschirm aus. Die Verwendung von globalen Variablen ist der einzige Weg dies zu erreichen. Andererseits muss eine globale Variable über das gesamte Spiel hinweg einzigartig sein. Wenn du var verwendest, kann z.B. die Variable test in jedem einzelnen Script vorkommen. Mach das nicht, wenn du eine globale Variable mit diesem Namen verwendest. Ich habe in der Vergangenheit schon einige WME-Projekte debugged, da kam es auch zu diesem Fehler: Globale Variablen wurden durch lokale Variablen mit dem selben Namen überschrieben. Versuche deinen Code, so gut es geht, sauber zu halten. Die Chancen, dass dein Projekt dadurch schnell fertig gestellt werden kann, steigen rapide an.

Ok, ich versprach dir zu erklären, wie ich Globale in meinen Projekten organisiere. Es ist so eine Art Hassliebe, also kann es dir entweder helfen, oder du wirst es nie verwenden. Es liegt ganz an dir. Und so gehts: Im Ordner data/scripts findest du die Datei base.inc. Diese Datei wird in jedem einzelnen Script deines Spiels eingebunden. Ich erstelle nun eine Gruppe eindeutig benannter inc-Dateien und füge alle Globale hier ein. Dann binde ich diese Dateien (mittels Include-Befehl) in base.inc ein und bin damit sicher später keine Probleme bei der Suche nach meinen Variablen zu haben. Laß uns nun unsere einfache globale Variable an dieses neue Schema anpassen.

Als Beispiel erstelle im Ordner data/scripts eine neue Datei mit dem Namen test.inc und gib dort diese eine Zeile ein:

global my_global; //Initialisiere niemals einen Wert in einer Include-Datei! Dies würde  
//in jedem geladenen Script zu einer ständigen Neunitialisierung der Variable führen 
//und dir mächtig Kopfschmerzen bereiten.

Nun füge in der base.inc-Datei eine Zeile ein, die da lautet

#include "scripts\test.inc"

In game.script entferne das Schlüsselwort global aus der Zeile global my_global = "Hi, ich bin deine globale Variable!";. Als nächstes entferne global my_global; aus scene_init.script, andernfalls bricht dein Spiel mit einem Script-Compiler-Fehler ab (das wäre eine doppelte Definition).

Dies beendet die Beschreibung des Verfahrens, wie ich mit Globalen umgehe und diese klar organisiert und nachvollziehbar halte. Ebenfalls kann ich so niemals eine bereits definierte Variable in einem Script überschreiben. Dies würde, da die original Variable bereits eingebunden ist, zu einem Script-Compiler-Fehler führen.

Aber … wir sind noch nicht fertig. Nun gehen wir zu einem wirklich großen Feld der WME-Variablen über - Objekte. Beginnen wir mit einem einfachen Beispiel um zu verstehen, wie man diese verwendet: Stell dir vor, du hast eine Szene mit einem wunderschönen Schmetterling darin. Dieser Schmetterling hat eine X- und Y-Position auf dem Bildschirm, einen Namen und z.B. einen Merker (Flag) welcher angibt, ob er sichtbar ist oder nicht. Auf dem herkömmlichen Weg müssten wir vier einzelne Variablen deklarieren, bei denen wir nicht den Überblick verlieren dürften. Nicht so bei WME! Hier können wir dafür Objekte verwenden.

Gehe zurück zu scene_init.script und füge noch etwas mehr hinzu:

var butterfly; // Das kennen wir bereits 
 
// Nun beginnt der Spaß: 
butterfly.X = 100; 
butterfly.Y = 200; 
butterfly.Name = "Wunderschöner Schmetterling"; 
butterfly.Active = false;

Wenn wir jetzt unseren Favoriten Game.Msg(butterfly); ausprobieren erscheint auf dem Bildschirm das Wort "[object]". Dies ist ein Zeichen dafür, dass unsere Bemühung, das benötigte Objekt zu erstellen, erfolgreich war. Um nun Zugriff auf die enthaltenen Werte zu erhalten und diese anzuzeigen verwenden wir

Game.Msg(butterfly.X); 
Game.Msg(butterfly.Y); 
Game.Msg(butterfly.Name); 
Game.Msg(butterfly.Active);

Beachte, dass die boolschen Werte True/False von Game.Msg() in Yes/No (Ja/Nein) interpretiert werden, doch du kannst diese auf herkömmliche Weise mit if ( butterfly.Active ) oder if (! butterfly.Active ) Konstrukten abfragen.

Glaube mir, die Organisation mit Objekten hilft dir, dich auch in fünf Monate alten Scripts noch zurecht zu finden und eventuelle Fehler darin aufzuspüren.

Zuletzt noch etwas fortgeschrittenes für die maximale Verwendung von Objekten. WME unterstützt nicht den Funktionsaufruf von einem Script in einem anderen. Doch es unterstützt den Funktionsaufruf von Objekten. Diese Funktionen heißen Methoden und sind Bestandteil von Script-Dateien. Wir verschieben nun unser Schmetterling-Beispiel auf eine höhere Ebene. :-)

Erstelle als erstes im Ordner scr deines Raums eine Datei mit dem Namen butterfly.script und füge hier folgendes ein:

method HelloButterfly() 
{ 
   Game.Msg(this.Name); 
}

Gehe dann zurück zu scene_init.script und ändere var butterfly; zu

var butterfly = new Object("scenes/Room/scr/butterfly.script");

Damit werden alle Methoden die in butterfly.script deklariert wurden mit unserer Variablen (nun ein Objekt) verbunden. Zuletzt können wir nun diese neue Funktionalität testen, indem du folgendes nach dem Schmetterlings-Teil im Script einfügst:

butterfly.HelloButterfly();

Beim Testlauf unseres Tutorial-Projekts sehen wir, dass es richtig Spaß macht mit Objekten zu arbeiten und früher oder später wirst du sie lieben lernen. Sie helfen dabei dein Projekt sauber zu halten und wenn du lernst sie richtig einzusetzen ersparst du dir jede Menge Stress. Ich hoffe, dass dir dieses Tutorial gefallen und geholfen hat dieses Basiswissen im Umgang mit WME-Scripts zu verstehen.