Menu
CoddyTech

Ein generisches Singleton

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 34 von 50.

Das Singleton aus Abschnitt 3 besteht aus fünf Zeilen, die jeder Manager wiederholt: ein statisches Instance, ein Awake, das es setzt, und die Prüfung auf Duplikate. Eine generische Basisklasse schreibt sie ein einziges Mal. Jeder Manager leitet sich davon ab und gibt sich selbst als Typ an:

public abstract class Singleton<T> : MonoBehaviour where T : MonoBehaviour
{
    public static T Instance { get; private set; }

    protected virtual void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this as T;
    }
}

public class ScoreManager : Singleton<ScoreManager>
{
    public int score;
    public void Add(int points) { score += points; }
}

public class SoundManager : Singleton<SoundManager>
{
    public void Play(string clip) { Debug.Log("Playing " + clip); }
}
// in einem beliebigen Skript
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");

Ein statisches Mitglied einer generischen Klasse gehört zu jedem daraus erzeugten Typ: Singleton<ScoreManager> und Singleton<SoundManager> sind zwei Typen mit jeweils einem Instance, deshalb teilen sich die Manager keines. ScoreManager.Instance ist bereits vom Typ ScoreManager, dafür ist T gedacht. Innerhalb der Basisklasse ist this nur als Singleton<T> bekannt, daher gibt this as T es als den Manager weiter, der es tatsächlich ist.

Die Basisklasse ist abstrakt: Unity fügt nur die Manager zu Objekten hinzu. Ein Manager, der ein eigenes Awake benötigt, darf kein einfaches void Awake() schreiben. Dadurch wird die Methode der Basisklasse ausgeblendet (der Compiler warnt davor), Unity ruft nur die Methode des Managers auf und Instance wird nie gesetzt. Überschreibe sie und rufe zuerst die Basisklassenmethode auf:

protected override void Awake()
{
    base.Awake();
    score = 0;
}
challenge icon

Aufgabe

Mittel

Eine Stadt und ein Wald, verbunden durch violette Portale. Jede Szene hat ihr eigenes Wallet- und MusicPlayer-Objekt, sodass jedes für sich spielt und die Münzen Wallet.Instance.Add(1) aufrufen. Heute ist jeder Manager das Singleton aus Abschnitt 3, daher ersetzt jeder Ladevorgang das Wallet durch ein leeres. Gib beiden Managern eine generische Basisklasse, die sie beim Laden von Szenen beibehält:

  • Schreibe in PersistentSingleton.cs public abstract class PersistentSingleton<T>, ein MonoBehaviour für jeden MonoBehaviour-Typ T, mit einem öffentlichen statischen Instance vom Typ T, den nur die Klasse festlegt, und einer protected virtual void Awake()-Methode.
  • Das Awake behält das erste seiner Art bei: Dieses wird zu Instance und überlebt das Laden von Szenen. Jedes spätere zerstört sein eigenes Objekt und ändert nichts.
  • Wallet und MusicPlayer leiten davon ab, und ihre eigenen Instance-Felder entfallen.
  • MusicPlayer behält ein eigenes Awake, das Now playing: Adventure protokolliert. Es muss nach dem Awake der Basisklasse ausgeführt werden und nur für das Objekt, das bestehen bleibt, damit die Musik einmal pro Spiel startet.

Die Pfeile bewegen den Player. Drücke Play, sammle die Münze ein, gehe in den Wald und zurück und klicke dann auf Check.

Probier es selbst

using UnityEngine;

// PersistentSingleton<T>: eine Instanz, die Szenenwechsel überdauert
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Spielarchitektur in Unity