UMG
Das UI-System von Unreal heißt Unreal Motion Graphics oder UMG. Es unterscheidet sich stark vom Standard-uGUI-System von Unity. Die meisten Ähnlichkeiten hat das UI Designer-Authoring-Tool von UMG mit dem UI Toolkit UI Builder von Unity, falls du bereits mit diesem System gearbeitet hast. Der Designer wird in der offiziellen Dokumentation ausführlich behandelt; die Seiten Erstellen deiner UI und Bewährte Praktiken für UMG (Unreal Motion Graphics) sind besonders nützlich für Unity-Entwickler, die noch nicht lange dabei sind. Das Herzstück von UMG sind die Widgets, d.h. eine Reihe vorgefertigter Funktionen und Hierarchien, die du zum Aufbau deiner Benutzeroberfläche verwenden kannst.
CommonUI
CommonUI ist ein von Epic Games entwickeltes Plugin, das wir in „Parrot“ verwenden. CommonUI richtet „gemeinsame“ Stile und Aktionen für alle Widgets ein, deren wiederholte manuelle Einrichtung normalerweise sehr viel Zeit in Anspruch nehmen würde. Ein praktisches Beispiel ist die Erkennung von Änderungen am Inputgerät und die automatische Umschaltung der Inputsymbole auf dem Bildschirm. Dies würde manuell sehr viel Zeit in Anspruch nehmen, aber Common UI automatisiert diesen Prozess. CommonUI wird auch für die Unterstützung der Tastenbelegung von Enhanced Input benötigt, die in der Dokumentation zu Enhanced Input ausführlicher behandelt wird.
Um CommonUI einzurichten, musst du es zunächst im Plugins-Fenster aktivieren. Suche im Menü Bearbeiten > Plugins nach „Common UI Plugin“, aktiviere es und starte dann den Editor neu.
Gehe zu Projekteinstellungen > Allgemeine Einstellungen und ändere die Spiel-Viewport-Client-Klasse von „GameViewportClient“ zu „CommonGameViewportClient“. So können CommonUI-Widgets Input-Events von der Engine empfangen.
Markiere unter Projekteinstellungen > CommonInput-Einstellungen das Kontrollkästchen Unterstützung für Enhanced Input aktivieren. Dies ermöglicht die Verwendung von Enhanced Input mit CommonInput. CommonInput verarbeitet die Inputs in CommonUI-Widgets.
Schließlich musst du noch einige Module in deinem Projekt aktivieren, damit du sie im Code verwenden kannst. Gehe zur Datei
$ProjectName.Build.cs, in diesem FallParrot.Build.cs. Füge Folgendes zur Liste PublicDependencyModuleNameshinzu:CommonInputCommonUIEnhancedInputGameplayTagsUMG
Widget-Hierarchie in „Parrot“
Die erste UI-Klasse, die wir uns in „Parrot“ ansehen, ist AParrotHUD. Die HUD-Klasse in der Unreal Engine ist ein Actor, der für jeden lokalen Spieler erstellt wird und das Heads-up-Display steuert. Dieser verfügt über einen Canvas und einen Debug-Canvas, auf den direkt gezeichnet werden kann. Du kannst ihn auch als Teil deiner Spielmoduskonfiguration zuweisen. Wenn du diese Klasse in „Parrot“ verwendest, ist sie ein Actor, der das Stamm-Widget besitzt, von dem aus alle deine Widgets erstellt und verwaltet werden.
Der Klassentyp für dieses besitzende Widget ist UParrotGameLayout. UParrotGameLayout ist der C++-Basis-Widget-Container für alle deine anderen UI-Widgets. Darin befindet sich eine Liste von „Ebenen“, die vom Typ UCommonActivatableWidgetContainerBase sind. Alle anderen Widgets, die du anzeigen möchtest, werden auf eine dieser Ebenen verschoben.
Dies sind die Basis-Ebenen, die wir einrichten:
Game: Die Ebene, auf die dein UMG HUD-Widget gepusht wird.
GameMenu: Die Ebene, auf die jedes Widget gepusht wird, das du über dem HUD anzeigen möchtest.
Menu: Die Ebene für alle Bildschirmwidgets wie Pausenbildschirm, Einstellungsbildschirm, Inventarbildschirm und andere ähnliche Bildschirme.
Modal: Die Ebene für alle modalen Popups.
Es ist immer nur ein Widget pro Ebene aktiv. Du kannst mehrere verschiedene Bildschirmwidgets auf die Ebene „Menu“ pushen, aber nur das letzte ist aktiv und wird angezeigt.
In „Parrot“ haben wir auch eine Klassenhierarchie für aktivierbare Bildschirme erstellt, da diese Widgets alle die gleiche Funktionalität haben und auf die Ebene „Menu“ verweisen. Die Klassenhierarchie sieht folgendermaßen aus:
Mit diesem Setup erstellen wir alle UI-Bildschirme in „Parrot“.
Widget-Styling
Mit dem Common UI-Plugin und der Bildschirmeinrichtung kannst du anfangen, deine Widgets zu gestalten. W_ButtonBase unter Content/UI/Widgets/Common ist ein gutes Beispiel dafür. Es verwendet die ButtonStyle_Base-Stylingdaten unter Content/UI/Styling. Es verwendet die UCommonButtonStyle-Klasse von Common UI. Es gibt eine Vielzahl von Optionen, die du anpassen kannst. Einige Beispiele sind Sounds und Pinsel, die auf dem Zustand der Schaltfläche basieren. Common UI hat viele verschiedene Styling-Klassen wie diese, abhängig von dem Widget, das du verwendest. Wenn du etwas Eigenes erstellen möchtest, ist der Code für diese gestylten Widgets eine gute Anlaufstelle für dich.
Ladebildschirm
Der Ladebildschirm in „Parrot“ verwendet ein First-Party-Plugin von Epic Games: CommonLoadingScreen. Ein weiteres Beispiel für dieses Plugin in der Praxis findet sich im Lyra-Beispielprojekt von Epic Games. Um zu verstehen, warum wir dieses Plugin verwenden, müssen wir zunächst die Grundlagen des Ladens von Leveln in der Unreal Engine verstehen.
Es gibt mehrere Möglichkeiten, das Laden von Leveln in UE zu handhaben. Ein einfacher Ansatz ist der Aufruf des Knotens Open Level in einem Blueprint. Diese Funktion kann eine Karte über eine Zeichenkette oder eine Soft-Objekt-Referenz auf die Karte laden. Dies funktioniert gut für einfache Karten, aber es gibt einen Haken. Wenn diese Funktion aufgerufen wird, wird die Karte synchron geladen, was zu einem auffälligen Ruckeln führen kann, je nachdem wie viele Daten für die neue Karte geladen werden müssen. Ein weiteres Problem besteht darin, dass ein zum Viewport hinzugefügtes Widget an einen Player-Controller gebunden ist, der im vorherigen Level existiert. Wenn das Level wechselt, wird es beim Entladen des Levels aufgeräumt.
Es kann von Vorteil sein, einen neuen Spielmodus auf der Grundlage der Karte zu laden (z. B. Einzelspieler-Level gegen Mehrspieler-Level). Aber wie kann man den Ladebildschirm aufrechterhalten und mögliche Ladeprobleme mit Open Level vermeiden? Werfen wir einen Blick auf BP_ParrotGameInstance.
Das asynchrone Laden des Levels löst hier das Problem, dass die Assets zum Zeitpunkt des Aufrufs von Open Level noch nicht fertig sind. Wie in dem Kommentar erwähnt, wird die Arbeit des Ladebildschirms auch hier bereits erledigt. Die Konfiguration des Plugins ist einfach und du kannst das Ladebildschirm-Widget unter Bearbeiten > Projekteinstellungen > Gemeinsamer Ladebildschirm einstellen.
Beachte hier auch die Debugging-Umschalter. Wenn du diese im Editor testest, kannst du dir ein besseres Bild davon machen, wie der Ladebildschirm in einer verpackten Version aussehen wird.
Die Level werden jetzt mit einem Ladebildschirm geladen. Es lohnt sich, selbst weiter zu erforschen, wie wir in BP_ParrotGameInstance die Reihenfolge der Einzelspieler- und Mehrspieler-Level eingerichtet haben. Die Einrichtung des Spielstatus wird in der Dokumentation zum Unreal Gameplay-Framework behandelt.