Wintermute – Multilanguage Support
In diesem Artikel wollen wir beleuchten, welche Möglichkeiten wir haben, bequem mehrere Sprachen in unserem Wintermute-Spiel zu unterstützen.
Dabei kommen uns zwei Features der Engine zu gute, die Unterstützung von String-Tab-Dateien und das Paketsystem, d.h. das Aufteilen der Spieldateien in mehrere Pakete.
Einleitung
Da uns die Wintermute-Engine die Möglichkeit gibt, String-Tab-Dateien benutzen zu können und zudem ein einfach zu verwendendes Paketsystem mitliefert, ist es relativ einfach, ein Spiel mehrsprachig zu machen. Wir wollen uns 2 Varianten näher anschauen :
- Mehrsprachigkeit über Packages
- Sprachumschalter per In-Game Optionsmenü
1. Mehrsprachigkeit über Packages
1.1 Vorbereitung
In der ersten Variante wollen wir die Mehrsprachigkeit und das Anbieten der einzelnen Sprachen komplett über das Paketsystem und der Priorisierung der Pakete verwirklichen. Das heißt, wir liefern ein Standardsprachpaket mit dem Spiel mit, weitere Sprachpakete können dann z.B. heruntergeladen oder im Rahmen einer Lokalisierung als Sprachpaket in eine eigenständige „Landes“-Distribution des Spiels eingebunden werden. Wir wollen das nun am Beispiel zweier Sprachpakete beleuchten.
Zunächst erstellen wir ein neues WME Projekt. Als Template können wir das 2D Demo Projekt verwenden.
1.2 Pakete anlegen und priorisieren
Als nächstes legen wir 2 Pakete an, z.B. en und de. Das werden unsere Sprachpakete. In die Pakete legen wir jeweils eine string.tab Datei. Wir können diese aus dem data-Ordner kopieren. Damit wir dann eine Übersetzung sehen müssen wir noch einige Konstanten im deutschen Sprachfile übersetzen.
Nun geben wir den Paketen eine Priorität. Höhere Prioritäten überschreiben niedrige Prioritäten.
Als Standardsprache wollen wie englisch verwenden. Wir setzen also die Priorität des Paketes en auf 0. Dem Paket de geben wir die Priorität 1. Nun wählen wir in den Startup Settings unter String table die Datei aus dem Standardsprachpaket aus.
Was bedeutet das jetzt? Standardmäßig wird die String-Table aus dem Paket en geladen. Ist nun ein höher priorisiertes Sprachpaket vorhanden, wird die String-Table aus diesem Paket geladen. Wenn wir jetzt unser Projekt kompilieren, finden wir folgende kompilierte Paketdateien im Ausgabeordner:
Wenn wir jetzt das Spiel starten, sehen wir den Settings-Dialog in deutscher Sprache – da das höher priorisierte de-Paket vorhanden ist.
Wenn wir jetzt das Paket de aus dem Ordner löschen, wird das niedriger priorisierte Standardsprachpaket en verwendet.
Interessant wird die Sache, wenn wir nicht nur Text lokalisieren, sondern auch Grafiken und Sprache. Denn wir können in die Sprachpakete alle Dateien hineinlegen, die wir wollen. Höher priorisierte Pakete mit deutscher Sprachausgabe überschreiben dann z.B. das Standardsprachpaket mit englischer Sprachausgabe.
Jetzt könnten wir auf der Webseite unser Spiel in der Standardsprache und ganz einfach die zusätzlichen Sprachpakete der Lokalisierungen zum Download anbieten. Fertig.
2. Sprachumschalter per In-Game Optionsmenü
2.1 Vorbereitung
Im Gegensatz zur ersten Variante, für die keine einzige Zeile Code geschrieben werden musste, erfordert ein In-Game-Sprachumschalter einen anderen Ansatz. Hier bedienen wir uns der Möglichkeit, per Skript eine String-Table laden zu können.
Zunächst erstellen wir wieder ein neues Projekt auf Basis des 2D Demo Templates.
Dieses mal benötigen wir nur ein Package für unsere Sprachfiles. In dem Paket legen wir jeweils einen Ordner für die zur Verfügung stehende Sprache an. Dorthinein kopieren wir dann jeweils die entsprechend übersetzte string.tab-Datei und setzen eine Default-StringTable.
2.2 Erstellen der Menüs
Jetzt benötigen wir ein In-Game Optionsmenü. Dafür legen wir ein neues Windowobjekt options an.
Dieses können wir nun mittels WME-Tool WindowEdit gestalten. Zum Umschalten erstellen wir uns 2 Grafiken für RadioButton – eins für an und eins für aus. Die Grafiken tauschen wir dann entsprechend im Skript.
Jetzt benötigen wir noch einen Button im Hauptmenü (mainmenu.window), der unser Optionsmenü aufruft.
Das war es an dieser Stelle schon. Jetzt müssen wir skripten.
2.3 Scripting
Als erstes legen wir eine globale Variable lang in der Datei scripts/base.inc an.
global lang;
Als nächstes wollen wir, dass unser Optionsmenü geöffnet wird, wenn man im Hauptmenü auf den Button drückt. Dazu passen wir das Skript mainmenu.script an. Unsern Button haben wir options genannt, wir benötigen nun also eine Event-Funktion, die das neue Fenster öffnet.
on "options" { var WinOptions = Game.LoadWindow("interface\system\options.window"); WinOptions.Center(); WinOptions.GoSystemExclusive(); }
Wenn wir jetzt das Spiel starten, das Hauptmenü mit ESC aufrufen und den Button klicken, öffnet sich unser neues Menü.
Jetzt schauen wir uns das Skript für das Otionsmenü an: options.script
Initial schauen wir, welche Sprache in der globalen Variable gesetzt ist und initialisieren die RadioButtons.
this.initRadioBtn(); method initRadioBtn() { var radioBtnEn = this.GetControl("btnEn"); var radioBtnDe = this.GetControl("btnDe"); if(lang == "de") { radioBtnEn.SetImage("sprites\system\RadioBtn0.png"); radioBtnDe.SetImage("sprites\system\RadioBtn1.png"); } else { // default en radioBtnEn.SetImage("sprites\system\RadioBtn1.png"); radioBtnDe.SetImage("sprites\system\RadioBtn0.png"); } }
Wenn wir jetzt auf per RadioButton die Sprache wechseln, tauschen wir die Grafiken, setzen die globale variable und schreiben den Wert in die Registry, damit die Spracheinstellung beim nächsten Start noch wirksam ist.
// Auf Sprache en wechseln on "btnEn" { lang = "en"; var radioBtnEn = this.GetControl("btnEn"); var radioBtnDe = this.GetControl("btnDe"); radioBtnEn.SetImage("sprites\system\RadioBtn1.png"); radioBtnDe.SetImage("sprites\system\RadioBtn0.png"); Game.RegWriteString("language", lang); Game.setLanguage(lang); } // Auf Sprache de wechseln on "btnDe" { lang = "de"; var radioBtnEn = this.GetControl("btnEn"); var radioBtnDe = this.GetControl("btnDe"); radioBtnEn.SetImage("sprites\system\RadioBtn0.png"); radioBtnDe.SetImage("sprites\system\RadioBtn1.png"); Game.RegWriteString("language", lang); Game.setLanguage(lang); }
Wir haben in den Events zum Sprachwechsel eine Methode setLanguage des Game-Objekts aufgerufen. Diese müssen wir als nächstes implementieren. Dazu wechseln wir ins Skript scripts/game.script und fügen die Methode hinzu. In der Methode laden wir die String-Table aus dem ausgewählten Sprachordner. Die Inventory-Items müssen ebenfalls neu geladen werden, damit die Sprache auch dort wirksam wird.
method setLanguage(lang) { Game.LoadStringTable(lang+ "\String.tab", true); Game.LoadItems("items/items.items"); }
Der 2. Parameter der Methode LoadStringTable gibt an, ob die vorher geladenen Strings ersetzt (true) oder ergänzt (false) werden sollen.
Jetzt fehlt noch eine Sache, das initiale Setzen der Sprache beim Spielstart. Dazu erweitern wir erneut das game.script, in dem wir die Sprache aus der Registry laden und setzen. Als 2. Parameter der Methode RegReadString geben wir an, welche Sprache gesetzt werden soll, wenn noch kein Registry-Eintrag existiert.
lang = Game.RegReadString("language", "en"); this.initLanguage(); method initLanguage() { Game.LoadStringTable(lang+ "\String.tab", true); Game.LoadItems("items/items.items"); }
Jetzt haben wir alles implementiert, was wir für das Umschalten der Sprachen brauchen. Jetzt fehlt nur noch die Lokalisierung selbst.
3. Die Lokalisierung
Für beide Varianten fehlt nun noch die Lokalisierung an sich. Dazu muss einiges beachtet werden.
3.1 String-Table
Schauen wir uns zunächst einmal die mitgelieferte StringTable an. Da finden wir zunächst Einträge SYSENG0001 bis SYSENG0xxx. Diese Konstanten sind die Übersetzungen für den WME-Setup Dialog. Diese erweitern wir jetzt um einige Konstanten aus dem Menü und dem Spiel, um die Wirksamkeit unseres Sprachschalters zu erkkennen.
3.2 Verwendung der Konstanten aus den StringTables im Spiel
Um einen String im Spiel aus der StringTable holen, nutzen wir folgendes Schema:
/TAB_CONSTANTE/Standardtext oder Platzhalter
Das funktioniert direkt im Code für Funktionen zur Textausgabe, als auch in den Text- und Caption-Eigenschaften der einzelnen Objekte. Hier ein paar Beispiele.
Textausgabe im Spiel:
Game.ExpandString("/TEXT001/Textausgabe"); actor.Talk("/ACTOR001/Das wird übersetzt.");
Texte in Window-Objekten (Editor):
Texte in Window-Objekten (Code):
... STATIC { NAME="headline" CAPTION="" FONT="fonts\outline_white.font" TEXT="/OPTIONS_HEADLINE/Language" ...
Bei Items:
ITEM { CURSOR_COMBINED = TRUE CAPTION = "/ITEM_MONEY/Money" NAME = "money" ...
Im Scene Editor:
3.3 Voice-Files ausgeben
Um automatisch ein Voice-File zur String-Tab Konstante abzuspielen, müssen wir die Audiodatei so benennen, wie die zugehörige Konstante.
Beispiel:
ACTOR0001 Well, here we are.
Und wir müssen der Engine beim Spielstart mitteilen, wo die Speech-Files liegen.
Game.AddSpeechDir(lang);
Sie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen