Menu
CoddyTech

Generyczny singleton

Część sekcji Architektura gier w Unity ścieżki Unity w Coddy. Lekcja 34 z 50.

Singleton z sekcji 3 to pięć wierszy, które powtarza każdy menedżer: statyczne Instance, Awake, które je ustawia, i sprawdzenie duplikatów. Generyczna klasa bazowa zapisuje je raz. Każdy menedżer dziedziczy po niej, podając własny typ:

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); }
}
// w dowolnym skrypcie
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");

Składowa statyczna klasy generycznej należy do każdego utworzonego z niej typu: Singleton<ScoreManager> i Singleton<SoundManager> to dwa typy, z których każdy ma własne Instance, więc menedżery nigdy go nie współdzielą. ScoreManager.Instance ma już typ ScoreManager — właśnie do tego służy T. W klasie bazowej this jest znane tylko jako Singleton<T>, więc this as T przekazuje je jako typ menedżera, którym rzeczywiście jest.

Klasa bazowa jest abstrakcyjna: Unity umieszcza na obiektach tylko menedżery. Menedżer, który potrzebuje własnego Awake, nie może napisać zwykłego void Awake(). Ukrywa to metodę klasy bazowej (kompilator wyświetli ostrzeżenie), Unity wywoła tylko metodę menedżera, a Instance nigdy nie zostanie ustawione. Zastosuj override i najpierw wywołaj metodę klasy bazowej:

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

Wyzwanie

Średni

Miasteczko i las połączone fioletowymi portalami. Każda scena ma własne obiekty Wallet i MusicPlayer, więc każdy z nich odtwarza muzykę niezależnie, a monety wywołują Wallet.Instance.Add(1). Dziś każdy menedżer jest singletonem z sekcji 3, więc każde wczytanie zastępuje portfel pustym. Utwórz dla obu menedżerów klasę bazową generyczną, która zachowa je podczas wczytywania scen:

  • W pliku PersistentSingleton.cs napisz public abstract class PersistentSingleton<T>, klasę MonoBehaviour dla dowolnego typu MonoBehaviour T, z publicznym statycznym polem Instance typu T, którego wartość może ustawiać tylko ta klasa, oraz metodą protected virtual void Awake().
  • Metoda Awake zachowuje pierwszy obiekt tego rodzaju: staje się on Instance i przetrwa wczytywanie scen. Każdy kolejny niszczy własny obiekt i niczego nie zmienia.
  • Wallet i MusicPlayer dziedziczą po tej klasie, a ich własne pola Instance należy usunąć.
  • MusicPlayer zachowuje własną metodę Awake, która rejestruje Now playing: Adventure. Musi ona uruchomić się po metodzie Awake klasy bazowej i tylko dla obiektu, który pozostaje, aby muzyka zaczynała grać raz na grę.

Strzałki poruszają Playerem. Naciśnij Play, zbierz monetę, przejdź do lasu i wróć, a następnie naciśnij Check.

Spróbuj swoich sił

using UnityEngine;

// PersistentSingleton<T>: jedna instancja, która pozostaje aktywna podczas wczytywania kolejnych scen
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Architektura gier w Unity