Implementación de Singleton en Gestor de Interfaz de Usuario

Clase 24 de 31Curso de Desarrollo de Videojuegos para Móviles con Unity

Resumen

El flujo de puntuación y movimientos puede ser simple y eficiente si se aprovechan propiedades con getter y setter sobre un patrón Singleton. Con este enfoque, la UI reacciona sin depender de un update continuo, algo clave en juegos móviles: menos consumo y cambios inmediatos en pantalla.

¿Por qué usar un singleton en el manager de interfaz?

El objetivo es tener un único Graphical User Interface Manager que centralice cambios de score y move counter. Así, cualquier script puede invocar la shared instance y actualizar la interfaz al instante.

  • Evitar update en móvil: no es nuestro mejor amigo para redibujar continuamente. Mejor propiedades reactivas.
  • Propiedades con efecto: cada setter actualiza textos y estados sin lógica adicional.
  • Instancia única: previene duplicados y estados inconsistentes en escena.

¿Cómo se implementa la shared instance del GUI manager?

  • Crear una variable private static del mismo tipo que la clase y exponerla como pública para acceso global.
  • En start: si no existe, asignar this; si existe, hacer destroy del segundo game object.
public class GraphicalUserInterfaceManager : MonoBehaviour
{
    public static GraphicalUserInterfaceManager sharedInstance; // debe ser pública.

    private int _moveCounter;
    private int _score;

    [SerializeField] private Text movesText;
    [SerializeField] private Text scoreText;

    void Start()
    {
        if (sharedInstance == null)
            sharedInstance = this;
        else
            Destroy(this.gameObject);
    }

    public int MoveCounter
    {
        get => _moveCounter;
        set
        {
            _moveCounter = value;
            UpdateMovesUI();
        }
    }

    public int Score
    {
        get => _score;
        set
        {
            _score = value;
            UpdateScoreUI();
        }
    }

    void UpdateMovesUI() => movesText.text = _moveCounter.ToString();
    void UpdateScoreUI() => scoreText.text = _score.ToString();
}

¿Qué ventaja tienen getters y setters frente a update en móvil?

  • Menos coste: se actualiza solo cuando cambian los datos.
  • Menos código disperso: una sola fuente de verdad controla la UI.
  • Reactividad inmediata: cambios en score y move counter se reflejan al instante.

¿Cómo se actualizan movimientos y puntuación en tiempo real?

La interacción del usuario y la caída de piezas marcan los dos puntos de actualización: decrementar movimientos al ejecutar un swipe válido y aumentar puntos cuando caen caramelos en la corrutina del tablero.

¿Dónde decrementar move counter con can swipe?

  • Dentro del bloque if (canSwipe): se intercambian caramelos, se comprueban matches y se deselecciona el caramelo.
  • Justo ahí, invocar a la shared instance y hacer -- del contador.
// Dentro de Candy (o el script que gestiona el input)
if (canSwipe)
{
    // Intercambio, comprobación de matches, etc.
    GraphicalUserInterfaceManager.sharedInstance.MoveCounter--;
}

¿Dónde incrementar score en la corrutina del board manager?

  • En la corrutina que reposiciona caramelos: tras cada espera, un caramelo cae y se reubica.
  • Ese es un buen momento para sumar puntos fijos, por ejemplo, 10 por ciclo.
// Dentro de la corrutina del BoardManager
// Valor de ejemplo para una caída ágil: 0.02f–0.05f.
yield return new WaitForSeconds(0.02f);
GraphicalUserInterfaceManager.sharedInstance.Score += 10;

¿Qué detalles operativos conviene recordar?

  • Acceso público: si la shared instance es privada, no aparecerá al autocompletar.
  • Orden de guardado: guardar scripts y volver a probar tras cada cambio.
  • Valores de espera: tiempos pequeños aceleran pruebas sin perder claridad visual.

¿Qué comportamiento de juego observamos y qué retos propone el instructor?

El resultado confirma la lógica: la puntuación arranca en cero, los movimientos en treinta, y cada acción válida modifica la UI. Además, se distinguen casos con y sin match.

¿Qué resultados en pantalla confirman la lógica?

  • Primer movimiento: movimientos bajan a veintinueve; puntos suben a treinta.
  • Caídas encadenadas: rebotes múltiples elevan rápidamente la puntuación, por ejemplo hasta ciento cincuenta.
  • Movimientos potentes: un solo movimiento con cuatro piezas puede sumar cuarenta puntos.

¿Qué pasa con movimientos sin match?

  • Movimientos: se decrementan igualmente en una unidad.
  • Puntuación: permanece sin cambios si no hay tres en línea.
  • Nota de diseño: en el original de Candy Crush, el movimiento sin match se revierte; aquí se permite y solo resta un movimiento.

¿Qué retos finales puedes implementar?

  • Pantalla de game over: lanzar al llegar a cero movimientos y evitar negativos.
  • Resumen de partida: mostrar puntuación final y estadísticas relevantes.
  • Máximas puntuaciones y ranking: almacenar y ordenar resultados para incentivar la rejugabilidad.

¿Tienes dudas o quieres compartir tu implementación del Singleton y las propiedades reactivas? Comenta tus avances y propuestas de mejoras.