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 60.

Cargar una escena destruye todos los objetos de la anterior, pero algunas cosas deben durar toda la partida, como las monedas que un jugador lleva de un nivel a otro. DontDestroyOnLoad(gameObject) saca un objeto de su escena y lo coloca en una escena propia, llamada DontDestroyOnLoad en la Jerarquía al pulsar «Jugar», que las cargas nunca afectan. Solo funciona con un objeto raíz: si se aplica a un objeto secundario, Unity registra una advertencia y no conserva nada. Los objetos secundarios del objeto conservado también se mantienen, 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 se compara como 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);
    }
}

Esta GameSession está en la escena Menu. Al pulsar «Jugar», se pasa de Menu a Level1 y después se vuelve a Menu, que vuelve a crear todos sus objetos, incluida una nueva GameSession, mientras la que se conservó sigue allí. Sin la comprobación en Awake habría dos, y la nueva reemplazaría Instance con 0 monedas. Con ella, la nueva encuentra que Instance ya está asignada, 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 la nueva: Instance = this; haría que todos los scripts apuntaran a un objeto a punto de ser destruido.

challenge icon

Desafío

Fácil

Mantén un único reloj de la partida durante la carga de todas las escenas.

  1. En Awake(), si Instance != null, llama a Destroy(gameObject); y a return;. De lo contrario, establece Instance y llama a DontDestroyOnLoad(gameObject);.
  2. La carga destruye el texto del nivel anterior, así que en Update(), antes de la línea del texto, cuando clockText == null, establece clockText = GameObject.Find("ClockText").GetComponent<TMP_Text>();.

Pulsa «Jugar», ve a Level2 y vuelve: un único reloj sigue contando. Después, pulsa «Comprobar».

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"));
    }
}

Todas las lecciones de Creación de juegos reales

Practica por tu cuenta: Playground de Unity