Ich arbeite in meiner Freizeit viel an meinem Phaser Adventure. Und so ein Adventure besteht natürlich auch aus einer Story mit vielen Texten. Nun stand ich vor dem Problem, eine allgemein gültige Lösung für Textboxen zu finden. Aus dieser Not heraus, entstand letztendlich eine dynamische Textbox Klasse, die ich gerne mit dir teilen möchte.
Demo & Code
Im folgenden CodePen siehst du nicht nur wie das Ganze letztendlich bei mir aussieht, sondern kannst dir auch den JavaScript Code ansehen, den ich dafür entwickelt habe. Im „Babel“ Tab kannst du ganz einfach die Variablen BOX_WIDTH
und EXAMPLE_TEXT
anpassen, um die dynamische Textbox zu verändern.
Schau dir den Code von Nick (@NickHatBoecker) auf CodePen an.0
Das Problem
Als ich mit der Umsetzung angefangen habe, hatte ich mir zunächst einmal eine statische Textbox Grafik, in einer festen Höhe und Breite, abgelegt. Damit stößt man allerdings ziemlich schnell an seine Grenzen, denn jeder Text beziehungsweise Inhalt muss perfekt auf diese Maße angepasst werden. Am Ende muss man dann den eigentlich stimmig ausgewählten Dialog-Text ändern, statt dass die Box sich einfach an die Länge des Textes anpasst.
Die Lösung
Du willst nicht nur kopieren & einfügen? Dann kommt hier jetzt eine kleine Erklärung zu dem CodePen von oben.
Der Einfachheit halber wollte ich ein Objekt für meine dynamische Textbox, welches ich beliebig in Phaser Szenen einfügen kann. Daher habe ich eine neue Klasse namens DynamicTextbox deklariert.
Container / constructor()
Die neue Klasse erbt ihre Eigenschaften von der Phaser Container Klasse. Das ist hilfreich um die Textbox später inklusive Hintergrund und Text im Canvas zu positionieren.
Im Konstruktor der Klasse wird zunächst der Text generiert. Das ist wichtig, damit die Box ihre Höhe an den bestehenden Text anpassen kann. Erst dann wird der Box-Hintergrund inklusive Rahmen generiert. Danach sind alle Maße der dynamischen Textbox bekannt, sodass sie mittels setPosition
und den mitgelieferten Koordinaten positioniert werden kann. Aus Darstellungszwecken überschreibe ich diese Position in der create
Methode allerdings, um die Box im Canvas zu zentrieren.
Text / _initText()
Für die Textbox müssen wir zuerst den Text generieren. Das ist wichtig, damit sich der Boxhintergrund und der -Rahmen an den Text anpassen können. Damit der Text nicht direkt am Box-Rahmen klebt, definieren wir ein Padding (das kennst du vllt schon von der Programmierung mit CSS). Deshalb setzen wir die X
und Y
Koordinaten jeweils auf den Padding-Wert. Als nächstes kümmern wir uns um den automatischen Umbruch. Damit der Text nicht in einer Zeile aus der Box hinaus läuft, geben wir in dem TextStyle
Objekt eine Breite namens width
mit. Diese gibt an, ab welcher Breite der Text in die neue Zeile übergehen soll. Nun könnte man ja einfach die Breite der gesamten Box nehmen. Dann würde der Text aber im schlimmsten Fall wieder aus der Box heraus laufen, weil in dieser Breite das Padding nicht enthalten ist. Der Text soll also umbrechen, wenn er die Breite der Box; minus das Padding links; minus das Padding rechts erreicht hat. Also width - (padding * 2)
.
Box / _initBox()
Anders als in der Webentwicklung, wo eine Box nicht mehr als ein div
Element ist, dem wir mittels CSS Eigenschaften zuweisen, besteht die umgesetzte Textbox aus mehreren Grafiken/Elementen.
Das erste Element ist ein Rechteck, welches einfach nur als Hintergrundfarbe für unsere Box dient, auf der später der Text zu lesen ist. Dazu kommen insgesamt acht Sprites, die den Textbox-Rahmen formen. In der preload()
Funktion habe ich diese Sprites als Spritesheet geladen. Das Spritesheet besteht aus neun 16×16 Sprites, wobei wir den Sprite in der Mitte auslassen. Man hätte ihn aber auch anstelle des Rechtecks als Hintergrund verwenden können.
Die äußeren vier Ecken sind vermutlich selbst erklärend. Die obere linke Ecke ist in der Koordinate 0x0
positioniert. Die rechte obere Ecke wird ans Ende der Box gesetzt. Dazu wird die Breite des Sprites, also 16px, von der Gesamtbreite der Box abgezogen. Also x = boxWidth - (tileSize * 2)
. Ähnlich ist es mit den beiden verbleibenden Ecken.
Nun zu den dynamischen Parts. Die horizontalen Zwischenräume müssen auf die gesamte Breite minus der beiden Ecken links und rechts gezogen werden. Die vertikalen Zwischenräume auf die gesamte Höhe minus der beiden Ecken oben und unten. Die Höhe haben wir ja im Konstruktor bereits anhand des Textes ermittelt.
And that’s it! Ich hoffe der Beitrag und die Code Ausschnitte haben dir weitergeholfen. Lass es mich gerne hier oder auf Twitter @NickHatBoecker wissen.