This page needs JavaScript activated to work.
/blog

Unity - UI System

14. August 2021

Ein UI-System erlaubt es UI Elemente zu kontrollieren. Die Leichtigkeit in der Benutzung steht dabei im Vordergrund. So können Elemente einfach angezeigt oder unsichtbar gemacht werden. Außerdem wird der Anzeigeprozess durch Animationen „smoother“ gemacht. Im folgenden Artikel werden wir ein solches UI-System in Unity implementieren.
UISystem Klasse
Als erstes erstellen wir eine Klasse „UISystem“, die unsere UI verwaltet. Dort werden alle späteren Prefabs von unseren UI Elementen gespeichert. Um besser auf diese zugreifen zu können erstellen wir eine ShowUI Methode über die wir die UIElemente aufrufen können. Ein enum wird dabei noch verwendet, um den Zugriff und die Bedienung zu erleichtern. Natürlich sollten wir auch eine Instanz der Klasse erstellen, damit sie von überall zugreifbar ist. Diese Klasse sollte dann ungefähr so aussehen:
public class UISystem : MonoBehaviour {

    public GameObject gamePlayUI;    // UI Element 1
    public GameObject gameOverUI;    // UI Element 2
    public GameObject menuUI;        // UI Element n (es können beliebig viele Elemente hinzugefügt werden)

    [HideInInspector]
    public Canvas canvas;

    public enum UI {      // das enum Speichert die Namen aller Elemente
        GamePlay,         // verweißt auf Element 1
        GameOver,         // verweißt auf Element 2
        Menu              // ...
    }

    public static UISystem Instance; // static = von überall aus zugreifbar, egal welche Klasse
    public UISystem() {
        Instance = this;             // die Instanz wird zu dieser Klasse gesetzt
    }

    private void Awake() {
        canvas = GameObject.Find("Canvas").GetComponent<Canvas>();    // Canvas suchen und setzen
    }

    public void ShowUI(UI ui, bool background) {  // ShowUI Methode mit Argumenten ui als enum und background als bool

        GameObject targetUI = null;               // targetUI erst auf null setzen, denn wir wissen noch nicht welches
                                                  // Objekt die gewünschte UI ist
        switch (ui) {                             // mit switch Anweisung den enum UI durchlaufen
            case UI.GamePlay:                     // für jeden Fall die richtige UI als target setzen
                targetUI = gamePlayUI;
                break;
            case UI.GameOver:
                targetUI = gameOverUI;
                break;
            case UI.Menu:
                targetUI = menuUI;
                break;
        }

        GameObject obj = Instantiate(targetUI);                 // Objekt erstellen
        if (targetUI.GetComponent<Animator>() != null)
            obj.transform.localScale = Vector3.zero;            // den Scale auf (0, 0, 0) setzen - für Animation später
        obj.transform.SetParent(canvas.transform, false);       // das Canvas als Parent setzen
        if (background) obj.GetComponent<UIElement>().Open();              // Wenn ein Background erstellt werden soll, Open Methode
                                                                // von UIElement aufrufen - die Klasse erstellen wir noch
    }
}        
UI Elemente erstellen
Als nächstes erstellen wir alle UI Elemente, die wir anzeigen lassen wollen. Dafür gehen wir in Unity in die „Hierarchy“ der Scene > Rechtsklick > UI > Canvas, um ein Canvas zu erstellen. (Ein Canvas ist ein Bereich, auf dem UI Elemente dargestellt werden können.) In unserem Canvas erstellen wir nun 3 verschiedene Panels: MainUI, GameOverUI und GamePlayUI. Diese gestalten wir nun nach unseren Vorstellungen und fügen sie als Prefab hinzu. Dafür ziehen wir einfach das Element in den Projektordner unter dem Inspector.
MainUI, GamePlayUI, GameOverUI
Prefab view
Animationen erstellen
Die Elemente sollen natürlich nicht plötzlich einfach auftauchen, sondern schön in die Scene reinsliden. Dafür erstellen wir einen AnimationController. Als erstes öffnen wir das Animator und Animation Window. Dafür gehen wir auf die obere Leiste auf Window > Animation > Animation und Window > Animation > Animator. Dann klicken wir ein UIElement an, egal welches. In diesem Beispiel nehmen wir einfach MainUI. Dann gehen wir auf Animation > Create und nennen diese UIOpen. Danach klicken wir auf record und ändern den Scale des Objekts auf 0. Jetzt bewegen wir den Cursor auf 20 Frames und ändern den Scale wieder auf 1 und stoppen die Aufnahme. Dasselbe machen wir nur umgedreht mit UIClose.
Animation erstellen
Scale Property
Zum Schluss müssen wir noch den Loop der Animation entfernen, sonst würde die Animation immer wieder neu abgespielt werden. Dafür klicken wir die Animation im Projektordner an und ändern die Einstellung Loop Time zu false (den Haken entfernen).
Loop Time entfernen
UIElement Klasse
Jedes UIElement benötigt eine Klasse mit der es verwaltet werden kann. Die Klasse benötigt verschiedene Funktionen. Die UI muss angezeigt werden können, unsichtbar gemacht werden können, den Hintergrund abdunkeln können und diesen auch wieder entfernen können. Erstellen wir also so eine Klasse:
// Wichtig für den Anfang
// wir müssen die UI Elemente von Unity importieren, um damit arbeiten zu können
using UnityEngine.UI;

public class UIElement : MonoBehaviour {
    public Color backgroundColor = new Color(0, 0, 0, 0.6f);         // Farbe für den abgedunkelten Hintergrund
    private GameObject background;
    private Animator animator;

    private void Start() {
        animator = GetComponent<Animator>();        // Animator Komponente setzen
    }

    public void Open() {
        CreateBackground();                         // Hintergrund erstellen (siehe unten)
    }

    public void Close() {
        if (animator != null) {     // animator darf nicht null sein, sonst NullReferenceException
                                    // UIClose Animation abspielen, wenn UI geöffnet wurde
            if (animator.GetCurrentAnimatorStateInfo(0).IsName("UIOpen")) animator.Play("UIClose");
        }

        RemoveBackground();         // Hintergrund entfernen
        StartCoroutine(DestroyUI());
    }

    private IEnumerator DestroyUI() {
        yield return new WaitForSeconds(0.5f);     // halbe Sekunde warten
        Destroy(background);                       // Hintergrund entfernen
        Destroy(this.gameObject);                  // dieses UIElement entfernen
    }

    private void CreateBackground() {
        Texture2D texture = new Texture2D(1, 1);         // Textur für Hintergrund erstellen
        texture.SetPixel(0, 0, backgroundColor);         // Farbe der Textur bei Pixel (0, 0) setzen
        texture.Apply();                                 // alle Werte für Textur übernehmen

        background = new GameObject("UI Background");       // das Objekt für Background erstellen
        Image image = background.AddComponent<Image>();     // Image Komponente hinzufügen
        
        // Sprite erstellen mit (Textur, Größe als Rect, Zentrum des Bildes - auch Pivot, Pixel pro Einheit)
        Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f), 1);
        image.sprite = sprite;                              // Sprite setzen
        image.CrossFadeAlpha(1.0f, 0.4f, false);            // Transparenz von 0 auf 1 in 0.4 Sek. setzen

        Canvas canvas = UISystem.Instance.canvas;           // Canvas von UISystem übernehmen
        background.transform.localScale = Vector3.one;      // Scale auf 1 setzen

        // Größe des Backgrounds zur Größe des Canvas setzen
        background.GetComponent<RectTransform>().sizeDelta = canvas.GetComponent<RectTransform>().sizeDelta;
        background.transform.SetParent(canvas.transform, false);            // Canvas als Parent setzen
        background.transform.SetSiblingIndex(transform.GetSiblingIndex());  // Background hinter UI setzen (Index unter UI)
    }

    private void RemoveBackground() {
        Image image = background.GetComponent<Image>();
        if (image != null) image.CrossFadeAlpha(0.0f, 0.2f, false);         // Hintergrund über 0.2 Sek. unsichtbar machen
    }
}        
UI-System testen
Ok wir sind fertig! In den folgenden Zeilen sind einige Beispiele, um das UI System zu testen.
UISystem.Instance.ShowUI(UISystem.UI.Menu, false);     // wenn keine Animation gewünscht ist, dann den Animator löschen
UISystem.Instance.ShowUI(UISystem.UI.GamePlay, true);
UISystem.Instance.ShowUI(UISystem.UI.GameOver, true);