Nachricht- / Information- / Chatanzeige (HUD) ohne komplizierte Indexsortierung


Hier möchte ich ein kleines Tutorial vorstellen, in dem es darum geht dem Spieler kurze Nachrichten anzuzeigen. Dies können Chatnachrichten, Spielereignisse oder was auch immer sein. Das "Schwierige" daran ist, diese Nachrichten werden am besten unten angezeigt, und die neueste Nachricht wird unter die alte gepackt und alles zusammen nach oben gescrollt. Des Weiteren ist ein Anspruch hier, dass die Nachrichten nicht ewig auf dem Bildschirm angezeigt werden sollen, sondern halt auch wieder verschwinden, schließlich will der Spieler das Spiel sehen und nicht eines der früheren Textadventure lesen. Ich gehe davon aus, dass ihr schon ein HUD im Spiel habt. Also ganz von Anfang an beginne ich nicht.


Hier möchte ich ein kleines Tutorial vorstellen, in dem es darum geht dem Spieler kurze Nachrichten anzuzeigen. Dies können Chatnachrichten, Spielereignisse oder was auch immer sein. Das "Schwierige" daran ist, diese Nachrichten werden am besten unten angezeigt, und die neueste Nachricht wird unter die alte gepackt und alles zusammen nach oben gescrollt. Des Weiteren ist ein Anspruch hier, dass die Nachrichten nicht ewig auf dem Bildschirm angezeigt werden sollen, sondern halt auch wieder verschwinden, schließlich will der Spieler das Spiel sehen und nicht eines der früheren Textadventure lesen. Ich gehe davon aus, dass ihr schon ein HUD im Spiel habt. Also ganz von Anfang an beginne ich nicht.


Als Erstes brauchen wir ein Extrawidget. Dies nenne ich in meinem Beispiel HUD_MessageBox. Wichtig, da ja alles spätere darauf beruht.



11693-messagewidget-komponenten-png


Die `Struktur der Messagebox sieht wie folgt aus. Wobei wichtig ist das hinter dem Canvas eine Horizontal Box ist mit folgenden Eigenschaften:

11704-messagewidget-messageboxanchor-png



Der Anchor wird auf Top über die ganze Breite gesetzt.


11696-messagewidget-sizes-png


Bei Offset Right setzen wir das Ganze auf 0,0 und Size Y auf 24,0. Wobei Size Y etwas größer als die Schriftart sein sollte.

Und diese Horizontal Box packen wir dann noch einmal Text und benennen das in txtMessage um.


11699-messagewidget-txtmessagepading-png


Padding stellen wir bei txtMessage auf Left und Right jeweils 10 für ein wenig Abstand zum Rand.

&thumbnail=1


Fontsize habe ich hier auf 15 gestellt. Hier würde ich einen nicht zu hohen Wert nehmen, denn im Spiel können Fonts schnell recht gewaltig aussehen.


11697-messagewidget-txtmessageautowrap-png


Zudem schalten wir noch Autowrap ein, weil eine Maximale Textlänge habe ich hier nicht eingebaut.

Backgroundblur und Border sind für das Beispiel nicht notwendig. Ich habe hier halt nur einen Hintergrund mit Blurwert 2,0 und einem Schwarz von einem Alphawert von 0,2 mit eingebaut damit sich die Nachricht ein wenig vom Hintergrund her unterscheidet.



Es sollte in Etwa so aussehen:

11689-messagewidget-design-png



11687-messagewidget-binding-png


Als Text geben wir "<Message>" als Platzhalter ein.


Als letztes fügen wir der txtMessage noch ein Binding im Content hinzu. Dies erlaubt es später per Blueprint auf den Inhalt zuzugreifen.


Nun kümmern wir uns um den Graphbereich dieses Widgets...


Normalerweise schaltet beim Erstellen eines Bindings die Engine eh auf den Graphbereich um, falls nicht, oben Rechts halt neben dem Designer auf Graph klicken.


Im BP fügen wir nun zwei Variablen hinzu.

Eine Variable NewMessage vom Typ Text

Und eine Variable TimeToShowText vom Typ Float, hier habe ich einen Standardwert von 3,0 (Sekunden) gewählt.



11700-messagewidget-variables-png


Das Fade kommt später hinzu.


Als erstes kümmern wir uns um die Funktionen.

11691-messagewidget-functions-png


Die Get_txtMessage benenn wir eben halt um in Get_txtMessage ohne 0 oder was auch immer automatisch dahinter gesetzt wird, weil braucht kein Mensch.

Wir wählen die Funktion Get_txtMessage aus und ergänzen den Code wie folgt.

11692-messagewidget-gettxtmessage-png


Wir lesen als schlicht die Variable NewMessage aus.

Danach legen wir eine neue Funktion an und benennen diese in Set_txtMessage. Und fügen einen Inputpin vom Typ Text hinzu.

Hier fügen wir dann die Variable NewMessage ein, als Set und verbinden dies mit dem Inputpin.



11695-messagewidget-settxtmessage-png


Damit haben wir jetzt sowohl eine Funktion zum Auslesen der Variablen, die automatisch mit txtMessage verbunden ist, hier müssen wir also gar nichts machen, um den Inhalt zu ändern, wir müssen die Funktion nicht einmal irgendwie aufrufen. Set_txtMessage sorgt halt für den Inhalt der Variablen die ausgelesen wird.


Kümmern wir uns mal ein wenig um die Animation. Es ist zu empfehlen eine kleine Animation zu verwenden damit der Spieler auch auf die Nachricht aufmerksam wird, bzw. nicht erschlagen wird, wenn diese ganz plötzlich aufpoppt.


Ich habe mich hier für ein Scalefade entschieden wo die Nachricht beim Einblenden größer wird, beim Ausblenden halt kleiner. Genauso gut kann man über den Alphakanal auch Ein- und Ausblenden. Wie man das machen möchte bleibt einem letztendlich selber überlassen. Wichtig ist nur das man die Animation nicht zu lange macht, denn kein Spieler will 2 Minuten auf die Nachricht starren und warten bis die endlich komplett angezeigt wird. Nach einigen Tests habe ich festgestellt das eine Zeit von 0,25 bis 0,5 Sekunden relativ angenehm ist. Wobei das natürlich auch immer auf die Art der Animation ankommt.


Wir klicken also unten Links auf +Animation um eine neue Animation zu erstellen. Diese habe ich Fade genannt.

11690-messagewidget-fade-png


Unter +Track wählt man dann CanvasPanel_0 aus. Fügt aus der rechten Liste den Transformbereich hinzu. In der Timeline setzt man den Pfeil auf 0 Sekunden und gibt unter Scale die werte X und Y 0,01 ein. Danach setzt man den Timelinepfeil auf 0,25 Sekunden (oder je nachdem wie lang die Animation dauern soll) klickt bei Scale X und Y den Kreis zwischen den Pfeilen an und setzt danach die Werte auf 1,0. Nun hat man eine Animation die diese Nachricht vergrößert, wenn sie abgespielt wird. Ist jetzt vielleicht etwas kurz gefasst, aber vielleicht kann ich, oder auch jemand anderes ja nochmal ein Tutorial über Animationen von Widgets machen.


Nun gehen wir in den Eventbereich unserer HUD_Messagebox. Hier sorgen wir jetzt dafür, das diese Animation abgespielt wird.

Wir finden in diesem BP nun ein Event mit dem Namen "Event Construct" Alle anderen Events können wir löschen, weil benötigen wir nicht.


Dazu fügen wir noch ein "Custom Event" hinzu und benennen dies in FadeOut um. Das ist zwar nicht zwingen notwendig, dies dient nur dafür um wenigstens ein Delay zu sparen. Ich habe eine persönliche Abneigung gegen Delay und versuche diese zu vermeiden wo es geht. Obwohl ich am Ende dann doch eins verwendet habe.


Auf jeden Fall kommt hinter Event Construct ein Play Animation. Als In Anmation ziehen wir die Animation Fade an den Pin. Danach kommt ein Set Timer by Event. Das Event verknüpfen wir mit dem FadeOut Event und Time verknüpfen wir mit der Time to Show Text Variablen.


In das Event FadeOut kommt wieder ein Play Animation, an den Pin In Animation kommt wieder die Variable Fade. Diesmal stellen wir den Play Mode allerdings auf Reverse (Animation rückwärts abspielen). Danach ein Delay von 0,5 Sekunden und am Schluss ein Remove from Parent Target bleibt self. Dies löscht nach einer gewissen Zeit die Nachricht.


Das Ganze sollte dann so aussehen.

11688-messagewidget-constru-png


Dies sollte es mit dem MessageBox Widget gewesen sein. Zumindest hoffe ich es. Nicht so ganz einfach die Übersicht zu behalten. Also Compilieren und Speichern, was ja eh zwischendurch zu empfehlen ist.


Erstellen wir nun ersteinmal eine Blueprint Functions Library. Zu finden ist dies per Rechtsklick im Contentbrowser unter Blueprints. Diese neue Funktionslibrary benennen wir um in WidgetControls. Eine solche Library würde ich sowieso jedem der viel mit Widgets arbeitet, was ja meistens der Fall sein dürfte, anzulegen, weil man so sehr gut Funktionen anlegen kann, die man dann nicht in jedem Blueprint neu machen muss.


In dieser Library legen wir uns also eine neue Funktion an und nennen diese Sand_a_Message. Dieser Funktion geben wir nun ein Get All Widgets Of Class. Als Widget Class wählen wir unser HUD aus.


11702-sendamessage-bp-png


Der letzte Teil, On Message bleibt erstmal weg, weil den müssen wir erstmal im HUD bauen.



Kümmern wir uns also um das HUD. In das HUD fügen wir folgendes in das CanvasPanel ein.


Einmal eine Scroll Box. Diese nennen wir MessageContainer.

In diesen MessageContainer fügen wir noch eine Vertical Box ein und diese nennen wir nun Message.

&thumbnail=1


Bei dem MessageContainer stellen wir folgende Werte ein.

11683-hud-messagecontainerposition-png



Die Position und Größe kann natürlich den eigenen Bedürfnissen angepasst werden. In diesem Fall sollte nun aber ein relativ großes Rechteck im Designer zu sehen sein das oberhalb von Schnellzugriffsleisten vom Inventar oder ähnlichem liegt und unterhalb von Minimaps und Gesundheitsanzeigen. Also Mitte Rechts halt.



11682-hud-messagecontainerangle-png


Unter Transform drehen wir den Messagecontainer nun um 180 Grad, sprich wir stellen ihn auf den Kopf. Das ist natürlich doof, weil wer macht schon einen Handstand beim Spielen? Die Auflösung kommt gleich.


Wir gehen nun auf Message (die Vertical Box). Auch diese stellen wir per Transform / Angle auf 180 Grad.

Was soll das Ganze? Nun, Wenn wir den Messagecontainer auf den Kopf stellen sorgen wir dafür, dass alle eingehenden Nachrichten nach oben gescrollt werden, so wie wir es halt haben möchten. Das dumme ist nur, alle Nachrichten stehen dann ebenfalls auf dem Kopf. Deswegen drehen wir die Vertiacal Box ebenfalls auf den Kopf. Dies sorgt wiederum dafür, dass die Nachrichten richtig rum angezeigt werden. Und dazu kommt dann halt noch dass die neuen Nachrichten unten angefügt werden, während die älteren Nachrichten nach oben gepuscht werden. Also genau das Ergebnis, das wir haben möchten.


11684-hud-messagevar-png


Zudem muss die Vertical Box noch als Variable eingestellt werden. So können wir dann per BP neue Childs (Die vorher erstellte Messagebox) hinzufügen.


Kümmern wir uns nun um den BP-Teil im HUD. Wir wechseln also zu Graph.


Hier erstellen wir ein Custom Event. Dieses benennen wir um in OnMessage.

Dem OnMessage fügen wir ein InputPin hinzu, vom Typ Text und benennen diesen in Message um.


11686-hud-onmessageinput-png


An dieses Event packen wir ein Create Widget. Als Calass wählen wir unser Widget "HUD_Messagebox" aus. An Owning Player packen wir einen ganz einfachen Get Player Controller. Von dem Create Widget rufen wir SettxtMessage auf. Als Target verknüpfen wir Return Value vonm Create Widget. Und den Event Input Pin von OnMessage verbinden wir mit Message. Daraufhin folgt ein Add Child. Content wird wieder mit dem Return Value von Create Widget verbunden und Target wird die Variable von der Vertical Box "Message angepinnt.


Sieht dan in etwa so aus.


11685-hud-onmessagebp-png


Wir Speichern und Kompilieren das Ganze nun.


Gehen wir noch einmal zurück zur Funktionslibrary. Ich hoffe ihr erinnert euch.

11702-sendamessage-bp-png


Hier können wir nun OnMessage hinten dran hängen. Von Get All Widgets gehen wir nun noch von Found Widgets zu Target. Und vom Input Pin "Message" gehen wir nun zum Pin Message des Eventaufrufes.


Auch das wäre erledigt. Also Kompilieren und Speichern.


Und nun hoffe ich inständig das ich nicht zu viel vergessen habe. Weil Tutorials hier schreiben ist schon etwas schwierig um die Übersicht zu behalten, was man zum Ende hin wahrscheinlich auch an meinem Schreibstil bemerkt ^^. Aber, wenn alles richtig ist sollte es nun funktionieren.



Aufgerufen wird das Ganze über Send a Message, von jedem BP aus das halt benötigt wird.


Ich habe hier mal ein kleines Beispiel gebaut das, welches sekündlich eine durchnummerierte Testnachricht auf den Bildschirm bringt.


&thumbnail=1


Am Ende sollte es dann etwa so in der Ausgabe aussehen.


11701-screenshot-png


Man sieht, es werden die neuen Nachrichten schön unten eigefügt. Das es nach oben scrollt müsst ihr mir einfach mal so glauben, weil das ist auf einem Screenshot nicht ganz so gut zu erkennen 8o.


Falls ich etwas vergessen haben sollte, oder etwas unklar ist, ich bin ja noch da. Für Fragen stehe ich gerne offen. Allerdings bitte nur solche die ich auch beantworten kann. ^^

Bilder

 477×457 49&thumbnail=1Beispielaufruf.PNG  165,64 kB 1.144×574 55&thumbnail=1HUD_Messagecontainer.PNG  15,66 kB 383×266 50&thumbnail=1HUD_MessagecontainerAngle.PNG  28,01 kB 528×396 38&thumbnail=1HUD_MessagecontainerPosition.PNG  20,38 kB 547×256 48&thumbnail=1HUD_Messagevar.PNG  5,66 kB 507×74 38&thumbnail=1HUD_OnMessageBP.PNG  184,29 kB 1.521×304 43&thumbnail=1HUD_OnMessageInput.PNG  9,25 kB 454×205 44&thumbnail=1Messagewidget_Binding.PNG  4,6 kB 425×68 42&thumbnail=1Messagewidget_Constru.PNG  169,8 kB 1.000×684 47&thumbnail=1Messagewidget_Design.PNG  7,47 kB 988×80 47&thumbnail=1Messagewidget_Fade.PNG  34,15 kB 917×295 5111717-messagewidget-functions-pngMessagewidget_Functions.PNG

  • 4,58 kB
  • 343×70
  • 51

11718-messagewidget-gettxtmessage-pngMessagewidget_GettxtMessage.PNG

  • 26,71 kB
  • 331×122
  • 48

11719-messagewidget-komponenten-pngMessagewidget_Komponenten.PNG

  • 9,97 kB
  • 279×193
  • 56

11720-messagewidget-messageboxanchor-pngMessagewidget_MessageBoxAnchor.PNG

  • 7,76 kB
  • 301×146
  • 46

&thumbnail=1Messagewidget_SettxtMessage.PNG  23,86 kB 408×103 5011722-messagewidget-sizes-pngMessagewidget_Sizes.PNG

  • 4,02 kB
  • 309×97
  • 47

11723-messagewidget-txtmessageautowrap-pngMessagewidget_txtMessageAutowrap.PNG

  • 3,5 kB
  • 293×75
  • 43

&thumbnail=1Messagewidget_txtMessageFontsize.PNG  5,92 kB 378×109 3611725-messagewidget-txtmessagepading-pngMessagewidget_txtMessagePading.PNG

  • 7,59 kB
  • 307×188
  • 51

11726-messagewidget-variables-pngMessagewidget_Variables.PNG

  • 7,22 kB
  • 348×119
  • 46

&thumbnail=1Screenshot.PNG  116,86 kB 909×217 44&thumbnail=1SendAMessage_BP.PNG  52,01 kB 733×192 38&thumbnail=1SendAMessage_Input.PNG  24,35 kB 477×457 52

Über den Autor

Mal etwas mehr über mich.


Obwohl ich schon zu Zeiten des C64 mit Assembler angefangen habe, C (ohne ++) weiter gemacht habe und am Ende dann C# für mich entdeckt habe, bin ich nun bei der Unreal Engine und BP gelandet. Trotzdem würde ich mich eher als Anfänger bezeichnen, denn irgendwie lernt man beim Programmieren nie aus. Optimieren kann man immer und ständig jenseits einer "Hello World" - Anwendung.


Bei Artist, nun ja. Anfänger ist eigentlich übertrieben. Leider komme ich bei der Spieleprogrammierung nicht drumherum. Mir fehlt an der Stelle einfach etwas die Kreativität der bildlichen Vorstellungskraft und vor allem der geschickte Umgang mit der Maus in einer 3D-Umgebung.

Tomarr Urgestein

Kommentare