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.
Desafío
FácilUn 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
ClockTextdel nivel que está abierto, comoTime: 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.Instancesea 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"));
}
}
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
1Texto en pantalla
Canvas y textoMuestra la puntuaciónDa formato a los númerosUn temporizador de cuenta regresivaRepaso: velocímetro4Escenas y niveles
Cargar una escenaReiniciar el nivelSiguiente nivelConservar entre escenasRepaso: selección de nivel10Proyecto: plataformas 3D
El recorridoPlataformas móviles2Botones y pantallas
Botones y onClickLambdasConectar en el InspectorPaneles activados y desactivadosBarras de saludRepaso: tienda de mejoras5Guardar con PlayerPrefs
Guardar un númeroCargar con un valor predeterminadoPuntuación más altaGuardar ajustesRepaso: monedas en el banco3El gestor del juego
Un solo script ejecuta el juegoEl SingletonEstados del juegoActivar el estadoRepaso: gestor de rondas6Proyecto: corredor infinito
Tres carrilesObstáculos por delante9El nuevo sistema de entrada
Dos sistemas de entradaTeclado y ratónPulsado en este fotogramaAcciones de entradaRepaso: cambio de entrada