Menu
CoddyTech

Ein generisches Singleton

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 43 von 64.

Der Singleton aus Abschnitt 3 besteht aus fünf Zeilen, die jeder Manager wiederholt: eine statische Instance, ein Awake, das sie festlegt, und die Prüfung auf Duplikate. Eine generische Basisklasse schreibt sie einmal. Jeder Manager leitet sich davon ab und gibt seinen eigenen 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 jedem 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 einer Instance, daher teilen sich die Manager niemals eine. ScoreManager.Instance ist bereits als ScoreManager typisiert – genau dafür gibt es T. Innerhalb der Basisklasse ist this nur als Singleton<T> bekannt, daher übergibt this as T es als den Manager, der es tatsächlich ist.

Die Basisklasse ist abstrakt: Unity setzt nur die Manager auf Objekte. 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 festgelegt. Überschreibe die Methode und rufe zuerst die Basisklassenmethode auf:

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

Aufgabe

Mittel

Gib beiden Managern eine Basis, die Szenenwechsel übersteht.

  1. Schreibe in PersistentSingleton protected virtual void Awake(): Das erste Objekt wird zu Instance und bleibt erhalten (DontDestroyOnLoad); ein späteres zerstört sich selbst.
  2. Wallet und MusicPlayer leiten davon ab; lösche ihre Instance und das Awake von Wallet.
  3. MusicPlayer überschreibt Awake: base.Awake(), dann wird, falls es die Instance ist, Now playing: Adventure protokolliert.

Drücke „Spielen“, besuche den Wald und kehre zurück: 1 Münze. Drücke dann „Prüfen“.

Probier es selbst

using UnityEngine;

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

    // Awake: Die erste Instanz über Szenenwechsel hinweg beibehalten, jede spätere zerstören
}

Alle Lektionen in Spielarchitektur in Unity

Übe selbstständig: Unity-Playground