Menu
CoddyTech

Un singleton genérico

Parte de la sección Arquitectura de juegos en Unity del Journey de Unity de Coddy. Lección 34 de 50.

El singleton de la sección 3 consta de cinco líneas que todos los administradores repiten: un Instance estático, un Awake que lo establece y la comprobación de duplicados. Una clase base genérica las escribe una sola vez. Cada administrador deriva de ella y se nombra a sí mismo como 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); }
}
// en cualquier script
ScoreManager.Instance.Add(10);
SoundManager.Instance.Play("coin");

Un miembro estático de una clase genérica pertenece a cada tipo creado a partir de ella: Singleton<ScoreManager> y Singleton<SoundManager> son dos tipos, cada uno con su propio Instance, así que los administradores nunca comparten uno. ScoreManager.Instance ya tiene el tipo ScoreManager, que es para lo que sirve T. Dentro de la clase base, this solo se conoce como un Singleton<T>, así que this as T lo entrega como el administrador que realmente es.

La clase base es abstracta: Unity coloca solo los administradores en los objetos. Un administrador que necesite su propio Awake no debe escribir un void Awake() sin más. Esto oculta el método de la clase base (el compilador lo advierte), Unity solo llama al método del administrador e Instance nunca se establece. Sobrescríbelo y llama primero a la clase base:

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

Desafío

Intermedio

Un pueblo y un bosque, unidos por portales morados. Cada escena tiene su propio objeto Wallet y MusicPlayer, así que cada uno reproduce música por su cuenta, y las monedas llaman a Wallet.Instance.Add(1). Hoy, cada administrador es un singleton de la sección 3, así que cada carga reemplaza la billetera por una vacía. Dales a ambos administradores una clase base genérica que los mantenga durante las cargas de escena:

  • En PersistentSingleton.cs, escribe public abstract class PersistentSingleton<T>, un MonoBehaviour para cualquier tipo T de MonoBehaviour, con un Instance estático público de tipo T que solo establece la clase, y un protected virtual void Awake().
  • Su Awake conserva el primero de su tipo: ese se convierte en Instance y sobrevive a las cargas de escena. Cualquier instancia posterior destruye su propio objeto y no cambia nada.
  • Wallet y MusicPlayer derivan de ella, y se eliminan sus propios campos Instance.
  • MusicPlayer conserva su propio Awake, que registra Now playing: Adventure. Debe ejecutarse después del Awake de la clase base, y solo para la instancia que permanece, para que la música empiece una vez por partida.

Las flechas mueven al Player. Pulsa Jugar, recoge la moneda, ve al bosque y vuelve, luego pulsa Comprobar.

Pruébalo tú mismo

using UnityEngine;

// PersistentSingleton<T>: una instancia que persiste al cargar escenas
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Arquitectura de juegos en Unity