Menu
CoddyTech

Un singleton generico

Fa parte della sezione Architettura dei giochi in Unity del percorso Unity di Coddy. Lezione 43 di 64.

Il singleton della sezione 3 consiste in cinque righe che ogni gestore ripete: un Instance statico, un Awake che lo imposta, il controllo dei duplicati. Una classe base generica le scrive una volta sola. Ogni gestore deriva da essa, indicandosi come tipo:

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 qualsiasi script
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");

Un membro statico di una classe generica appartiene a ciascun tipo creato a partire da essa: Singleton<ScoreManager> e Singleton<SoundManager> sono due tipi, ognuno con il proprio Instance, quindi i gestori non ne condividono mai uno. ScoreManager.Instance è già tipizzato come ScoreManager, ed è proprio a questo che serve T. All’interno della classe base, this è noto solo come Singleton<T>, quindi this as T lo passa come il gestore che è realmente.

La classe base è astratta: Unity mette sugli oggetti solo i gestori. Un gestore che ha bisogno di un proprio Awake non deve scrivere un semplice void Awake(). Questo nasconde il metodo della classe base (il compilatore avvisa del problema), Unity chiama solo quello del gestore e Instance non viene mai impostato. Esegui l’override e chiama prima il metodo della classe base:

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

Sfida

Medio

Fornisci a entrambi i gestori una base che sopravviva ai caricamenti delle scene.

  1. In PersistentSingleton, scrivi protected virtual void Awake(): il primo diventa Instance e resta (DontDestroyOnLoad); uno successivo si autodistrugge.
  2. Wallet e MusicPlayer derivano da questa classe; elimina il loro Instance e l'Awake di Wallet.
  3. MusicPlayer esegue l'override di Awake: base.Awake(), poi, se è l'Instance, registra Now playing: Adventure.

Premi «Gioca», visita la foresta e torna: 1 moneta. Poi premi «Verifica».

Provalo tu

using UnityEngine;

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

    // Awake: mantieni il primo durante i caricamenti delle scene, distruggi tutti quelli successivi
}

Tutte le lezioni di Architettura dei giochi in Unity

Esercitati da solo: Playground Unity