Menu
CoddyTech

Conservar entre escenas

Parte de la sección Creación de juegos reales del Journey de Unity de Coddy. Lección 20 de 56.

Al cargar una escena, se destruyen todos los objetos de la anterior, pero algunas cosas deben durar durante todo el juego, como las monedas que un jugador lleva de un nivel a otro. DontDestroyOnLoad(gameObject) saca un objeto de su escena y lo mueve a una escena propia, llamada DontDestroyOnLoad en la Jerarquía durante la ejecución, que no se ve afectada por las cargas. Solo funciona con un objeto raíz: en un objeto secundario, Unity registra una advertencia y no conserva nada. Los objetos secundarios del objeto conservado lo acompañan, pero no los objetos a los que solo apunta: después de la carga, un campo que apuntaba a un objeto de la escena anterior contiene un objeto destruido, que es igual a null.

public class GameSession : MonoBehaviour
{
    public static GameSession Instance;
    public int coins;

    void Awake()
    {
        if (Instance != null)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }
}

Este GameSession vive en la escena Menu. Al ejecutar el juego, se pasa de Menu a Level1 y luego se vuelve a Menu, que vuelve a crear todos sus objetos, incluido un nuevo GameSession, mientras el que se conservó sigue ahí. Sin la comprobación en Awake habría dos, y el recién creado reemplazaría a Instance con 0 monedas. Con ella, el recién creado encuentra que Instance ya está asignado, se destruye y se detiene, y la sesión que pasó por los niveles permanece.

return es importante porque Destroy espera hasta el final del fotograma. Sin él, el resto de Awake seguiría ejecutándose para el recién creado: Instance = this; haría que todos los scripts apuntaran a un objeto a punto de ser destruido.

challenge icon

Desafío

Fácil

Un cronómetro de speedrun. El objeto RunClock de Level1 cuenta los segundos de toda la partida y registra un tiempo parcial cada vez que se completa un nivel. La meta dorada de Level1 carga Level2, cuya meta vuelve a cargar Level1, y cada meta llama primero a RunClock.Instance.Split(). Cada nivel tiene su propio HUD con un ClockText; en el Inspector se asigna al RunClock el de Level1. Las flechas mueven al Player. Cambia RunClock.cs para que:

  • el cronómetro siga funcionando al cargar cada escena, sin volver a empezar;
  • el tiempo se muestre siempre en el ClockText del nivel que está abierto, como Time: 12.3;
  • al volver a Level1, que tiene su propio RunClock, siga habiendo un solo cronómetro: el que ha estado funcionando, y que RunClock.Instance sea ese.

Pulsa Play, ve a Level2 y vuelve, y termina Level1 de nuevo; después, pulsa Check.

Pruébalo tú mismo

using UnityEngine;
using TMPro;

public class RunClock : MonoBehaviour
{
    public static RunClock Instance;
    public TMP_Text clockText;
    private float seconds;

    void Awake()
    {
        Instance = this;
    }

    void Update()
    {
        seconds += Time.deltaTime;
        clockText.text = "Time: " + seconds.ToString("0.0");
    }

    public void Split()
    {
        Debug.Log("Split: " + seconds.ToString("0.0"));
    }
}
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 Creación de juegos reales